@stencil/core 5.0.0-beta.3 → 5.0.0-beta.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/app-data/index.d.ts +1 -1
  2. package/dist/{client-BRu0GtRn.mjs → client-BYvfR_Hx.mjs} +127 -68
  3. package/dist/compiler/browser.d.ts +114 -81
  4. package/dist/compiler/browser.js +733 -336
  5. package/dist/compiler/index.d.mts +110 -2
  6. package/dist/compiler/index.mjs +3 -3
  7. package/dist/compiler/utils/index.d.mts +1 -1
  8. package/dist/{compiler-BPgV6bA4.mjs → compiler-6RhuOkQ0.mjs} +4829 -2895
  9. package/dist/declarations/stencil-public-compiler.d.ts +152 -129
  10. package/dist/declarations/stencil-public-docs.d.ts +23 -0
  11. package/dist/declarations/stencil-public-runtime.d.ts +60 -58
  12. package/dist/{index-DmHmu3y0.d.mts → index-BGUOG9Wc.d.mts} +6 -2
  13. package/dist/{index-BXAcVN2j.d.ts → index-BHciXst1.d.ts} +57 -55
  14. package/dist/{index-BopBfjPu.d.mts → index-BogZpjP2.d.mts} +150 -127
  15. package/dist/index.d.mts +3 -0
  16. package/dist/index.mjs +1 -1
  17. package/dist/jsx-runtime.d.mts +6 -0
  18. package/dist/jsx-runtime.mjs +1 -1
  19. package/dist/{node-75gQKkFz.mjs → node-CvPPhnWO.mjs} +41 -47
  20. package/dist/runtime/client/lazy.js +252 -189
  21. package/dist/runtime/client/runtime.d.ts +71 -66
  22. package/dist/runtime/client/runtime.js +252 -189
  23. package/dist/runtime/index.d.ts +4 -5
  24. package/dist/runtime/index.js +250 -187
  25. package/dist/runtime/server/index.d.mts +11 -11
  26. package/dist/runtime/server/index.mjs +302 -228
  27. package/dist/runtime/server/runner.d.mts +4 -4
  28. package/dist/runtime/server/runner.mjs +82 -54
  29. package/dist/signals/index.d.ts +11 -2
  30. package/dist/signals/index.js +14 -35
  31. package/dist/sys/node/index.d.mts +1 -1
  32. package/dist/sys/node/index.mjs +1 -1
  33. package/dist/sys/node/worker.mjs +2 -2
  34. package/dist/testing/index.d.mts +136 -120
  35. package/dist/testing/index.mjs +259 -201
  36. package/package.json +8 -4
@@ -1182,7 +1182,6 @@ const BUILD = {
1182
1182
  asyncLoading: true,
1183
1183
  asyncQueue: false
1184
1184
  };
1185
- BUILD.isDev, BUILD.isTesting;
1186
1185
  BUILD.isTesting;
1187
1186
  /*!__STENCIL_STATIC_IMPORT_SWITCH__*/
1188
1187
  (typeof window !== "undefined" ? window : {}).HTMLElement;
@@ -1501,7 +1500,7 @@ const scopeSelector = (selector, scopeSelectorText, hostSelector, slotSelector)
1501
1500
  else return shallowPart.trim();
1502
1501
  }).join(", ");
1503
1502
  };
1504
- const isScopableAtRule = (selector) => selector.startsWith("@media") || selector.startsWith("@supports") || selector.startsWith("@page") || selector.startsWith("@document") || selector.startsWith("@layer");
1503
+ const isScopableAtRule = (selector) => selector.startsWith("@media") || selector.startsWith("@supports") || selector.startsWith("@page") || selector.startsWith("@document") || selector.startsWith("@layer") || selector.startsWith("@container");
1505
1504
  const scopeSelectors = (cssText, scopeSelectorText, hostSelector, slotSelector, commentOriginalSelector) => {
1506
1505
  return processRules(cssText, (rule) => {
1507
1506
  let selector = rule.selector;
@@ -1693,6 +1692,18 @@ const createJsVarName = (fileName) => {
1693
1692
  }
1694
1693
  return fileName;
1695
1694
  };
1695
+ /**
1696
+ * Create a function that lowercases the first string parameter before passing it to the provided function
1697
+ * @param fn the function to pass the lowercased path to
1698
+ * @returns the result of the provided function
1699
+ */
1700
+ const lowerPathParam = (fn) => (p) => fn(p.toLowerCase());
1701
+ /**
1702
+ * Determine if a stringified file path is a TypeScript declaration file based on the extension at the end of the path.
1703
+ * @param p the path to evaluate
1704
+ * @returns `true` if the path ends in `.d.ts` (case-sensitive), `false` otherwise.
1705
+ */
1706
+ const isDtsFile = lowerPathParam((p) => p.endsWith(".d.ts") || p.endsWith(".d.mts") || p.endsWith(".d.cts"));
1696
1707
  function getTextDocs(docs) {
1697
1708
  if (docs == null) return "";
1698
1709
  return [escapeWithPattern(docs.text.replace(LINE_BREAK_REGEX, " "), /\*\//, "*\\/", true), ...docs.tags.filter((tag) => tag.name !== "internal").map((tag) => {
@@ -1832,7 +1843,7 @@ const validateComponentTag = (tag) => {
1832
1843
  };
1833
1844
  //#endregion
1834
1845
  //#region src/version.ts
1835
- const version = "5.0.0-beta.3";
1846
+ const version = "5.0.0-beta.30";
1836
1847
  //#endregion
1837
1848
  //#region src/compiler/events.ts
1838
1849
  const buildEvents = () => {
@@ -1895,6 +1906,7 @@ const resolve = (id, _opts, cb) => {
1895
1906
  };
1896
1907
  //#endregion
1897
1908
  //#region src/compiler/sys/resolve/resolve-utils.ts
1909
+ const isLocalModule = (p) => p.startsWith(".") || p.startsWith("/");
1898
1910
  const isNodeModulePath = (p) => normalizePath(p).split("/").includes("node_modules");
1899
1911
  const getModuleId = (orgImport) => {
1900
1912
  if (orgImport.startsWith("~")) orgImport = orgImport.substring(1);
@@ -2345,15 +2357,6 @@ const createSystem = (c) => {
2345
2357
  }
2346
2358
  return results;
2347
2359
  };
2348
- /**
2349
- * `self` is the global namespace object used within a web worker.
2350
- * `window` is the browser's global namespace object (I reorganized this to check the reference on that second)
2351
- * `global` is Node's global namespace object. https://nodejs.org/api/globals.html#globals_global
2352
- *
2353
- * loading in this order should allow workers, which are most common, then browser,
2354
- * then Node to grab the reference to fetch correctly.
2355
- */
2356
- const fetch = typeof self !== "undefined" ? self?.fetch : typeof window !== "undefined" ? window?.fetch : typeof global !== "undefined" ? global?.fetch : void 0;
2357
2360
  const writeFile = async (p, data) => writeFileSync(p, data);
2358
2361
  const tmpDirSync = () => "/.tmp";
2359
2362
  const tick = Promise.resolve();
@@ -2364,6 +2367,7 @@ const createSystem = (c) => {
2364
2367
  if (typeof hashLength === "number") hashHex = hashHex.slice(0, hashLength);
2365
2368
  return hashHex;
2366
2369
  };
2370
+ const generateFileHash = async (filePath, hashLength) => generateContentHash(readFileSync(filePath), hashLength);
2367
2371
  const copy = async (copyTasks, srcDir) => {
2368
2372
  const results = {
2369
2373
  diagnostics: [],
@@ -2373,9 +2377,6 @@ const createSystem = (c) => {
2373
2377
  logger.info("todo, copy task", copyTasks.length, srcDir);
2374
2378
  return results;
2375
2379
  };
2376
- const getEnvironmentVar = (key) => {
2377
- return process$1?.env[key];
2378
- };
2379
2380
  const getLocalModulePath = (opts) => join$1(opts.rootDir, "node_modules", opts.moduleId, opts.path);
2380
2381
  const getRemoteModuleUrl = (opts) => {
2381
2382
  const npmBaseUrl = "https://cdn.jsdelivr.net/npm/";
@@ -2391,13 +2392,14 @@ const createSystem = (c) => {
2391
2392
  access,
2392
2393
  accessSync,
2393
2394
  addDestroy,
2395
+ checkVersion: async () => noop,
2394
2396
  copyFile,
2395
2397
  createDir,
2396
2398
  createDirSync,
2397
2399
  homeDir,
2398
2400
  isTTY,
2399
- getEnvironmentVar,
2400
2401
  destroy,
2402
+ dynamicImport: (p) => import(p),
2401
2403
  encodeToBase64,
2402
2404
  exit: async (exitCode) => logger.warn(`exit ${exitCode}`),
2403
2405
  getCurrentDirectory,
@@ -2408,6 +2410,7 @@ const createSystem = (c) => {
2408
2410
  isSymbolicLink,
2409
2411
  nextTick,
2410
2412
  normalizePath: normalize,
2413
+ onProcessInterrupt: noop,
2411
2414
  platformPath: path,
2412
2415
  readDir,
2413
2416
  readDirSync,
@@ -2417,7 +2420,6 @@ const createSystem = (c) => {
2417
2420
  realpathSync,
2418
2421
  removeDestroy,
2419
2422
  rename,
2420
- fetch,
2421
2423
  resolvePath,
2422
2424
  removeDir,
2423
2425
  removeDirSync,
@@ -2432,6 +2434,7 @@ const createSystem = (c) => {
2432
2434
  writeFile,
2433
2435
  writeFileSync,
2434
2436
  generateContentHash,
2437
+ generateFileHash,
2435
2438
  createWorkerController: null,
2436
2439
  details: {
2437
2440
  cpuModel: "",
@@ -2633,19 +2636,20 @@ const getTranspileCssConfig = (compileOpts, importData, results) => {
2633
2636
  minify: false,
2634
2637
  autoprefixer: false,
2635
2638
  module: compileOpts.module,
2636
- styleImportData: compileOpts.styleImportData
2639
+ styleImportData: compileOpts.styleImportData,
2640
+ docs: compileOpts.docs === true
2637
2641
  };
2638
2642
  };
2639
2643
  const getTranspileConfigOpt = (value, validValues, defaultValue) => {
2640
2644
  if (value === null || value === "null") return null;
2641
- value = isString$1(value) ? value.toLowerCase().trim() : null;
2645
+ value = isString$1(value) ? value.toLowerCase().trim() : void 0;
2642
2646
  if (validValues.has(value)) return value;
2643
2647
  return defaultValue;
2644
2648
  };
2645
2649
  const VALID_EXPORT = /* @__PURE__ */ new Set(["customelement", "module"]);
2646
- const VALID_METADATA = /* @__PURE__ */ new Set(["compilerstatic", null]);
2650
+ const VALID_METADATA = /* @__PURE__ */ new Set(["compilerstatic"]);
2647
2651
  const VALID_MODULE = /* @__PURE__ */ new Set(["cjs", "esm"]);
2648
- const VALID_PROXY = /* @__PURE__ */ new Set(["defineproperty", null]);
2652
+ const VALID_PROXY = /* @__PURE__ */ new Set(["defineproperty"]);
2649
2653
  const VALID_STYLE = /* @__PURE__ */ new Set(["static"]);
2650
2654
  const VALID_STYLE_IMPORT_DATA = /* @__PURE__ */ new Set(["queryparams"]);
2651
2655
  const VALID_TARGET = /* @__PURE__ */ new Set([
@@ -2825,7 +2829,7 @@ const validateReadmeOutputTarget = (config, outputTarget) => {
2825
2829
  if (!isAbsolute(outputTarget.dir)) outputTarget.dir = join$1(config.rootDir, outputTarget.dir);
2826
2830
  if (outputTarget.footer == null) outputTarget.footer = NOTE;
2827
2831
  outputTarget.strict = !!outputTarget.strict;
2828
- if (!isBoolean$1(outputTarget.skipInDev)) outputTarget.skipInDev = !config._docsFlag;
2832
+ if (!isBoolean$1(outputTarget.skipInDev)) outputTarget.skipInDev = true;
2829
2833
  return outputTarget;
2830
2834
  };
2831
2835
  const validateJsonDocsOutputTarget = (config, diagnostics, outputTarget) => {
@@ -2837,7 +2841,7 @@ const validateJsonDocsOutputTarget = (config, diagnostics, outputTarget) => {
2837
2841
  if (isString$1(outputTarget.typesFile) && !isAbsolute(outputTarget.typesFile)) outputTarget.typesFile = join$1(config.rootDir, outputTarget.typesFile);
2838
2842
  else if (outputTarget.typesFile !== null && outputTarget.file.endsWith(".json")) outputTarget.typesFile = outputTarget.file.replace(/\.json$/, ".d.ts");
2839
2843
  outputTarget.strict = !!outputTarget.strict;
2840
- if (!isBoolean$1(outputTarget.skipInDev)) outputTarget.skipInDev = !config._docsFlag;
2844
+ if (!isBoolean$1(outputTarget.skipInDev)) outputTarget.skipInDev = true;
2841
2845
  return outputTarget;
2842
2846
  };
2843
2847
  const validateCustomDocsOutputTarget = (config, diagnostics, outputTarget) => {
@@ -2846,7 +2850,7 @@ const validateCustomDocsOutputTarget = (config, diagnostics, outputTarget) => {
2846
2850
  err.messageText = `docs-custom outputTarget missing the "generator" function`;
2847
2851
  }
2848
2852
  outputTarget.strict = !!outputTarget.strict;
2849
- if (!isBoolean$1(outputTarget.skipInDev)) outputTarget.skipInDev = !config._docsFlag;
2853
+ if (!isBoolean$1(outputTarget.skipInDev)) outputTarget.skipInDev = true;
2850
2854
  return outputTarget;
2851
2855
  };
2852
2856
  const validateVScodeDocsOutputTarget = (config, diagnostics, outputTarget) => {
@@ -2854,21 +2858,22 @@ const validateVScodeDocsOutputTarget = (config, diagnostics, outputTarget) => {
2854
2858
  const err = buildError(diagnostics);
2855
2859
  err.messageText = `docs-vscode outputTarget missing the "file" path`;
2856
2860
  }
2857
- if (!isBoolean$1(outputTarget.skipInDev)) outputTarget.skipInDev = !config._docsFlag;
2861
+ if (!isBoolean$1(outputTarget.skipInDev)) outputTarget.skipInDev = true;
2858
2862
  return outputTarget;
2859
2863
  };
2860
2864
  const DEFAULT_AGENT_SKILL_DIR = "dist/skill";
2861
2865
  const validateAgentSkillOutputTarget = (config, outputTarget) => {
2862
2866
  outputTarget.dir = getAbsolutePath(config, outputTarget.dir || DEFAULT_AGENT_SKILL_DIR);
2863
2867
  outputTarget.name = toSkillName(outputTarget.name || config.fsNamespace);
2864
- if (!isBoolean$1(outputTarget.skipInDev)) outputTarget.skipInDev = !config._docsFlag;
2868
+ if (!isBoolean$1(outputTarget.skipInDev)) outputTarget.skipInDev = true;
2865
2869
  return outputTarget;
2866
2870
  };
2871
+ const DEFAULT_CUSTOM_ELEMENTS_MANIFEST_FILE = "dist/custom-elements.json";
2867
2872
  const validateCustomElementsManifestOutputTarget = (config, outputTarget) => {
2868
- if (!isString$1(outputTarget.file)) outputTarget.file = "custom-elements.json";
2873
+ if (!isString$1(outputTarget.file)) outputTarget.file = DEFAULT_CUSTOM_ELEMENTS_MANIFEST_FILE;
2869
2874
  if (!isAbsolute(outputTarget.file)) outputTarget.file = join$1(config.rootDir, outputTarget.file);
2870
2875
  outputTarget.strict = !!outputTarget.strict;
2871
- if (!isBoolean$1(outputTarget.skipInDev)) outputTarget.skipInDev = !config._docsFlag;
2876
+ if (!isBoolean$1(outputTarget.skipInDev)) outputTarget.skipInDev = true;
2872
2877
  return outputTarget;
2873
2878
  };
2874
2879
  //#endregion
@@ -3789,10 +3794,11 @@ const validateConfig = (userConfig = {}, bootstrapConfig) => {
3789
3794
  const devMode = isBoolean$1(config.devMode) ? config.devMode : false;
3790
3795
  config._isTesting = !!(process.env.VITEST || process.env.PLAYWRIGHT_TEST || process.env.TEST_WORKER_INDEX || process.env.TEST_PARALLEL_INDEX || false);
3791
3796
  const sys = config.sys ?? bootstrapConfig.sys ?? createNodeSys({ logger });
3797
+ const hasExplicitGlobalStyleWithInput = (config.outputTargets || []).some((o) => isOutputTargetGlobalStyle(o) && isString$1(o.input));
3792
3798
  if ((!isString$1(config.globalStyle) || !isString$1(config.globalScript)) && typeof sys.accessSync === "function") {
3793
3799
  const preRootDir = typeof config.rootDir !== "string" ? "/" : config.rootDir;
3794
3800
  const srcDir = typeof config.srcDir === "string" ? isAbsolute(config.srcDir) ? config.srcDir : join(preRootDir, config.srcDir) : join(preRootDir, "src");
3795
- if (!isString$1(config.globalStyle)) for (const ext of STYLE_EXT) {
3801
+ if (!isString$1(config.globalStyle) && !hasExplicitGlobalStyleWithInput) for (const ext of STYLE_EXT) {
3796
3802
  const candidate = join(srcDir, `global.${ext}`);
3797
3803
  if (sys.accessSync(candidate)) {
3798
3804
  config.globalStyle = candidate;
@@ -3812,7 +3818,8 @@ const validateConfig = (userConfig = {}, bootstrapConfig) => {
3812
3818
  ...config,
3813
3819
  devMode,
3814
3820
  compat: config.compat || {},
3815
- generateExportMaps: isBoolean$1(config.generateExportMaps) ? config.generateExportMaps : false,
3821
+ generateExportMaps: config.generateExportMaps === true,
3822
+ enableCssOnlyComponents: config.enableCssOnlyComponents ?? true,
3816
3823
  hydratedFlag: validateHydrated(config),
3817
3824
  logLevel,
3818
3825
  logger,
@@ -3870,29 +3877,159 @@ const validateConfig = (userConfig = {}, bootstrapConfig) => {
3870
3877
  };
3871
3878
  };
3872
3879
  //#endregion
3880
+ //#region src/compiler/docs/css-doc-comments.ts
3881
+ /**
3882
+ * A JSDoc-style comment is `/** ... *\/` or `/*! ... *\/` - postcss's `Comment.text` already
3883
+ * strips the `/*`/`*\/` delimiters, so this checks the leading `*` or `!` that remains.
3884
+ * @param commentText a postcss `Comment` node's `.text`
3885
+ * @returns `true` if the comment is JSDoc-style
3886
+ */
3887
+ const isJsDocComment = (commentText) => commentText.startsWith("*") || commentText.startsWith("!");
3888
+ /**
3889
+ * Strip the leading `*`/`!` marker and per-line `*` prefixes, returning trimmed lines.
3890
+ * @param commentText a postcss `Comment` node's `.text`
3891
+ * @returns the comment's lines, delimiters and leading `*`s stripped
3892
+ */
3893
+ const normalizeJsDocLines = (commentText) => {
3894
+ return commentText.replace(/^[*!]/, "").split(/\r?\n/).map((line) => line.trim().replace(/^\*/, "").trim()).filter((line, i, arr) => !(line === "" && (i === 0 || i === arr.length - 1)));
3895
+ };
3896
+ /**
3897
+ * @param commentText a postcss `Comment` node's `.text`
3898
+ * @returns the comment's lines joined into a single trimmed line of text
3899
+ */
3900
+ const normalizeJsDocText = (commentText) => normalizeJsDocLines(commentText).filter(Boolean).join(" ").trim();
3901
+ /**
3902
+ * @param value a CSS descriptor value, possibly quoted (e.g. a `syntax` descriptor's `"<length>"`)
3903
+ * @returns the value with any surrounding quotes removed
3904
+ */
3905
+ const stripQuotes = (value) => value.replace(/^['"]|['"]$/g, "");
3906
+ /**
3907
+ * Extract the `syntax`/`initial-value` descriptors from a native `@property` at-rule's body.
3908
+ * @param node a postcss `AtRule` node whose `name` is `property`
3909
+ * @returns the extracted descriptors, if present
3910
+ */
3911
+ const parsePropertyAtRuleDescriptors = (node) => {
3912
+ let syntax;
3913
+ let initialValue;
3914
+ node.each((child) => {
3915
+ if (child.type !== "decl") return;
3916
+ if (child.prop === "syntax") syntax = stripQuotes(child.value);
3917
+ else if (child.prop === "initial-value") initialValue = child.value;
3918
+ });
3919
+ return {
3920
+ syntax,
3921
+ initialValue
3922
+ };
3923
+ };
3924
+ /** `--name: docs`, `--name - docs` (as `@attr`/`@slot` use) or `--name docs`. */
3925
+ const CUSTOM_PROPERTY_TAG_RE = /^(--[\w-]+)\s*(?::|-(?=\s))?(.*)$/;
3926
+ /**
3927
+ * @param text the text after a `@prop`/`@cssprop` tag
3928
+ * @returns the custom property name and description, or `undefined` if `text` doesn't start
3929
+ * with a custom property name
3930
+ */
3931
+ const parseCustomPropertyTag = (text) => {
3932
+ const match = text.trim().match(CUSTOM_PROPERTY_TAG_RE);
3933
+ return match ? {
3934
+ name: match[1],
3935
+ docs: match[2].trim()
3936
+ } : void 0;
3937
+ };
3938
+ //#endregion
3873
3939
  //#region src/compiler/docs/style-docs.ts
3874
3940
  /**
3875
3941
  * Parse CSS docstrings that Stencil supports, as documented here:
3876
3942
  * https://stenciljs.com/docs/docs-json#css-variables
3877
3943
  *
3878
- * Docstrings found in the supplied style text will be added to the
3879
- * `styleDocs` param
3944
+ * Docstrings found in the supplied style text will be added to the `styleDocs` param, via three
3945
+ * mechanisms, in order of precedence (an earlier mechanism always wins over a later one for the
3946
+ * same custom property name):
3947
+ * 1. An explicit `@prop`/`@cssprop`/`@cssproperty` annotation in a block comment, anywhere in the file.
3948
+ * 2. A doc-commented `--foo: value;` declaration inside the component's "root" rule - `:host`
3949
+ * for `shadow`/`scoped` encapsulation, or the component's own tag selector for `none`.
3950
+ * 3. A native `@property --foo { ... }` at-rule, with the `syntax`/`initial-value` descriptors
3951
+ * surfaced as `syntax`/`default`. Not scoped - `@property` is a global registration. For a
3952
+ * property already documented by 1 or 2, it still supplies `syntax`/`default`.
3880
3953
  *
3881
3954
  * @param styleDocs the array to hold formatted CSS docstrings
3882
3955
  * @param styleText the CSS text we're working with
3883
3956
  * @param mode a mode associated with the parsed style, if applicable (e.g. this is not applicable for global styles)
3957
+ * @param tag the component's tag name, used to scope auto-detection for `none` encapsulation
3958
+ * @param encapsulation the component's encapsulation, used to pick the "root" scope for auto-detection
3884
3959
  */
3885
- function parseStyleDocs(styleDocs, styleText, mode) {
3960
+ function parseStyleDocs(styleDocs, styleText, mode, tag, encapsulation) {
3886
3961
  if (typeof styleText !== "string") return;
3887
- let match = styleText.match(CSS_DOC_START);
3962
+ let remainingText = styleText;
3963
+ let match = remainingText.match(CSS_DOC_START);
3888
3964
  while (match !== null) {
3889
- styleText = styleText.substring(match.index + match[0].length);
3890
- const endIndex = styleText.indexOf(CSS_DOC_END);
3965
+ remainingText = remainingText.substring(match.index + match[0].length);
3966
+ const endIndex = remainingText.indexOf(CSS_DOC_END);
3891
3967
  if (endIndex === -1) break;
3892
- parseCssComment(styleDocs, styleText.substring(0, endIndex), mode);
3893
- styleText = styleText.substring(endIndex + CSS_DOC_END.length);
3894
- match = styleText.match(CSS_DOC_START);
3968
+ parseCssComment(styleDocs, remainingText.substring(0, endIndex), mode);
3969
+ remainingText = remainingText.substring(endIndex + CSS_DOC_END.length);
3970
+ match = remainingText.match(CSS_DOC_START);
3895
3971
  }
3972
+ if (styleText.includes("--")) parseScopedAndNativeStyleDocs(styleDocs, styleText, mode, tag, encapsulation);
3973
+ }
3974
+ /**
3975
+ * Auto-detect doc-commented custom-property declarations within the component's "root" rule,
3976
+ * and native `@property` at-rule registrations, merging them into `styleDocs`. Mirrors the
3977
+ * equivalent detection for CSS-only components in `css-components/parse-css-component.ts`.
3978
+ *
3979
+ * @param styleDocs the array to hold formatted CSS docstrings - also consulted so an explicit
3980
+ * `@prop`/`@cssprop` annotation always wins over an auto-detected entry for the same name
3981
+ * @param styleText the CSS text we're working with
3982
+ * @param mode a mode associated with the parsed style, if applicable
3983
+ * @param tag the component's tag name
3984
+ * @param encapsulation the component's encapsulation
3985
+ */
3986
+ function parseScopedAndNativeStyleDocs(styleDocs, styleText, mode, tag, encapsulation) {
3987
+ let root;
3988
+ try {
3989
+ root = postcss().process(styleText, { from: void 0 }).root;
3990
+ } catch {
3991
+ return;
3992
+ }
3993
+ const hasName = (name) => styleDocs.some((styleDoc) => styleDoc.name === name);
3994
+ const rootSelector = encapsulation === "shadow" || encapsulation === "scoped" ? ":host" : tag;
3995
+ if (rootSelector) root.walkRules((rule) => {
3996
+ if (!rule.selectors.some((selector) => selector.trim() === rootSelector)) return;
3997
+ const children = rule.nodes;
3998
+ for (let i = 0; i < children.length; i++) {
3999
+ const child = children[i];
4000
+ if (child.type !== "decl" || !child.prop.startsWith("--") || hasName(child.prop)) continue;
4001
+ const prev = children[i - 1];
4002
+ if (!prev || prev.type !== "comment" || !isJsDocComment(prev.text)) continue;
4003
+ styleDocs.push({
4004
+ name: child.prop,
4005
+ docs: normalizeJsDocText(prev.text),
4006
+ annotation: "prop",
4007
+ mode
4008
+ });
4009
+ }
4010
+ });
4011
+ root.walkAtRules("property", (node) => {
4012
+ const propName = node.params.trim();
4013
+ if (!propName.startsWith("--")) return;
4014
+ const { syntax, initialValue } = parsePropertyAtRuleDescriptors(node);
4015
+ const prev = node.prev();
4016
+ const docs = prev && prev.type === "comment" && isJsDocComment(prev.text) ? normalizeJsDocText(prev.text) : "";
4017
+ const existing = styleDocs.find((styleDoc) => styleDoc.name === propName);
4018
+ if (existing) {
4019
+ existing.docs ||= docs;
4020
+ if (syntax) existing.syntax ??= syntax;
4021
+ if (initialValue) existing.default ??= initialValue;
4022
+ return;
4023
+ }
4024
+ styleDocs.push({
4025
+ name: propName,
4026
+ docs,
4027
+ annotation: "prop",
4028
+ mode,
4029
+ ...syntax && { syntax },
4030
+ ...initialValue && { default: initialValue }
4031
+ });
4032
+ });
3896
4033
  }
3897
4034
  /**
3898
4035
  * Parse a CSS comment string and insert it into the provided array of
@@ -3909,13 +4046,11 @@ function parseCssComment(styleDocs, comment, mode) {
3909
4046
  return line;
3910
4047
  }).join(" ").replace(/\t/g, " ").trim();
3911
4048
  while (comment.includes(" ")) comment = comment.replace(" ", " ");
3912
- comment.split(CSS_PROP_ANNOTATION).forEach((d) => {
3913
- const cssDocument = d.trim();
3914
- if (!cssDocument.startsWith(`--`)) return;
3915
- const splt = cssDocument.split(`:`);
4049
+ comment.split(CSS_PROP_ANNOTATION_RE).forEach((d) => {
4050
+ const prop = parseCustomPropertyTag(d);
4051
+ if (!prop) return;
3916
4052
  const styleDoc = {
3917
- name: splt[0].trim(),
3918
- docs: (splt.shift() && splt.join(`:`)).trim(),
4053
+ ...prop,
3919
4054
  annotation: "prop",
3920
4055
  mode
3921
4056
  };
@@ -3932,9 +4067,11 @@ const CSS_DOC_START = /\/\*(\*|!)/;
3932
4067
  */
3933
4068
  const CSS_DOC_END = "*/";
3934
4069
  /**
3935
- * The `@prop` annotation we support within CSS docstrings
4070
+ * The `@prop` annotation we support within CSS docstrings. `@cssprop`/`@cssproperty` are also
4071
+ * recognized as synonyms (the more common names in other web-component-analyzer/docgen
4072
+ * ecosystems).
3936
4073
  */
3937
- const CSS_PROP_ANNOTATION = "@prop";
4074
+ const CSS_PROP_ANNOTATION_RE = /@(?:cssproperty|cssprop|prop)\b/;
3938
4075
  //#endregion
3939
4076
  //#region src/compiler/sys/browser-stubs/browserslist.ts
3940
4077
  const browserslist = (_query) => [];
@@ -4046,6 +4183,39 @@ const DEFAULT_BROWSER_TARGETS = [
4046
4183
  //#endregion
4047
4184
  //#region src/compiler/style/css-parser/parse-css.ts
4048
4185
  /**
4186
+ * Splits a selector list on top-level commas in a single pass: a comma only
4187
+ * splits when it's outside a quoted string and at paren depth 0, so commas in
4188
+ * `:is(:a,:has(:b))` or `[title="a,b"]` aren't treated as separators.
4189
+ * Backslash escapes (inside or outside a string) are skipped so they can't shift state,
4190
+ * so e.g. `[title="a\,b"]` is treated as a single selector.
4191
+ * @param selectors The selector list to split
4192
+ * @returns An array of selectors, with whitespace trimmed from each selector
4193
+ */
4194
+ const splitSelectorList = (selectors) => {
4195
+ const parts = [];
4196
+ let depth = 0;
4197
+ let quote = null;
4198
+ let start = 0;
4199
+ for (let i = 0; i < selectors.length; i++) {
4200
+ const ch = selectors[i];
4201
+ if (quote) {
4202
+ if (ch === "\\") i++;
4203
+ else if (ch === quote) quote = null;
4204
+ continue;
4205
+ }
4206
+ if (ch === "\"" || ch === "'") quote = ch;
4207
+ else if (ch === "\\") i++;
4208
+ else if (ch === "(") depth++;
4209
+ else if (ch === ")") depth = Math.max(0, depth - 1);
4210
+ else if (ch === "," && depth === 0) {
4211
+ parts.push(selectors.slice(start, i));
4212
+ start = i + 1;
4213
+ }
4214
+ }
4215
+ parts.push(selectors.slice(start));
4216
+ return parts.map((s) => s.trim());
4217
+ };
4218
+ /**
4049
4219
  * Parses CSS string input into an AST representation.
4050
4220
  * Used for minification, finding & resolving URLs and during SSR / prerendering, removing unused selectors.
4051
4221
  *
@@ -4170,11 +4340,8 @@ const parseCss = (css, filePath) => {
4170
4340
  const selector = () => {
4171
4341
  const m = match(/^([^{]+)/);
4172
4342
  if (!m) return null;
4173
- return trim(m[0]).replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*\/+/g, "").replace(/"(?:\\"|[^"])*"|'(?:\\'|[^'])*'/g, function(str) {
4174
- return str.replace(/,/g, "‌");
4175
- }).split(/\s*(?![^(]*\)),\s*/).map(function(s) {
4176
- return s.replace(/\u200C/g, ",");
4177
- });
4343
+ const cleaned = trim(m[0]).replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*\/+/g, "");
4344
+ return splitSelectorList(cleaned);
4178
4345
  };
4179
4346
  const declaration = () => {
4180
4347
  const pos = position();
@@ -4772,12 +4939,10 @@ const optimizeCss = async (inputOpts) => {
4772
4939
  const CREATE_EVENT = "__stencil_createEvent";
4773
4940
  const DEFINE_CUSTOM_ELEMENT = "__stencil_defineCustomElement";
4774
4941
  const GET_ELEMENT = "__stencil_getElement";
4775
- const HOST = "__stencil_Host";
4776
4942
  const HTML_ELEMENT = "HTMLElement";
4777
4943
  const PROXY_CUSTOM_ELEMENT = "__stencil_proxyCustomElement";
4778
4944
  const REGISTER_INSTANCE = "__stencil_registerInstance";
4779
4945
  const REGISTER_HOST = "__stencil_registerHost";
4780
- const H = "__stencil_h";
4781
4946
  const TRANSFORM_TAG = "__stencil_transformTag";
4782
4947
  const GET_REGISTRY = "__stencil_getRegistry";
4783
4948
  const INJECT_SIDE_EFFECT_STYLE = "__stencil_injectSideEffectStyle";
@@ -4785,9 +4950,7 @@ const RUNTIME_APIS = {
4785
4950
  createEvent: `createEvent as ${CREATE_EVENT}`,
4786
4951
  defineCustomElement: `defineCustomElement as ${DEFINE_CUSTOM_ELEMENT}`,
4787
4952
  getElement: `getElement as ${GET_ELEMENT}`,
4788
- h: `h as ${H}`,
4789
4953
  legacyH: `h`,
4790
- Host: `Host as ${HOST}`,
4791
4954
  HTMLElement: HTML_ELEMENT,
4792
4955
  proxyCustomElement: `proxyCustomElement as ${PROXY_CUSTOM_ELEMENT}`,
4793
4956
  registerHost: `registerHost as ${REGISTER_HOST}`,
@@ -9186,9 +9349,9 @@ const serializeSymbol = (checker, symbol) => {
9186
9349
  };
9187
9350
  };
9188
9351
  /**
9189
- * Maps a TypeScript 4.3+ JSDocTagInfo to a flattened Stencil CompilerJsDocTagInfo.
9352
+ * Maps a TypeScript 4.3+ JSDocTagInfo to a flattened Stencil JsonDocsTag.
9190
9353
  * @param tags A readonly array of JSDocTagInfo objects.
9191
- * @returns An array of CompilerJsDocTagInfo objects.
9354
+ * @returns An array of JsonDocsTag objects.
9192
9355
  */
9193
9356
  const mapJSDocTagInfo = (tags) => {
9194
9357
  return tags.map((tag) => ({
@@ -9599,7 +9762,7 @@ const transformCssToEsmModule = (input) => {
9599
9762
  defaultVarName: createCssVarName(input.file, input.mode),
9600
9763
  styleDocs: []
9601
9764
  };
9602
- if (input.docs) parseStyleDocs(results.styleDocs, input.input, input.mode);
9765
+ if (input.docs) parseStyleDocs(results.styleDocs, input.input, input.mode, input.tag, input.encapsulation);
9603
9766
  try {
9604
9767
  const varNames = /* @__PURE__ */ new Set([results.defaultVarName]);
9605
9768
  if (isString$1(input.tag) && input.encapsulation === "scoped") {
@@ -9696,7 +9859,7 @@ const getCssToEsmImports = (varNames, cssText, filePath, modeName) => {
9696
9859
  isNodeModule: false
9697
9860
  };
9698
9861
  if (!isLocalCssImport(cssImportData.srcImportText)) continue;
9699
- else if (cssImportData.url === "stencil-globals" || cssImportData.url === "stencil-hydrate") continue;
9862
+ else if (cssImportData.url === "stencil-component-globals" || cssImportData.url === "stencil-hydrate" || cssImportData.url === "stencil-css-components") continue;
9700
9863
  else if (isCssNodeModule(cssImportData.url)) {
9701
9864
  cssImportData.filePath = cssImportData.url.substring(1);
9702
9865
  cssImportData.isNodeModule = true;
@@ -9911,6 +10074,7 @@ var BuildContext = class {
9911
10074
  completedTasks = [];
9912
10075
  compilerCtx;
9913
10076
  components = [];
10077
+ cssOnlyComponents = [];
9914
10078
  componentGraph = /* @__PURE__ */ new Map();
9915
10079
  config;
9916
10080
  data = {};
@@ -9952,6 +10116,7 @@ var BuildContext = class {
9952
10116
  styleBuildCount = 0;
9953
10117
  stylesPromise = null;
9954
10118
  stylesUpdated = [];
10119
+ globalStylesUpdated = [];
9955
10120
  timeSpan = null;
9956
10121
  timestamp;
9957
10122
  transpileBuildCount = 0;
@@ -10132,12 +10297,18 @@ var CompilerContext = class {
10132
10297
  */
10133
10298
  prevStylesMap = /* @__PURE__ */ new Map();
10134
10299
  globalStyleCache = /* @__PURE__ */ new Map();
10300
+ cssOnlyComponentsCache = /* @__PURE__ */ new Map();
10301
+ stencilCss;
10302
+ globalStyleVirtualImports = /* @__PURE__ */ new Map();
10135
10303
  styleModeNames = /* @__PURE__ */ new Set();
10136
10304
  worker = null;
10137
10305
  reset() {
10138
10306
  this.cache.clear();
10139
10307
  this.cssModuleImports.clear();
10140
10308
  this.globalStyleCache.clear();
10309
+ this.cssOnlyComponentsCache.clear();
10310
+ this.stencilCss = void 0;
10311
+ this.globalStyleVirtualImports.clear();
10141
10312
  this.collections.length = 0;
10142
10313
  this.compilerOptions = null;
10143
10314
  this.hasSuccessfulBuild = false;
@@ -10228,6 +10399,7 @@ const resetModuleLegacy = (moduleFile) => {
10228
10399
  moduleFile.externalImports.length = 0;
10229
10400
  moduleFile.isCollectionDependency = false;
10230
10401
  moduleFile.localImports.length = 0;
10402
+ moduleFile.functionalComponentDeps.length = 0;
10231
10403
  moduleFile.originalCollectionComponentPath = null;
10232
10404
  moduleFile.originalImports.length = 0;
10233
10405
  moduleFile.hasVdomXlink = false;
@@ -10742,31 +10914,6 @@ const createIdentifierFromStyleIdentifier = (styleIdentifier, externalStyleIds)
10742
10914
  return ts$1.factory.createBinaryExpression(createIdentifierFromStyleIdentifier(styleIdentifier, [id]), ts$1.SyntaxKind.PlusToken, createIdentifierFromStyleIdentifier(styleIdentifier, externalStyleIds.slice(1)));
10743
10915
  };
10744
10916
  //#endregion
10745
- //#region src/compiler/transformers/host-data-transform.ts
10746
- const transformHostData = (classElements, moduleFile) => {
10747
- if (classElements.some((e) => ts$1.isMethodDeclaration(e) && e.name.escapedText === "hostData")) {
10748
- const renderIndex = classElements.findIndex((e) => ts$1.isMethodDeclaration(e) && e.name.escapedText === "render");
10749
- if (renderIndex >= 0) {
10750
- const renderMethod = classElements[renderIndex];
10751
- classElements[renderIndex] = ts$1.factory.updateMethodDeclaration(renderMethod, retrieveModifierLike(renderMethod), renderMethod.asteriskToken, ts$1.factory.createIdentifier(INTERNAL_RENDER), renderMethod.questionToken, renderMethod.typeParameters, renderMethod.parameters, renderMethod.type, renderMethod.body);
10752
- }
10753
- classElements.push(syntheticRender(moduleFile, renderIndex >= 0));
10754
- }
10755
- };
10756
- const syntheticRender = (moduleFile, hasRender) => {
10757
- addCoreRuntimeApi(moduleFile, RUNTIME_APIS.Host);
10758
- addCoreRuntimeApi(moduleFile, RUNTIME_APIS.h);
10759
- const hArguments = [ts$1.factory.createIdentifier(HOST), ts$1.factory.createCallExpression(ts$1.factory.createPropertyAccessExpression(ts$1.factory.createThis(), "hostData"), void 0, void 0)];
10760
- if (hasRender) hArguments.push(ts$1.factory.createCallExpression(ts$1.factory.createPropertyAccessExpression(ts$1.factory.createThis(), INTERNAL_RENDER), void 0, void 0));
10761
- /**
10762
- * render() {
10763
- * return h(arguments);
10764
- * }
10765
- */
10766
- return ts$1.factory.createMethodDeclaration(void 0, void 0, "render", void 0, void 0, [], void 0, ts$1.factory.createBlock([ts$1.factory.createReturnStatement(ts$1.factory.createCallExpression(ts$1.factory.createIdentifier(H), void 0, hArguments))]));
10767
- };
10768
- const INTERNAL_RENDER = "__stencil_render";
10769
- //#endregion
10770
10917
  //#region src/compiler/transformers/reactive-handler-meta-transform.ts
10771
10918
  /**
10772
10919
  * Add a getter to a class for a static representation of the watchers
@@ -10848,7 +10995,6 @@ const updateLazyComponentMembers = (transformOpts, styleStatements, classNode, m
10848
10995
  addReactivePropHandlers(classMembers, cmp, "watchers");
10849
10996
  addReactivePropHandlers(classMembers, cmp, "serializers");
10850
10997
  addReactivePropHandlers(classMembers, cmp, "deserializers");
10851
- transformHostData(classMembers, moduleFile);
10852
10998
  if (transformOpts.style === "static") addStaticStylePropertyToClass(styleStatements, cmp, buildCtx);
10853
10999
  return classMembers;
10854
11000
  };
@@ -11296,7 +11442,6 @@ const updateNativeHostComponentMembers = (transformOpts, classNode, moduleFile,
11296
11442
  addReactivePropHandlers(classMembers, cmp, "deserializers");
11297
11443
  if (cmp.isPlain) addNativeComponentMeta(classMembers, cmp);
11298
11444
  if (transformOpts.style === "static") addNativeStaticStyle(classMembers, cmp, buildCtx);
11299
- transformHostData(classMembers, moduleFile);
11300
11445
  return classMembers;
11301
11446
  };
11302
11447
  //#endregion
@@ -11499,110 +11644,6 @@ const isDecoratorNamed = (propName) => {
11499
11644
  };
11500
11645
  };
11501
11646
  //#endregion
11502
- //#region src/compiler/transformers/decorators-to-static/attach-internals.ts
11503
- /**
11504
- * Convert the attach internals decorator to static, saving the name of the
11505
- * decorated property so an `ElementInternals` object can be bound to it later
11506
- * on.
11507
- *
11508
- * The `@AttachInternals` decorator is used to indicate a field on a class
11509
- * where the return value of the `HTMLElement.attachInternals` method should be
11510
- * bound. This then allows component authors to use that interface to make their
11511
- * Stencil components rich participants in whatever `HTMLFormElement` instances
11512
- * they find themselves inside of in the future.
11513
- *
11514
- * The decorator also accepts an optional `states` option to define initial
11515
- * custom states that will be set on the `ElementInternals.states` CustomStateSet.
11516
- * Each state property can have a JSDoc comment that will be extracted for documentation.
11517
- *
11518
- * **Note**: this function will mutate the `newMembers` parameter in order to
11519
- * add new members to the class.
11520
- *
11521
- * @param diagnostics for reporting errors and warnings
11522
- * @param decoratedMembers the decorated members found on the class
11523
- * @param newMembers an out param for new class members
11524
- * @param typeChecker a TypeScript typechecker, needed for resolving the prop
11525
- * declaration name
11526
- * @param decoratorName the name of the decorator to look for
11527
- */
11528
- const attachInternalsDecoratorsToStatic = (diagnostics, decoratedMembers, newMembers, typeChecker, decoratorName) => {
11529
- const attachInternalsMembers = decoratedMembers.filter(ts$1.isPropertyDeclaration).filter((prop) => {
11530
- return !!retrieveTsDecorators(prop)?.find(isDecoratorNamed(decoratorName));
11531
- });
11532
- if (attachInternalsMembers.length === 0) return;
11533
- if (attachInternalsMembers.length > 1) {
11534
- const error = buildError(diagnostics);
11535
- error.messageText = `Stencil does not support adding more than one AttachInternals() decorator to a component`;
11536
- return;
11537
- }
11538
- const [decoratedProp] = attachInternalsMembers;
11539
- const { staticName: name } = tsPropDeclName(decoratedProp, typeChecker);
11540
- const decorator = retrieveTsDecorators(decoratedProp)?.find(isDecoratorNamed(decoratorName));
11541
- const customStates = parseCustomStatesFromDecorator(decorator, typeChecker);
11542
- const formAssociated = parseFormAssociatedFromDecorator(decorator);
11543
- newMembers.push(createStaticGetter("attachInternalsMemberName", convertValueToLiteral(name)));
11544
- if (customStates.length > 0) newMembers.push(createStaticGetter("attachInternalsCustomStates", convertValueToLiteral(customStates)));
11545
- if (formAssociated) newMembers.push(createStaticGetter("formAssociated", convertValueToLiteral(true)));
11546
- };
11547
- /**
11548
- * Parse the formAssociated option from the decorator.
11549
- * Returns true (form-associated) unless explicitly set to false.
11550
- *
11551
- * @param decorator the decorator node to parse
11552
- * @returns whether the component should be form-associated
11553
- */
11554
- function parseFormAssociatedFromDecorator(decorator) {
11555
- if (!decorator || !ts$1.isCallExpression(decorator.expression)) return true;
11556
- const [firstArg] = decorator.expression.arguments;
11557
- if (!firstArg || !ts$1.isObjectLiteralExpression(firstArg)) return true;
11558
- const formAssociatedProp = firstArg.properties.find((prop) => ts$1.isPropertyAssignment(prop) && ts$1.isIdentifier(prop.name) && prop.name.text === "formAssociated");
11559
- if (!formAssociatedProp) return true;
11560
- if (formAssociatedProp.initializer.kind === ts$1.SyntaxKind.FalseKeyword) return false;
11561
- return true;
11562
- }
11563
- /**
11564
- * Parse custom states from the decorator AST, including JSDoc comments.
11565
- *
11566
- * Supports JSDoc comments on state properties:
11567
- * ```ts
11568
- * @AttachInternals({
11569
- * states: {
11570
- * hovered: false,
11571
- * /&#42;&#42; Whether is currently active &#42;/
11572
- * active: true
11573
- * }
11574
- * })
11575
- * ```
11576
- *
11577
- * @param decorator the decorator node to parse
11578
- * @param typeChecker a TypeScript typechecker for resolving symbols
11579
- * @returns array of custom state metadata with docs
11580
- */
11581
- function parseCustomStatesFromDecorator(decorator, typeChecker) {
11582
- if (!decorator || !ts$1.isCallExpression(decorator.expression)) return [];
11583
- const [firstArg] = decorator.expression.arguments;
11584
- if (!firstArg || !ts$1.isObjectLiteralExpression(firstArg)) return [];
11585
- const statesProp = firstArg.properties.find((prop) => ts$1.isPropertyAssignment(prop) && ts$1.isIdentifier(prop.name) && prop.name.text === "states");
11586
- if (!statesProp || !ts$1.isObjectLiteralExpression(statesProp.initializer)) return [];
11587
- const customStates = [];
11588
- for (const prop of statesProp.initializer.properties) {
11589
- if (!ts$1.isPropertyAssignment(prop)) continue;
11590
- const stateName = ts$1.isIdentifier(prop.name) ? prop.name.text : ts$1.isStringLiteral(prop.name) ? prop.name.text : null;
11591
- if (!stateName) continue;
11592
- let initialValue = false;
11593
- if (prop.initializer.kind === ts$1.SyntaxKind.TrueKeyword) initialValue = true;
11594
- else if (prop.initializer.kind === ts$1.SyntaxKind.FalseKeyword) initialValue = false;
11595
- const symbol = typeChecker.getSymbolAtLocation(prop.name);
11596
- const docs = symbol ? ts$1.displayPartsToString(symbol.getDocumentationComment(typeChecker)) : "";
11597
- customStates.push({
11598
- name: stateName,
11599
- initialValue,
11600
- docs
11601
- });
11602
- }
11603
- return customStates;
11604
- }
11605
- //#endregion
11606
11647
  //#region src/compiler/transformers/decorators-to-static/style-to-static.ts
11607
11648
  const styleToStatic = (newMembers, componentOptions) => {
11608
11649
  const defaultModeStyles = [];
@@ -11667,6 +11708,12 @@ const normalizeStyleUrl = (style) => {
11667
11708
  //#region src/compiler/transformers/decorators-to-static/component-decorator.ts
11668
11709
  let hasShownDeprecatedApiError = false;
11669
11710
  /**
11711
+ * Reset the deprecated API error flag. Call this at the start of each build.
11712
+ */
11713
+ const resetDeprecatedApiWarning = () => {
11714
+ hasShownDeprecatedApiError = false;
11715
+ };
11716
+ /**
11670
11717
  * Perform code generation to create new class members for a Stencil component
11671
11718
  * which will drive the runtime functionality specified by various options
11672
11719
  * passed to the `@Component` decorator.
@@ -11867,6 +11914,110 @@ const findTagNode = (propName, node) => {
11867
11914
  return out;
11868
11915
  };
11869
11916
  //#endregion
11917
+ //#region src/compiler/transformers/decorators-to-static/attach-internals.ts
11918
+ /**
11919
+ * Convert the attach internals decorator to static, saving the name of the
11920
+ * decorated property so an `ElementInternals` object can be bound to it later
11921
+ * on.
11922
+ *
11923
+ * The `@AttachInternals` decorator is used to indicate a field on a class
11924
+ * where the return value of the `HTMLElement.attachInternals` method should be
11925
+ * bound. This then allows component authors to use that interface to make their
11926
+ * Stencil components rich participants in whatever `HTMLFormElement` instances
11927
+ * they find themselves inside of in the future.
11928
+ *
11929
+ * The decorator also accepts an optional `states` option to define initial
11930
+ * custom states that will be set on the `ElementInternals.states` CustomStateSet.
11931
+ * Each state property can have a JSDoc comment that will be extracted for documentation.
11932
+ *
11933
+ * **Note**: this function will mutate the `newMembers` parameter in order to
11934
+ * add new members to the class.
11935
+ *
11936
+ * @param diagnostics for reporting errors and warnings
11937
+ * @param decoratedMembers the decorated members found on the class
11938
+ * @param newMembers an out param for new class members
11939
+ * @param typeChecker a TypeScript typechecker, needed for resolving the prop
11940
+ * declaration name
11941
+ * @param decoratorName the name of the decorator to look for
11942
+ */
11943
+ const attachInternalsDecoratorsToStatic = (diagnostics, decoratedMembers, newMembers, typeChecker, decoratorName) => {
11944
+ const attachInternalsMembers = decoratedMembers.filter(ts$1.isPropertyDeclaration).filter((prop) => {
11945
+ return !!retrieveTsDecorators(prop)?.find(isDecoratorNamed(decoratorName));
11946
+ });
11947
+ if (attachInternalsMembers.length === 0) return;
11948
+ if (attachInternalsMembers.length > 1) {
11949
+ const error = buildError(diagnostics);
11950
+ error.messageText = `Stencil does not support adding more than one AttachInternals() decorator to a component`;
11951
+ return;
11952
+ }
11953
+ const [decoratedProp] = attachInternalsMembers;
11954
+ const { staticName: name } = tsPropDeclName(decoratedProp, typeChecker);
11955
+ const decorator = retrieveTsDecorators(decoratedProp)?.find(isDecoratorNamed(decoratorName));
11956
+ const customStates = parseCustomStatesFromDecorator(decorator, typeChecker);
11957
+ const formAssociated = parseFormAssociatedFromDecorator(decorator);
11958
+ newMembers.push(createStaticGetter("attachInternalsMemberName", convertValueToLiteral(name)));
11959
+ if (customStates.length > 0) newMembers.push(createStaticGetter("attachInternalsCustomStates", convertValueToLiteral(customStates)));
11960
+ if (formAssociated) newMembers.push(createStaticGetter("formAssociated", convertValueToLiteral(true)));
11961
+ };
11962
+ /**
11963
+ * Parse the formAssociated option from the decorator.
11964
+ * Returns true (form-associated) unless explicitly set to false.
11965
+ *
11966
+ * @param decorator the decorator node to parse
11967
+ * @returns whether the component should be form-associated
11968
+ */
11969
+ function parseFormAssociatedFromDecorator(decorator) {
11970
+ if (!decorator || !ts$1.isCallExpression(decorator.expression)) return true;
11971
+ const [firstArg] = decorator.expression.arguments;
11972
+ if (!firstArg || !ts$1.isObjectLiteralExpression(firstArg)) return true;
11973
+ const formAssociatedProp = firstArg.properties.find((prop) => ts$1.isPropertyAssignment(prop) && ts$1.isIdentifier(prop.name) && prop.name.text === "formAssociated");
11974
+ if (!formAssociatedProp) return true;
11975
+ if (formAssociatedProp.initializer.kind === ts$1.SyntaxKind.FalseKeyword) return false;
11976
+ return true;
11977
+ }
11978
+ /**
11979
+ * Parse custom states from the decorator AST, including JSDoc comments.
11980
+ *
11981
+ * Supports JSDoc comments on state properties:
11982
+ * ```ts
11983
+ * @AttachInternals({
11984
+ * states: {
11985
+ * hovered: false,
11986
+ * /&#42;&#42; Whether is currently active &#42;/
11987
+ * active: true
11988
+ * }
11989
+ * })
11990
+ * ```
11991
+ *
11992
+ * @param decorator the decorator node to parse
11993
+ * @param typeChecker a TypeScript typechecker for resolving symbols
11994
+ * @returns array of custom state metadata with docs
11995
+ */
11996
+ function parseCustomStatesFromDecorator(decorator, typeChecker) {
11997
+ if (!decorator || !ts$1.isCallExpression(decorator.expression)) return [];
11998
+ const [firstArg] = decorator.expression.arguments;
11999
+ if (!firstArg || !ts$1.isObjectLiteralExpression(firstArg)) return [];
12000
+ const statesProp = firstArg.properties.find((prop) => ts$1.isPropertyAssignment(prop) && ts$1.isIdentifier(prop.name) && prop.name.text === "states");
12001
+ if (!statesProp || !ts$1.isObjectLiteralExpression(statesProp.initializer)) return [];
12002
+ const customStates = [];
12003
+ for (const prop of statesProp.initializer.properties) {
12004
+ if (!ts$1.isPropertyAssignment(prop)) continue;
12005
+ const stateName = ts$1.isIdentifier(prop.name) ? prop.name.text : ts$1.isStringLiteral(prop.name) ? prop.name.text : null;
12006
+ if (!stateName) continue;
12007
+ let initialValue = false;
12008
+ if (prop.initializer.kind === ts$1.SyntaxKind.TrueKeyword) initialValue = true;
12009
+ else if (prop.initializer.kind === ts$1.SyntaxKind.FalseKeyword) initialValue = false;
12010
+ const symbol = typeChecker.getSymbolAtLocation(prop.name);
12011
+ const docs = symbol ? ts$1.displayPartsToString(symbol.getDocumentationComment(typeChecker)) : "";
12012
+ customStates.push({
12013
+ name: stateName,
12014
+ initialValue,
12015
+ docs
12016
+ });
12017
+ }
12018
+ return customStates;
12019
+ }
12020
+ //#endregion
11870
12021
  //#region src/compiler/transformers/decorators-to-static/decorators-constants.ts
11871
12022
  /**
11872
12023
  * All the decorators supported by Stencil
@@ -13194,14 +13345,16 @@ const parseWatchDecorator = (typeChecker, method, decoratorName) => {
13194
13345
  * @param diagnostics for surfacing errors and warnings
13195
13346
  * @param typeChecker a TypeScript typechecker instance
13196
13347
  * @param program a {@link ts.Program} object
13348
+ * @param includeClassExpressions also convert `ts.ClassExpression` nodes (e.g. a mixin factory's
13349
+ * `(Base) => class extends Base {}`), not just named `ts.ClassDeclaration`s
13197
13350
  * @returns a TypeScript transformer factory which can be passed to
13198
13351
  * TypeScript to transform source code during the compilation process
13199
13352
  */
13200
- const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) => {
13353
+ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program, includeClassExpressions = false) => {
13201
13354
  return (transformCtx) => {
13202
13355
  let sourceFile;
13203
13356
  const visit = (node) => {
13204
- if (ts$1.isClassDeclaration(node)) return visitClassDeclaration(config, diagnostics, typeChecker, program, node, sourceFile);
13357
+ if (ts$1.isClassDeclaration(node) || includeClassExpressions && ts$1.isClassExpression(node)) return visitClassDeclaration(config, diagnostics, typeChecker, program, node, sourceFile);
13205
13358
  return ts$1.visitEachChild(node, visit, transformCtx);
13206
13359
  };
13207
13360
  return (tsSourceFile) => {
@@ -13211,10 +13364,10 @@ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) =>
13211
13364
  };
13212
13365
  };
13213
13366
  /**
13214
- * Visit {@link ts.ClassDeclaration} nodes as part of the tree-traversal
13367
+ * Visit {@link ts.ClassDeclaration}/{@link ts.ClassExpression} nodes as part of the tree-traversal
13215
13368
  * required for {@link convertDecoratorsToStatic} to work.
13216
13369
  *
13217
- * If a given class declaration node is not decorated with `@Component` this
13370
+ * If a given class node is not decorated with `@Component` this
13218
13371
  * function will simply return it as-is. If it _is_ decorated, then it will
13219
13372
  *
13220
13373
  * 1. Convert the arguments to the `@Component` decorator to static values.
@@ -13223,7 +13376,7 @@ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) =>
13223
13376
  * to static values.
13224
13377
  * 3. Validate that the various options selected by the component author are
13225
13378
  * valid, both individually and in combination.
13226
- * 4. Return an updated class declaration node which is ready to be used in
13379
+ * 4. Return an updated class node which is ready to be used in
13227
13380
  * the rest of the Stencil compilation pipeline (e.g. in output target
13228
13381
  * generation).
13229
13382
  *
@@ -13242,7 +13395,7 @@ const visitClassDeclaration = (config, diagnostics, typeChecker, program, classN
13242
13395
  const decoratedMembers = classMembers.filter((member) => (retrieveTsDecorators(member)?.length ?? 0) > 0);
13243
13396
  if (!decoratedMembers.length && !componentDecorator) return classNode;
13244
13397
  const filteredMethodsAndFields = removeStencilMethodDecorators(Array.from(classMembers), diagnostics, importAliasMap);
13245
- if (componentDecorator) componentDecoratorToStatic(config, typeChecker, diagnostics, classNode, filteredMethodsAndFields, componentDecorator);
13398
+ if (componentDecorator && ts$1.isClassDeclaration(classNode)) componentDecoratorToStatic(config, typeChecker, diagnostics, classNode, filteredMethodsAndFields, componentDecorator);
13246
13399
  if (decoratedMembers.length > 0) {
13247
13400
  const serializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("PropSerialize"), "PropSerialize", importAliasMap.get("Prop"));
13248
13401
  const deserializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("AttrDeserialize"), "AttrDeserialize", importAliasMap.get("Prop"));
@@ -13258,7 +13411,8 @@ const visitClassDeclaration = (config, diagnostics, typeChecker, program, classN
13258
13411
  validateMethods(diagnostics, classMembers);
13259
13412
  const currentDecorators = retrieveTsDecorators(classNode);
13260
13413
  const updatedClassFields = updateConstructor(classNode, filteredMethodsAndFields, []);
13261
- return ts$1.factory.updateClassDeclaration(classNode, [...filterDecorators(currentDecorators, CLASS_DECORATORS_TO_REMOVE.map((decorator) => importAliasMap.get(decorator))) ?? [], ...retrieveTsModifiers(classNode) ?? []], classNode.name, classNode.typeParameters, classNode.heritageClauses, updatedClassFields);
13414
+ const updatedModifiers = [...filterDecorators(currentDecorators, CLASS_DECORATORS_TO_REMOVE.map((decorator) => importAliasMap.get(decorator))) ?? [], ...retrieveTsModifiers(classNode) ?? []];
13415
+ return ts$1.isClassDeclaration(classNode) ? ts$1.factory.updateClassDeclaration(classNode, updatedModifiers, classNode.name, classNode.typeParameters, classNode.heritageClauses, updatedClassFields) : ts$1.factory.updateClassExpression(classNode, updatedModifiers, classNode.name, classNode.typeParameters, classNode.heritageClauses, updatedClassFields);
13262
13416
  };
13263
13417
  /**
13264
13418
  * Take a list of `ClassElement` AST nodes and remove any decorators from
@@ -13524,12 +13678,18 @@ const gatherVdomMeta = (m, args, typeChecker) => {
13524
13678
  };
13525
13679
  //#endregion
13526
13680
  //#region src/compiler/transformers/static-to-meta/call-expression.ts
13527
- const parseCallExpression = (m, node, typeChecker) => {
13681
+ /**
13682
+ * @param m the module or component to record vdom metadata on
13683
+ * @param node the call expression to parse
13684
+ * @param typeChecker used to resolve functional components / JSX-returning calls to their source
13685
+ * @param moduleFile the module to record those dependencies on; defaults to `m` when it's a module
13686
+ */
13687
+ const parseCallExpression = (m, node, typeChecker, moduleFile = "functionalComponentDeps" in m ? m : void 0) => {
13528
13688
  if (node.arguments != null && node.arguments.length > 0) {
13529
- if (ts$1.isIdentifier(node.expression)) visitCallExpressionArgs(m, node.expression, node.arguments, typeChecker);
13689
+ if (ts$1.isIdentifier(node.expression)) visitCallExpressionArgs(m, node.expression, node.arguments, typeChecker, moduleFile);
13530
13690
  else if (ts$1.isPropertyAccessExpression(node.expression)) {
13531
13691
  const n = node.expression.name;
13532
- if (ts$1.isIdentifier(n) && n) visitCallExpressionArgs(m, n, node.arguments, typeChecker);
13692
+ if (ts$1.isIdentifier(n) && n) visitCallExpressionArgs(m, n, node.arguments, typeChecker, moduleFile);
13533
13693
  }
13534
13694
  } else if (ts$1.isPropertyAccessExpression(node.expression)) {
13535
13695
  if (ts$1.isIdentifier(node.expression.name)) {
@@ -13539,24 +13699,20 @@ const parseCallExpression = (m, node, typeChecker) => {
13539
13699
  if (!declarations || declarations.length === 0) return;
13540
13700
  const sourceFile = declarations[0].getSourceFile();
13541
13701
  if (!sourceFile) return;
13542
- const sourceFilePath = normalizePath(sourceFile.fileName);
13543
- const moduleFile = m;
13544
- if (moduleFile.functionalComponentDeps) {
13545
- if (!moduleFile.functionalComponentDeps.includes(sourceFilePath)) moduleFile.functionalComponentDeps.push(sourceFilePath);
13546
- }
13702
+ addFunctionalComponentDep(moduleFile, sourceFile);
13547
13703
  }
13548
13704
  }
13549
13705
  };
13550
- const visitCallExpressionArgs = (m, callExpressionName, args, typeChecker) => {
13706
+ const visitCallExpressionArgs = (m, callExpressionName, args, typeChecker, moduleFile) => {
13551
13707
  const fnName = callExpressionName.escapedText;
13552
13708
  if (fnName === "h" || fnName === "__stencil_h" || fnName === "createElement") {
13553
- visitCallExpressionArg(m, args[0], typeChecker);
13709
+ visitCallExpressionArg(m, args[0], typeChecker, moduleFile);
13554
13710
  if (fnName === "h" || fnName === "__stencil_h") gatherVdomMeta(m, args, typeChecker);
13555
13711
  } else if (fnName === "jsx" || fnName === "jsxs" || fnName === "_jsx" || fnName === "_jsxs") {
13556
- visitCallExpressionArg(m, args[0], typeChecker);
13712
+ visitCallExpressionArg(m, args[0], typeChecker, moduleFile);
13557
13713
  gatherVdomMeta(m, args, typeChecker);
13558
13714
  if (args.length > 2 && args[2]) m.hasVdomKey = true;
13559
- } else if (args.length > 1 && fnName === "createElementNS") visitCallExpressionArg(m, args[1], typeChecker);
13715
+ } else if (args.length > 1 && fnName === "createElementNS") visitCallExpressionArg(m, args[1], typeChecker, moduleFile);
13560
13716
  else if (fnName === "require" && args.length > 0 && m.originalImports) {
13561
13717
  const arg = args[0];
13562
13718
  if (ts$1.isStringLiteral(arg)) {
@@ -13564,7 +13720,7 @@ const visitCallExpressionArgs = (m, callExpressionName, args, typeChecker) => {
13564
13720
  }
13565
13721
  }
13566
13722
  };
13567
- const visitCallExpressionArg = (m, arg, typeChecker) => {
13723
+ const visitCallExpressionArg = (m, arg, typeChecker, moduleFile) => {
13568
13724
  if (ts$1.isStringLiteral(arg)) {
13569
13725
  let tag = arg.text;
13570
13726
  if (typeof tag === "string") {
@@ -13572,31 +13728,31 @@ const visitCallExpressionArg = (m, arg, typeChecker) => {
13572
13728
  m.htmlTagNames.push(tag);
13573
13729
  if (tag.includes("-")) m.potentialCmpRefs.push(tag);
13574
13730
  }
13575
- } else if (typeChecker && ts$1.isIdentifier(arg)) resolveFunctionalComponentDep(m, arg, typeChecker);
13731
+ } else if (typeChecker && ts$1.isIdentifier(arg)) resolveFunctionalComponentDep(moduleFile, arg, typeChecker);
13576
13732
  };
13577
13733
  /**
13578
13734
  * Resolves a functional component identifier to its source file and tracks it
13579
13735
  * as a dependency so that build-conditionals can be properly propagated.
13736
+ * Follows import / re-export aliases through to the declaring file.
13580
13737
  *
13581
- * @param m the module or component metadata to track the dependency on
13738
+ * @param moduleFile the module to track the dependency on
13582
13739
  * @param identifier the identifier node representing the functional component
13583
13740
  * @param typeChecker the TypeScript type checker for symbol resolution
13584
13741
  */
13585
- const resolveFunctionalComponentDep = (m, identifier, typeChecker) => {
13742
+ const resolveFunctionalComponentDep = (moduleFile, identifier, typeChecker) => {
13743
+ if (!moduleFile) return;
13586
13744
  try {
13587
13745
  const symbol = typeChecker.getSymbolAtLocation(identifier);
13588
13746
  if (!symbol) return;
13589
- const declarations = (typeChecker.getAliasedSymbol(symbol) || symbol).declarations;
13590
- if (!declarations || declarations.length === 0) return;
13591
- const sourceFile = declarations[0].getSourceFile();
13592
- if (!sourceFile) return;
13593
- const sourceFilePath = normalizePath(sourceFile.fileName);
13594
- const moduleFile = m;
13595
- if (moduleFile.functionalComponentDeps) {
13596
- if (!moduleFile.functionalComponentDeps.includes(sourceFilePath)) moduleFile.functionalComponentDeps.push(sourceFilePath);
13597
- }
13747
+ const sourceFile = (symbol.flags & ts$1.SymbolFlags.Alias ? typeChecker.getAliasedSymbol(symbol) : symbol).declarations?.[0]?.getSourceFile();
13748
+ if (sourceFile) addFunctionalComponentDep(moduleFile, sourceFile);
13598
13749
  } catch {}
13599
13750
  };
13751
+ const addFunctionalComponentDep = (moduleFile, sourceFile) => {
13752
+ const deps = moduleFile?.functionalComponentDeps;
13753
+ const sourceFilePath = normalizePath(sourceFile.fileName);
13754
+ if (deps && !deps.includes(sourceFilePath)) deps.push(sourceFilePath);
13755
+ };
13600
13756
  //#endregion
13601
13757
  //#region src/compiler/transformers/component-build-conditionals.ts
13602
13758
  const setComponentBuildConditionals = (cmpMeta) => {
@@ -13869,11 +14025,11 @@ const parseStaticWatchers = (staticMembers) => {
13869
14025
  //#endregion
13870
14026
  //#region src/compiler/transformers/static-to-meta/class-extension/shared.ts
13871
14027
  /**
13872
- * Warns when an `extends`/`Mixin(...)` target resolved to *something* but no class declaration
13873
- * could be found inside it - e.g. a mixin factory whose class isn't a named declaration
13874
- * (`(Base) => class extends Base {}` rather than `(Base) => { class Foo extends Base {} return
13875
- * Foo; }`). Without this, the target is silently dropped: any `@Prop`/`@State` etc. it declares
13876
- * just never appears on the extending component, with no diagnostic explaining why.
14028
+ * Warns when an `extends`/`Mixin(...)` target resolved to *something* but no class literal
14029
+ * could be found inside it - e.g. a mixin factory that returns an existing class by reference
14030
+ * (`(Base) => SomeExistingClass`) rather than a class literal. Without this, the target is
14031
+ * silently dropped: any `@Prop`/`@State` etc. it declares just never appears on the extending
14032
+ * component, with no diagnostic explaining why.
13877
14033
  * @param buildCtx used to surface the warning - omit to warn silently (e.g. from tests)
13878
14034
  * @param targetName the identifier the target was reached through
13879
14035
  * @param anchor the node to attach the warning to
@@ -13881,27 +14037,32 @@ const parseStaticWatchers = (staticMembers) => {
13881
14037
  function warnMixinFactoryClassNotFound(buildCtx, targetName, anchor) {
13882
14038
  if (!buildCtx) return;
13883
14039
  const err = buildWarn(buildCtx.diagnostics);
13884
- err.messageText = `Found "${targetName}", but couldn't find a class declaration inside it. If it's meant to be a mixin factory, make sure it declares and returns a named class, e.g. \`(Base) => { class ${targetName}Class extends Base {} return ${targetName}Class; }\` - a factory that returns a class expression directly (\`(Base) => class extends Base {}\`) isn't recognized, and any \`@Prop\`/\`@State\`/etc. it declares won't be applied.`;
14040
+ err.messageText = `Found "${targetName}", but couldn't find a class inside it. If it's meant to be a mixin factory, make sure it returns a class literal directly, e.g. \`(Base) => class extends Base {}\` or \`(Base) => { class ${targetName}Class extends Base {} return ${targetName}Class; }\` - returning an existing class by reference (\`(Base) => SomeExistingClass\`) isn't recognized, and any \`@Prop\`/\`@State\`/etc. it declares won't be applied.`;
13885
14041
  if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, anchor);
13886
14042
  }
13887
14043
  /**
13888
- * Walks the AST looking for a class declaration, optionally by name - descends
13889
- * into a mixin factory's wrapping function (arrow function or `function`
13890
- * declaration) body too, since a mixin factory's class is always nested one
13891
- * level inside it (e.g. `const Foo = (Base) => class extends Base {}`).
14044
+ * Walks the AST looking for a class declaration or class expression, optionally by name -
14045
+ * descends into a mixin factory's wrapping function (arrow function or `function` declaration)
14046
+ * body too, since a mixin factory's class is always nested one level inside it. Recognizes all of:
14047
+ * `const Foo = (Base) => class extends Base {}` (concise arrow body), `const Foo = (Base) => {
14048
+ * return class extends Base {}; }` (block body, `return` of a class expression), and `const Foo =
14049
+ * (Base) => { class FooClass extends Base {} return FooClass; }` (block body, named declaration).
13892
14050
  * @param node the node to search from
13893
- * @param name if given, only matches a class declaration with this name
13894
- * @returns the found class declaration, or `undefined`
14051
+ * @param name if given, only matches a class with this name
14052
+ * @returns the found class, or `undefined`
13895
14053
  */
13896
14054
  function findClassWalk(node, name) {
13897
14055
  if (!node) return void 0;
13898
- if (ts$1.isClassDeclaration(node)) {
14056
+ if (ts$1.isClassDeclaration(node) || ts$1.isClassExpression(node)) {
13899
14057
  if (!name || node.name?.text === name) return node;
13900
14058
  } else if (ts$1.isVariableDeclaration(node) && (!name || name === node.name?.text) && node.initializer && ts$1.isArrowFunction(node.initializer)) {
14059
+ const body = node.initializer.body;
14060
+ if (ts$1.isClassExpression(body)) return body;
13901
14061
  let found;
13902
- ts$1.forEachChild(node.initializer.body, (child) => {
14062
+ ts$1.forEachChild(body, (child) => {
13903
14063
  if (found) return;
13904
14064
  if (ts$1.isClassDeclaration(child)) found = child;
14065
+ else if (ts$1.isReturnStatement(child) && child.expression && ts$1.isClassExpression(child.expression)) found = child.expression;
13905
14066
  });
13906
14067
  return found;
13907
14068
  }
@@ -13914,6 +14075,22 @@ function findClassWalk(node, name) {
13914
14075
  return found;
13915
14076
  }
13916
14077
  /**
14078
+ * The declared name of a mixin-factory statement (`function Foo() {}`, or `const Foo = ...`) -
14079
+ * survives the decorator-to-static-getter transform even when the factory's inner class doesn't
14080
+ * have a name of its own, so it can anchor a post-transform re-lookup via `findClassWalk`.
14081
+ * @param node the factory statement (or its variable declaration) to read a name from
14082
+ * @returns the declared name, or `undefined` if it can't be determined
14083
+ */
14084
+ function factoryDeclaredName(node) {
14085
+ if (!node) return void 0;
14086
+ if (ts$1.isFunctionDeclaration(node)) return node.name?.text;
14087
+ if (ts$1.isVariableDeclaration(node)) return ts$1.isIdentifier(node.name) ? node.name.text : void 0;
14088
+ if (ts$1.isVariableStatement(node)) {
14089
+ const decl = node.declarationList.declarations[0];
14090
+ return decl && ts$1.isIdentifier(decl.name) ? decl.name.text : void 0;
14091
+ }
14092
+ }
14093
+ /**
13917
14094
  * Matches a top-level class/function/variable declaration by name - the three
13918
14095
  * shapes a mixin or base-class export can take (a plain class, a mixin
13919
14096
  * factory function declaration, or a mixin factory assigned to a `const`).
@@ -13931,22 +14108,173 @@ function matchesNamedDeclaration(name) {
13931
14108
  };
13932
14109
  }
13933
14110
  /**
13934
- * Finds a re-export of `className` in `sourceFile` - `export { X } from './y'` or
13935
- * `export { X as Y } from './y'` - as used by barrel entry points (e.g. `@stencil/core`'s own
13936
- * public `index.d.mts`, which re-exports its runtime API from `./declarations/stencil-public-runtime`
13937
- * rather than declaring it directly).
14111
+ * Finds a re-export of `className` in `sourceFile`: `export { X } from './y'`, or the
14112
+ * bundler-split shape `import { X as name } from './y'; export { name };` (no `from` clause).
13938
14113
  * @param sourceFile the (barrel) source file to scan
13939
14114
  * @param className the exported name to look for
13940
- * @returns the module specifier and the name to look for in that module (the local name, before
13941
- * any `as` aliasing), or `undefined` if no matching re-export is found
14115
+ * @returns the module specifier and name to look for there (before any `as` aliasing), or
14116
+ * `undefined` if not found
13942
14117
  */
13943
14118
  function findReExport(sourceFile, className) {
13944
14119
  for (const stmt of sourceFile.statements) {
13945
- if (!ts$1.isExportDeclaration(stmt) || !stmt.moduleSpecifier || !ts$1.isStringLiteral(stmt.moduleSpecifier) || !stmt.exportClause || !ts$1.isNamedExports(stmt.exportClause)) continue;
13946
- for (const element of stmt.exportClause.elements) if (element.name.text === className) return {
14120
+ if (!ts$1.isExportDeclaration(stmt) || !stmt.exportClause || !ts$1.isNamedExports(stmt.exportClause)) continue;
14121
+ const element = stmt.exportClause.elements.find((el) => el.name.text === className);
14122
+ if (!element) continue;
14123
+ if (stmt.moduleSpecifier && ts$1.isStringLiteral(stmt.moduleSpecifier)) return {
13947
14124
  moduleSpecifier: stmt.moduleSpecifier.text,
13948
14125
  localName: element.propertyName?.text ?? element.name.text
13949
14126
  };
14127
+ const importOrigin = findImportOrigin(sourceFile, element.propertyName?.text ?? element.name.text);
14128
+ if (importOrigin) return importOrigin;
14129
+ }
14130
+ }
14131
+ /**
14132
+ * @param sourceFile the (barrel) source file to scan
14133
+ * @returns the module specifiers of its `export * from './x'` statements, in order
14134
+ */
14135
+ function findStarReExportSpecifiers(sourceFile) {
14136
+ return sourceFile.statements.flatMap((stmt) => ts$1.isExportDeclaration(stmt) && !stmt.exportClause && !stmt.isTypeOnly && stmt.moduleSpecifier && ts$1.isStringLiteral(stmt.moduleSpecifier) ? [stmt.moduleSpecifier.text] : []);
14137
+ }
14138
+ /**
14139
+ * Finds `name`'s import in `sourceFile` and returns its module and origin name (before any `as`
14140
+ * aliasing; `'default'` for a default import).
14141
+ * @param sourceFile the source file to scan for a matching import
14142
+ * @param name the local (post-aliasing) name an import bound
14143
+ * @returns the import's module specifier and origin name, or `undefined` if `name` isn't imported
14144
+ */
14145
+ function findImportOrigin(sourceFile, name) {
14146
+ for (const stmt of sourceFile.statements) {
14147
+ if (!ts$1.isImportDeclaration(stmt) || !stmt.importClause || !ts$1.isStringLiteral(stmt.moduleSpecifier)) continue;
14148
+ const moduleSpecifier = stmt.moduleSpecifier.text;
14149
+ if (stmt.importClause.name?.text === name) return {
14150
+ moduleSpecifier,
14151
+ localName: "default"
14152
+ };
14153
+ const bindings = stmt.importClause.namedBindings;
14154
+ if (!bindings || !ts$1.isNamedImports(bindings)) continue;
14155
+ const element = bindings.elements.find((el) => el.name.text === name);
14156
+ if (element) return {
14157
+ moduleSpecifier,
14158
+ localName: element.propertyName?.text ?? element.name.text
14159
+ };
14160
+ }
14161
+ }
14162
+ /**
14163
+ * Finds `name` as a top-level declaration in `sf` (see `matchesNamedDeclaration`), following a
14164
+ * same-file export alias if `name` is only ever the public side of a local rename
14165
+ * (`export { RealName as name }`, no `from` clause).
14166
+ * @param sf the source file to search
14167
+ * @param name the declaration name to look for, which may only exist as an export alias
14168
+ * @returns the matched statement, or `undefined`
14169
+ */
14170
+ function findStatementByName(sf, name) {
14171
+ const direct = sf.statements.find(matchesNamedDeclaration(name));
14172
+ if (direct) return direct;
14173
+ for (const stmt of sf.statements) {
14174
+ if (!ts$1.isExportDeclaration(stmt) || stmt.moduleSpecifier || !stmt.exportClause || !ts$1.isNamedExports(stmt.exportClause)) continue;
14175
+ const aliasedName = stmt.exportClause.elements.find((el) => el.name.text === name)?.propertyName?.text;
14176
+ if (aliasedName && aliasedName !== name) return sf.statements.find(matchesNamedDeclaration(aliasedName));
14177
+ }
14178
+ }
14179
+ /**
14180
+ * Picks the runtime target out of a `package.json` `exports` condition entry - prefers `import`
14181
+ * over `require`/`node`/`default`, recursing into nested condition objects.
14182
+ * @param entry an `exports` map value: a path string, or nested conditions
14183
+ * @returns the resolved relative path, or `undefined` if no usable condition was found
14184
+ */
14185
+ function pickJsCondition(entry) {
14186
+ if (typeof entry === "string") return entry;
14187
+ if (typeof entry !== "object" || entry === null) return;
14188
+ const conditions = entry;
14189
+ for (const key of [
14190
+ "import",
14191
+ "require",
14192
+ "node",
14193
+ "default"
14194
+ ]) if (key in conditions) {
14195
+ const picked = pickJsCondition(conditions[key]);
14196
+ if (picked) return picked;
14197
+ }
14198
+ }
14199
+ /**
14200
+ * Reads and parses `filePath` as JS, with parent nodes set - unlike `tsGetSourceFile`, which
14201
+ * never triggers binding, so `.parent` stays unset and `node.getSourceFile()` returns `undefined`.
14202
+ * @param config the current Stencil validated config
14203
+ * @param filePath the absolute path of the JS file to read and parse
14204
+ * @returns the parsed source file, or `undefined` if it couldn't be read
14205
+ */
14206
+ function readJsSourceFile(config, filePath) {
14207
+ try {
14208
+ const text = config.sys.readFileSync(filePath);
14209
+ if (typeof text !== "string") return;
14210
+ return ts$1.createSourceFile(filePath, text, ts$1.ScriptTarget.ESNext, true, ts$1.ScriptKind.JS);
14211
+ } catch {
14212
+ return;
14213
+ }
14214
+ }
14215
+ /**
14216
+ * Resolves the runtime JS entry for a bare (non-relative) module specifier by reading its
14217
+ * package's own `package.json` `exports` map, instead of `tsResolveModuleName` - which always
14218
+ * resolves to the package's `types` entry, an ambient signature with no body a mixin factory's
14219
+ * class can never be found inside.
14220
+ * @param config the current Stencil validated config
14221
+ * @param compilerCtx the current compiler context
14222
+ * @param moduleSpecifier the bare package specifier to resolve
14223
+ * @param containingFile the file the specifier was imported from
14224
+ * @returns the resolved JS source file, or `undefined` if it couldn't be resolved this way
14225
+ */
14226
+ function resolveModuleJsEntry(config, compilerCtx, moduleSpecifier, containingFile) {
14227
+ if (isLocalModule(moduleSpecifier)) return;
14228
+ const pkgJsonPath = tsResolveModuleNamePackageJsonPath(config, compilerCtx, moduleSpecifier, containingFile);
14229
+ if (!pkgJsonPath) return;
14230
+ let pkgJson;
14231
+ try {
14232
+ pkgJson = JSON.parse(config.sys.readFileSync(pkgJsonPath));
14233
+ } catch {
14234
+ return;
14235
+ }
14236
+ const pkgName = pkgJson.name;
14237
+ if (!pkgName || !moduleSpecifier.startsWith(pkgName) || !pkgJson.exports) return;
14238
+ const subpath = moduleSpecifier === pkgName ? "." : `.${moduleSpecifier.slice(pkgName.length)}`;
14239
+ const exportsMap = pkgJson.exports;
14240
+ const conditionEntry = typeof exportsMap === "string" ? subpath === "." ? exportsMap : void 0 : exportsMap[subpath] ?? (subpath === "." ? exportsMap : void 0);
14241
+ const target = conditionEntry && pickJsCondition(conditionEntry);
14242
+ if (!target) return;
14243
+ return readJsSourceFile(config, normalizePath(join$1(dirname(pkgJsonPath), target)));
14244
+ }
14245
+ /**
14246
+ * Finds `className`'s class inside a resolved JS entry (see `resolveModuleJsEntry`), following
14247
+ * re-export hops the same way `resolveAndProcessExtendedClass` walks a `.d.ts`/`.ts` source.
14248
+ * @param config the current Stencil validated config
14249
+ * @param compilerCtx the current compiler context
14250
+ * @param source the JS source file to search
14251
+ * @param className the class (or mixin factory) name to look for
14252
+ * @param hopsRemaining re-export hops still allowed before giving up
14253
+ * @returns the found class and the source file it's declared in, or `undefined`
14254
+ */
14255
+ function findClassInJsModule(config, compilerCtx, source, className, hopsRemaining = 3) {
14256
+ const matchedStatement = findStatementByName(source, className);
14257
+ if (matchedStatement) {
14258
+ const classNode = ts$1.isClassDeclaration(matchedStatement) ? matchedStatement : findClassWalk(matchedStatement);
14259
+ return classNode && {
14260
+ classNode,
14261
+ sourceFile: source
14262
+ };
14263
+ }
14264
+ if (hopsRemaining <= 0) return;
14265
+ const readReExported = (moduleSpecifier) => {
14266
+ const resolvedFileName = tsResolveModuleName(config, compilerCtx, moduleSpecifier, source.fileName)?.resolvedModule?.resolvedFileName;
14267
+ return resolvedFileName ? readJsSourceFile(config, resolvedFileName) : void 0;
14268
+ };
14269
+ const reExport = findReExport(source, className);
14270
+ if (reExport) {
14271
+ const nextSource = readReExported(reExport.moduleSpecifier);
14272
+ return nextSource && findClassInJsModule(config, compilerCtx, nextSource, reExport.localName, hopsRemaining - 1);
14273
+ }
14274
+ for (const moduleSpecifier of findStarReExportSpecifiers(source)) {
14275
+ const nextSource = readReExported(moduleSpecifier);
14276
+ const found = nextSource && findClassInJsModule(config, compilerCtx, nextSource, className, hopsRemaining - 1);
14277
+ if (found) return found;
13950
14278
  }
13951
14279
  }
13952
14280
  /**
@@ -14035,14 +14363,15 @@ function convertDiskSourceFileDecorators(sourceFile, config, target = ts$1.Scrip
14035
14363
  const program = ts$1.createProgram([sourceFile.fileName], compilerOptions, host);
14036
14364
  const typeChecker = program.getTypeChecker();
14037
14365
  const ownSourceFile = program.getSourceFile(sourceFile.fileName) ?? sourceFile;
14038
- const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program)]);
14366
+ const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program, true)]);
14039
14367
  const printed = ts$1.createPrinter({ removeComments: false }).printFile(result.transformed[0]);
14040
14368
  return ts$1.createSourceFile(sourceFile.fileName, printed, target, true);
14041
14369
  }
14042
14370
  /**
14043
14371
  * Resolves an `extends` target through a module specifier: resolves the
14044
14372
  * module, finds the named class/mixin-factory export, and adds it (and its
14045
- * own ancestors) to `dependentClasses`. Follows one level of re-export (barrel file) when the
14373
+ * own ancestors) to `dependentClasses`. Follows one level of re-export (barrel file, named or
14374
+ * `export *`) when the
14046
14375
  * declaration isn't found directly in the resolved module.
14047
14376
  * @param compilerCtx the current compiler context
14048
14377
  * @param buildCtx the current build context
@@ -14055,13 +14384,17 @@ function convertDiskSourceFileDecorators(sourceFile, config, target = ts$1.Scrip
14055
14384
  * @param ogModule the original module file of the class declaration
14056
14385
  * @param targetScriptTarget the script target to convert decorators with, if needed
14057
14386
  * @param barrelHopsRemaining re-export hops still allowed before giving up
14387
+ * @param originalModuleSpecifier the specifier this lookup started from, before any barrel hops
14388
+ * @param originalContainingFile the file `originalModuleSpecifier` was imported from
14058
14389
  * @returns the found class declaration, or `undefined`
14059
14390
  */
14060
- function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, currentSource, moduleSpecifier, className, dependentClasses, typeChecker, ogModule, targetScriptTarget = ts$1.ScriptTarget.ESNext, barrelHopsRemaining = 1) {
14391
+ function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, currentSource, moduleSpecifier, className, dependentClasses, typeChecker, ogModule, targetScriptTarget = ts$1.ScriptTarget.ESNext, barrelHopsRemaining = 1, originalModuleSpecifier = moduleSpecifier, originalContainingFile = currentSource.fileName) {
14061
14392
  let keepLooking = true;
14062
14393
  const foundFile = tsResolveModuleName(buildCtx.config, compilerCtx, moduleSpecifier, currentSource.fileName);
14063
14394
  if (!foundFile?.resolvedModule || !className) return;
14064
- let foundSource = compilerCtx.moduleMap.get(foundFile.resolvedModule.resolvedFileName)?.staticSourceFile;
14395
+ const resolvedFileName = foundFile.resolvedModule.resolvedFileName;
14396
+ let foundSource = compilerCtx.moduleMap.get(resolvedFileName)?.staticSourceFile;
14397
+ if (!foundSource && isJsFile(currentSource.fileName) && isJsFile(resolvedFileName)) foundSource = readJsSourceFile(buildCtx.config, resolvedFileName);
14065
14398
  if (!foundSource) {
14066
14399
  foundSource = tsGetSourceFile(buildCtx.config, foundFile);
14067
14400
  if (!foundSource) {
@@ -14073,10 +14406,10 @@ function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration,
14073
14406
  }
14074
14407
  foundSource = convertDiskSourceFileDecorators(foundSource, buildCtx.config, targetScriptTarget);
14075
14408
  }
14076
- const matchedStatement = foundSource.statements.find(matchesNamedDeclaration(className));
14409
+ const matchedStatement = findStatementByName(foundSource, className);
14077
14410
  if (!matchedStatement) {
14078
- const reExport = barrelHopsRemaining > 0 ? findReExport(foundSource, className) : void 0;
14079
- if (reExport) return resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, foundSource, reExport.moduleSpecifier, reExport.localName, dependentClasses, typeChecker, ogModule, targetScriptTarget, barrelHopsRemaining - 1);
14411
+ const reExport = barrelHopsRemaining > 0 ? findReExport(foundSource, className) ?? findStarReExportOf(buildCtx.config, compilerCtx, foundSource, className) : void 0;
14412
+ if (reExport) return resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, foundSource, reExport.moduleSpecifier, reExport.localName, dependentClasses, typeChecker, ogModule, targetScriptTarget, barrelHopsRemaining - 1, originalModuleSpecifier, originalContainingFile);
14080
14413
  const err = buildWarn(buildCtx.diagnostics);
14081
14414
  err.messageText = `Unable to find "${className}" in the imported module "${moduleSpecifier}".
14082
14415
  Please import class / mixin-factory declarations directly and not via barrel files.`;
@@ -14084,21 +14417,61 @@ function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration,
14084
14417
  return;
14085
14418
  }
14086
14419
  let foundClassDeclaration = matchedStatement ? ts$1.isClassDeclaration(matchedStatement) ? matchedStatement : void 0 : void 0;
14087
- if (!foundClassDeclaration && matchedStatement) {
14420
+ let foundClassSource = foundSource;
14421
+ const findInJsEntry = () => {
14422
+ if (!isDtsFile(foundSource.fileName) || isLocalModule(originalModuleSpecifier)) return;
14423
+ const jsSource = resolveModuleJsEntry(buildCtx.config, compilerCtx, originalModuleSpecifier, originalContainingFile);
14424
+ return jsSource && findClassInJsModule(buildCtx.config, compilerCtx, jsSource, className);
14425
+ };
14426
+ if (foundClassDeclaration) {
14427
+ const foundInJs = findInJsEntry();
14428
+ if (foundInJs) {
14429
+ foundClassDeclaration = foundInJs.classNode;
14430
+ foundClassSource = foundInJs.sourceFile;
14431
+ }
14432
+ } else if (matchedStatement) {
14088
14433
  foundClassDeclaration = findClassWalk(matchedStatement);
14089
14434
  keepLooking = false;
14435
+ if (!foundClassDeclaration) {
14436
+ const foundInJs = findInJsEntry();
14437
+ if (foundInJs) {
14438
+ foundClassDeclaration = foundInJs.classNode;
14439
+ foundClassSource = foundInJs.sourceFile;
14440
+ }
14441
+ }
14090
14442
  if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, className, classDeclaration);
14091
14443
  }
14092
14444
  if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {
14093
14445
  dependentClasses.push({
14094
14446
  classNode: foundClassDeclaration,
14095
- sourceFile: foundSource,
14096
- fileName: foundFile.resolvedModule.resolvedFileName
14447
+ sourceFile: foundClassSource,
14448
+ fileName: foundClassSource.fileName
14097
14449
  });
14098
14450
  if (keepLooking) buildExtendsTree(compilerCtx, foundClassDeclaration, dependentClasses, typeChecker, buildCtx, ogModule);
14099
14451
  }
14100
14452
  return foundClassDeclaration;
14101
14453
  }
14454
+ /**
14455
+ * Finds the first `export * from './x'` in `barrel` whose target declares `className` directly.
14456
+ * @param config the current Stencil validated config
14457
+ * @param compilerCtx the current compiler context
14458
+ * @param barrel the source file to scan
14459
+ * @param className the declaration name to look for
14460
+ * @returns the re-export to follow, in `findReExport`'s shape, or `undefined`
14461
+ */
14462
+ function findStarReExportOf(config, compilerCtx, barrel, className) {
14463
+ for (const moduleSpecifier of findStarReExportSpecifiers(barrel)) {
14464
+ const resolved = tsResolveModuleName(config, compilerCtx, moduleSpecifier, barrel.fileName);
14465
+ const fileName = resolved?.resolvedModule?.resolvedFileName;
14466
+ if (!fileName) continue;
14467
+ const target = compilerCtx.moduleMap.get(fileName)?.staticSourceFile ?? (isJsFile(fileName) ? readJsSourceFile(config, fileName) : tsGetSourceFile(config, resolved));
14468
+ if (target && findStatementByName(target, className)) return {
14469
+ moduleSpecifier,
14470
+ localName: className
14471
+ };
14472
+ }
14473
+ }
14474
+ const isJsFile = (fileName) => /\.[cm]?js$/.test(fileName);
14102
14475
  function convertDtsToJs(declarationSourceFile, compilerCtx) {
14103
14476
  const jsPath = normalizePath(declarationSourceFile.replace(/\.d\.ts$/, ".js").replace("/types/", "/collection/"));
14104
14477
  return compilerCtx.moduleMap.get(jsPath)?.staticSourceFile;
@@ -14122,6 +14495,7 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
14122
14495
  const targetScriptTarget = (ogModule?.staticSourceFile)?.languageVersion ?? ts$1.ScriptTarget.ESNext;
14123
14496
  let classIdentifiers = [];
14124
14497
  let foundClassDeclaration;
14498
+ let foundClassName;
14125
14499
  let keepLooking = true;
14126
14500
  extendsClause.types.forEach((type) => {
14127
14501
  if (ts$1.isExpressionWithTypeArguments(type) && ts$1.isCallExpression(type.expression) && type.expression.expression.getText() === "Mixin") classIdentifiers = type.expression.arguments.filter(ts$1.isIdentifier);
@@ -14138,9 +14512,11 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
14138
14512
  declarations = [...source.statements];
14139
14513
  }
14140
14514
  foundClassDeclaration = declarations?.find(ts$1.isClassDeclaration);
14515
+ foundClassName = foundClassDeclaration?.name?.getText();
14141
14516
  if (!foundClassDeclaration) {
14142
14517
  const node = declarations?.[0];
14143
14518
  foundClassDeclaration = findClassWalk(node);
14519
+ foundClassName = foundClassDeclaration?.name?.getText() ?? factoryDeclaredName(node);
14144
14520
  if (!node) throw "revert to sad path";
14145
14521
  keepLooking = false;
14146
14522
  if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, extendee.getText(), classDeclaration);
@@ -14149,7 +14525,7 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
14149
14525
  const foundModule = compilerCtx.moduleMap.get(foundClassDeclaration.getSourceFile().fileName);
14150
14526
  if (foundModule) {
14151
14527
  const moduleSourceFile = foundModule.staticSourceFile;
14152
- const sourceClass = findClassWalk(moduleSourceFile, foundClassDeclaration.name?.getText());
14528
+ const sourceClass = findClassWalk(moduleSourceFile, foundClassName);
14153
14529
  if (sourceClass) {
14154
14530
  dependentClasses.push({
14155
14531
  classNode: sourceClass,
@@ -14170,20 +14546,24 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
14170
14546
  if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, classDeclaration);
14171
14547
  return;
14172
14548
  }
14173
- if (matchedStatement && ts$1.isClassDeclaration(matchedStatement)) foundClassDeclaration = matchedStatement;
14174
- else if (matchedStatement) {
14549
+ if (matchedStatement && ts$1.isClassDeclaration(matchedStatement)) {
14550
+ foundClassDeclaration = matchedStatement;
14551
+ foundClassName = foundClassDeclaration.name?.getText();
14552
+ } else if (matchedStatement) {
14175
14553
  foundClassDeclaration = findClassWalk(matchedStatement);
14554
+ foundClassName = foundClassDeclaration?.name?.getText() ?? extendee.getText();
14176
14555
  keepLooking = false;
14177
14556
  if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, extendee.getText(), classDeclaration);
14178
14557
  } else {
14179
14558
  foundClassDeclaration = findClassWalk(currentSource, extendee.getText());
14559
+ foundClassName = foundClassDeclaration?.name?.getText() ?? extendee.getText();
14180
14560
  keepLooking = false;
14181
14561
  }
14182
14562
  if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {
14183
14563
  const foundModule = compilerCtx.moduleMap.get(currentSource.fileName);
14184
14564
  if (foundModule?.staticSourceFile) {
14185
14565
  const transformedSource = foundModule.staticSourceFile;
14186
- const transformedClass = findClassWalk(transformedSource, foundClassDeclaration.name?.getText());
14566
+ const transformedClass = findClassWalk(transformedSource, foundClassName);
14187
14567
  if (transformedClass) {
14188
14568
  dependentClasses.push({
14189
14569
  classNode: transformedClass,
@@ -14468,7 +14848,7 @@ function convertInMemorySourceDecorators(sourceFile, config) {
14468
14848
  const program = ts$1.createProgram([sourceFile.fileName], compilerOptions, compilerHost);
14469
14849
  const typeChecker = program.getTypeChecker();
14470
14850
  const ownSourceFile = program.getSourceFile(sourceFile.fileName) ?? sourceFile;
14471
- const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program)]);
14851
+ const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program, true)]);
14472
14852
  const printed = ts$1.createPrinter({ removeComments: false }).printFile(result.transformed[0]);
14473
14853
  const scriptKind = sourceFile.fileName.endsWith(".tsx") || sourceFile.fileName.endsWith(".ts") ? ts$1.ScriptKind.TSX : ts$1.ScriptKind.JS;
14474
14854
  return ts$1.createSourceFile(sourceFile.fileName, printed, sourceFile.languageVersion, true, scriptKind);
@@ -14493,19 +14873,6 @@ function getExtendsClassNames(node) {
14493
14873
  if (ts$1.isCallExpression(expr) && expr.expression.getText() === "Mixin") return expr.arguments.filter(ts$1.isIdentifier).map((id) => id.text);
14494
14874
  return [];
14495
14875
  }
14496
- function findImportSpecifier(sf, localName) {
14497
- for (const stmt of sf.statements) {
14498
- if (!ts$1.isImportDeclaration(stmt) || !ts$1.isStringLiteral(stmt.moduleSpecifier)) continue;
14499
- const clause = stmt.importClause;
14500
- if (!clause) continue;
14501
- if (clause.name?.text === localName) return stmt.moduleSpecifier.text;
14502
- const bindings = clause.namedBindings;
14503
- if (bindings && ts$1.isNamedImports(bindings)) {
14504
- for (const el of bindings.elements) if (el.name.text === localName) return stmt.moduleSpecifier.text;
14505
- }
14506
- }
14507
- return null;
14508
- }
14509
14876
  /**
14510
14877
  * A single-file mini-program (see `convertInMemorySourceDecorators`) can
14511
14878
  * never load an imported module's own `SourceFile`, so a type that's
@@ -14529,7 +14896,7 @@ function reclassifyGlobalTypeReferences(members, declaringSf, declaringPath, res
14529
14896
  if (!references) return;
14530
14897
  Object.entries(references).forEach(([typeName, reference]) => {
14531
14898
  if (reference.location !== "global") return;
14532
- const specifier = findImportSpecifier(declaringSf, typeName);
14899
+ const specifier = findImportOrigin(declaringSf, typeName)?.moduleSpecifier;
14533
14900
  if (!specifier) return;
14534
14901
  const resolved = resolveImport(specifier, declaringPath);
14535
14902
  reference.location = "import";
@@ -14541,7 +14908,7 @@ function reclassifyGlobalTypeReferences(members, declaringSf, declaringPath, res
14541
14908
  }
14542
14909
  /**
14543
14910
  * Looks for `name` as a direct top-level declaration in `sf`; if not found, follows one level of
14544
- * re-export (barrel file) via `resolveImport` - matching `compiler-ctx-merge.ts`'s equivalent
14911
+ * re-export (barrel file, named or `export *`) via `resolveImport` - matching `compiler-ctx-merge.ts`'s equivalent
14545
14912
  * one-hop fallback (see `findReExport` in `shared.ts` for why it's capped at one hop).
14546
14913
  *
14547
14914
  * @param sf the source file to search
@@ -14552,26 +14919,31 @@ function reclassifyGlobalTypeReferences(members, declaringSf, declaringPath, res
14552
14919
  * differ from `sf`/`path` if resolved through a re-export), or `undefined`
14553
14920
  */
14554
14921
  function findDeclarationOrReExport(sf, path, name, resolveImport) {
14555
- const direct = sf.statements.find(matchesNamedDeclaration(name));
14922
+ const direct = findStatementByName(sf, name);
14556
14923
  if (direct) return {
14557
14924
  statement: direct,
14558
14925
  sourceFile: sf,
14559
14926
  path
14560
14927
  };
14561
- const reExport = findReExport(sf, name);
14562
- if (!reExport) return void 0;
14563
- const resolved = resolveImport(reExport.moduleSpecifier, path);
14564
- if (!resolved) return void 0;
14565
- const { code, path: resolvedPath } = resolved;
14566
- const isTs = resolvedPath.endsWith(".tsx") || resolvedPath.endsWith(".ts");
14567
- const reExportSf = ts$1.createSourceFile(resolvedPath, code, ts$1.ScriptTarget.ESNext, true, isTs ? ts$1.ScriptKind.TSX : ts$1.ScriptKind.JS);
14568
- const statement = reExportSf.statements.find(matchesNamedDeclaration(reExport.localName));
14569
- if (!statement) return void 0;
14570
- return {
14571
- statement,
14572
- sourceFile: reExportSf,
14573
- path: resolvedPath
14928
+ const findIn = (moduleSpecifier, localName) => {
14929
+ const resolved = resolveImport(moduleSpecifier, path);
14930
+ if (!resolved) return void 0;
14931
+ const { code, path: resolvedPath } = resolved;
14932
+ const isTs = resolvedPath.endsWith(".tsx") || resolvedPath.endsWith(".ts");
14933
+ const reExportSf = ts$1.createSourceFile(resolvedPath, code, ts$1.ScriptTarget.ESNext, true, isTs ? ts$1.ScriptKind.TSX : ts$1.ScriptKind.JS);
14934
+ const statement = findStatementByName(reExportSf, localName);
14935
+ return statement && {
14936
+ statement,
14937
+ sourceFile: reExportSf,
14938
+ path: resolvedPath
14939
+ };
14574
14940
  };
14941
+ const reExport = findReExport(sf, name);
14942
+ if (reExport) return findIn(reExport.moduleSpecifier, reExport.localName);
14943
+ for (const moduleSpecifier of findStarReExportSpecifiers(sf)) {
14944
+ const found = findIn(moduleSpecifier, name);
14945
+ if (found) return found;
14946
+ }
14575
14947
  }
14576
14948
  /**
14577
14949
  * Recursively resolves a class's `extends` heritage into a flat, deduplicated
@@ -14602,7 +14974,7 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
14602
14974
  let foundSf = sf;
14603
14975
  let foundPath = path;
14604
14976
  let keepLooking = true;
14605
- const sameFileStatement = sf.statements.find(matchesNamedDeclaration(parentName));
14977
+ const sameFileStatement = findStatementByName(sf, parentName);
14606
14978
  if (sameFileStatement) {
14607
14979
  if (ts$1.isClassDeclaration(sameFileStatement)) foundClass = sameFileStatement;
14608
14980
  else {
@@ -14611,7 +14983,7 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
14611
14983
  if (!foundClass) warnMixinFactoryClassNotFound(buildCtx, parentName, rootClassDeclaration);
14612
14984
  }
14613
14985
  } else {
14614
- const specifier = findImportSpecifier(sf, parentName);
14986
+ const specifier = findImportOrigin(sf, parentName)?.moduleSpecifier;
14615
14987
  if (!specifier) continue;
14616
14988
  const resolved = resolveImport(specifier, path);
14617
14989
  if (!resolved) continue;
@@ -14643,7 +15015,8 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
14643
15015
  ancestors.push({
14644
15016
  classNode: foundClass,
14645
15017
  sourceFile: foundSf,
14646
- path: foundPath
15018
+ path: foundPath,
15019
+ factoryName: parentName
14647
15020
  });
14648
15021
  if (keepLooking) resolveAncestors(foundClass, foundSf, foundPath, resolveImport, visited, ancestors, rootClassDeclaration, buildCtx);
14649
15022
  }
@@ -14660,8 +15033,8 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
14660
15033
  * @returns the ancestor's metadata
14661
15034
  */
14662
15035
  function extractAncestorMeta(ancestor, cmpSourceFile, resolveImport, config) {
14663
- const { classNode, sourceFile: parentSf, path: resolvedPath } = ancestor;
14664
- const className = classNode.name?.text;
15036
+ const { classNode, sourceFile: parentSf, path: resolvedPath, factoryName } = ancestor;
15037
+ const className = classNode.name?.text ?? factoryName;
14665
15038
  const parentStaticMembers = classNode.members.filter(isStaticGetter);
14666
15039
  let resolvedClassNode = classNode;
14667
15040
  let resolvedStaticMembers = parentStaticMembers;
@@ -14753,7 +15126,6 @@ function mergeExtendedClassMetaWithResolveImport(cmpNode, staticMembers, sourceF
14753
15126
  //#region src/compiler/transformers/static-to-meta/class-methods.ts
14754
15127
  const parseClassMethods = (classMethods, cmpMeta) => {
14755
15128
  if (!classMethods?.length) return;
14756
- const hasHostData = classMethods.includes("hostData");
14757
15129
  cmpMeta.hasAttributeChangedCallbackFn = classMethods.includes("attributeChangedCallback");
14758
15130
  cmpMeta.hasConnectedCallbackFn = classMethods.includes("connectedCallback");
14759
15131
  cmpMeta.hasDisconnectedCallbackFn = classMethods.includes("disconnectedCallback");
@@ -14765,8 +15137,7 @@ const parseClassMethods = (classMethods, cmpMeta) => {
14765
15137
  cmpMeta.hasComponentShouldUpdateFn = classMethods.includes("componentShouldUpdate");
14766
15138
  cmpMeta.hasComponentDidUpdateFn = classMethods.includes("componentDidUpdate");
14767
15139
  cmpMeta.hasLifecycle = cmpMeta.hasComponentWillLoadFn || cmpMeta.hasComponentDidLoadFn || cmpMeta.hasComponentWillUpdateFn || cmpMeta.hasComponentDidUpdateFn;
14768
- cmpMeta.hasRenderFn = classMethods.includes("render") || hasHostData;
14769
- cmpMeta.hasVdomRender = cmpMeta.hasVdomRender || hasHostData;
15140
+ cmpMeta.hasRenderFn = classMethods.includes("render");
14770
15141
  };
14771
15142
  //#endregion
14772
15143
  //#region src/compiler/transformers/static-to-meta/element-ref.ts
@@ -15146,13 +15517,13 @@ const parseStaticComponentMeta = (compilerCtx, typeChecker, cmpNode, moduleFile,
15146
15517
  hasPatchClone: false,
15147
15518
  hasPatchInsert: false
15148
15519
  };
15149
- const visitComponentChildNode = (node, ctx) => {
15150
- validateComponentMembers(node, ctx);
15151
- if (ts$1.isCallExpression(node)) parseCallExpression(cmp, node, typeChecker);
15520
+ if (!isCollectionDependency) validateComponentMembers(cmpNode, buildCtx);
15521
+ const visitComponentChildNode = (node) => {
15522
+ if (ts$1.isCallExpression(node)) parseCallExpression(cmp, node, typeChecker, moduleFile);
15152
15523
  else if (ts$1.isStringLiteral(node)) parseStringLiteral(cmp, node);
15153
- node.forEachChild((child) => visitComponentChildNode(child, ctx));
15524
+ node.forEachChild(visitComponentChildNode);
15154
15525
  };
15155
- visitComponentChildNode(cmpNode, buildCtx);
15526
+ visitComponentChildNode(cmpNode);
15156
15527
  parseClassMethods(classMethods, cmp);
15157
15528
  cmp.hasModernPropertyDecls = detectModernPropDeclarations(cmpNode) || doesExtend;
15158
15529
  cmp.htmlAttrNames = unique(cmp.htmlAttrNames);
@@ -15170,31 +15541,32 @@ const parseStaticComponentMeta = (compilerCtx, typeChecker, cmpNode, moduleFile,
15170
15541
  return cmpNode;
15171
15542
  };
15172
15543
  /**
15173
- * Check whether a class declaration is a Stencil component, i.e. it's
15174
- * decorated with `@Component({ tag: ... })`.
15175
- * @param classNode the class declaration to check
15176
- * @returns whether `classNode` is a Stencil component class
15544
+ * Warn about members a Stencil component class should not define.
15545
+ * @param cmpNode the component class declaration
15546
+ * @param buildCtx the current build context, used to surface diagnostics
15177
15547
  */
15178
- const isStencilComponentClass = (classNode) => {
15179
- const decorator = ts$1.getDecorators(classNode)?.[0];
15180
- return decorator != null && ts$1.isCallExpression(decorator.expression) && decorator.expression.arguments.length === 1 && ts$1.isObjectLiteralExpression(decorator.expression.arguments[0]) && decorator.expression.arguments[0].properties.some((prop) => ts$1.isPropertyAssignment(prop) && prop.name.getText() === "tag");
15181
- };
15182
- const validateComponentMembers = (node, buildCtx) => {
15183
- /**
15184
- * validate if:
15185
- */
15186
- if (ts$1.isGetAccessorDeclaration(node) && ts$1.isIdentifier(node.name) && typeof node.name.escapedText === "string" && BLACKLISTED_COMPONENT_METHODS.includes(node.name.escapedText) && node.parent && ts$1.isClassDeclaration(node.parent) && isStencilComponentClass(node.parent)) {
15187
- const propName = node.name.escapedText;
15188
- const componentName = node.parent.name.getText();
15189
- const err = buildWarn(buildCtx.diagnostics);
15190
- 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.`;
15191
- augmentDiagnosticWithNode(err, node);
15192
- }
15193
- if (ts$1.isMethodDeclaration(node) && ts$1.isIdentifier(node.name) && node.name.escapedText === "componentShouldUpdate" && node.parameters.length > 1 && node.parent && ts$1.isClassDeclaration(node.parent) && isStencilComponentClass(node.parent)) {
15194
- const componentName = node.parent.name.getText();
15195
- const err = buildWarn(buildCtx.diagnostics);
15196
- err.messageText = `The component "${componentName}" defines "componentShouldUpdate" with ${node.parameters.length} parameters. As of Stencil v5, "componentShouldUpdate" is called once per render with a single "changes" argument (a map of prop/state names to "{ newVal, oldVal }") instead of once per prop with "(newVal, oldVal, propName)". This method will still compile, but any extra parameters will be "undefined" at runtime.`;
15197
- augmentDiagnosticWithNode(err, node);
15548
+ const validateComponentMembers = (cmpNode, buildCtx) => {
15549
+ const componentName = cmpNode.name?.text ?? "";
15550
+ for (const member of cmpNode.members) {
15551
+ if (!member.name || !ts$1.isIdentifier(member.name)) continue;
15552
+ const memberName = member.name.text;
15553
+ /**
15554
+ * the component has a getter called "shadowRoot"
15555
+ */
15556
+ if (ts$1.isGetAccessorDeclaration(member) && BLACKLISTED_COMPONENT_METHODS.includes(memberName)) {
15557
+ const err = buildWarn(buildCtx.diagnostics);
15558
+ err.messageText = `The component "${componentName}" has a getter called "${memberName}". This getter is reserved for use by Stencil components and should not be defined by the user.`;
15559
+ augmentDiagnosticWithNode(err, ts$1.getOriginalNode(member));
15560
+ }
15561
+ /**
15562
+ * the component defines a "componentShouldUpdate" method with more than one parameter,
15563
+ * which was the pre-v5 per-prop signature "(newVal, oldVal, propName)"
15564
+ */
15565
+ if (ts$1.isMethodDeclaration(member) && memberName === "componentShouldUpdate" && member.parameters.length > 1) {
15566
+ const err = buildWarn(buildCtx.diagnostics);
15567
+ err.messageText = `The component "${componentName}" defines "componentShouldUpdate" with ${member.parameters.length} parameters. As of Stencil v5, "componentShouldUpdate" is called once per render with a single "changes" argument (a map of prop/state names to "{ newVal, oldVal }") instead of once per prop with "(newVal, oldVal, propName)". This method will still compile, but any extra parameters will be "undefined" at runtime.`;
15568
+ augmentDiagnosticWithNode(err, ts$1.getOriginalNode(member));
15569
+ }
15198
15570
  }
15199
15571
  };
15200
15572
  const parseVirtualProps = (docs) => {
@@ -15368,6 +15740,9 @@ const updateModule = (config, compilerCtx, buildCtx, tsSourceFile, sourceFileTex
15368
15740
  } else if (ts$1.isImportDeclaration(node)) {
15369
15741
  parseModuleImport(config, compilerCtx, buildCtx, moduleFile, srcDirPath, node, true);
15370
15742
  return;
15743
+ } else if (ts$1.isExportDeclaration(node)) {
15744
+ parseModuleReExport(moduleFile, srcDirPath, node);
15745
+ return;
15371
15746
  } else if (ts$1.isCallExpression(node)) parseCallExpression(moduleFile, node, typeChecker);
15372
15747
  else if (ts$1.isStringLiteral(node)) parseStringLiteral(moduleFile, node);
15373
15748
  else if (ts$1.isVariableStatement(node)) node.declarationList.declarations.forEach((declaration) => {
@@ -15538,18 +15913,32 @@ const addExternalImport = (config, compilerCtx, buildCtx, moduleFile, containing
15538
15913
  //#region src/compiler/transformers/static-to-meta/import.ts
15539
15914
  const parseModuleImport = (config, compilerCtx, buildCtx, moduleFile, dirPath, importNode, resolveCollections) => {
15540
15915
  if (importNode.moduleSpecifier && ts$1.isStringLiteral(importNode.moduleSpecifier)) {
15541
- let importPath = importNode.moduleSpecifier.text;
15916
+ const importPath = importNode.moduleSpecifier.text;
15542
15917
  if (!moduleFile.originalImports.includes(importPath)) moduleFile.originalImports.push(importPath);
15543
15918
  if (importPath === "@stencil/core/signals") moduleFile.hasSignalsImport = true;
15544
- if (isAbsolute(importPath)) {
15545
- importPath = normalizePath(importPath);
15546
- moduleFile.localImports.push(importPath);
15547
- } else if (importPath.startsWith(".")) {
15548
- importPath = normalizePath(join$1(dirPath, importPath));
15549
- moduleFile.localImports.push(importPath);
15550
- } else addExternalImport(config, compilerCtx, buildCtx, moduleFile, moduleFile.sourceFilePath, importPath, resolveCollections, !importNode.importClause);
15919
+ const localPath = resolveLocalImportPath(dirPath, importPath);
15920
+ if (localPath) moduleFile.localImports.push(localPath);
15921
+ else addExternalImport(config, compilerCtx, buildCtx, moduleFile, moduleFile.sourceFilePath, importPath, resolveCollections, !importNode.importClause);
15551
15922
  }
15552
15923
  };
15924
+ /**
15925
+ * Record a local `export … from './x'` re-export as a local import, so build conditionals
15926
+ * propagate through barrel files. Bare-specifier re-exports are left alone.
15927
+ *
15928
+ * @param moduleFile the module containing the re-export
15929
+ * @param dirPath the module's (normalized) directory
15930
+ * @param exportNode the export declaration
15931
+ */
15932
+ const parseModuleReExport = (moduleFile, dirPath, exportNode) => {
15933
+ if (exportNode.moduleSpecifier && ts$1.isStringLiteral(exportNode.moduleSpecifier)) {
15934
+ const localPath = resolveLocalImportPath(dirPath, exportNode.moduleSpecifier.text);
15935
+ if (localPath && !moduleFile.localImports.includes(localPath)) moduleFile.localImports.push(localPath);
15936
+ }
15937
+ };
15938
+ const resolveLocalImportPath = (dirPath, importPath) => {
15939
+ if (isAbsolute(importPath)) return normalizePath(importPath);
15940
+ if (importPath.startsWith(".")) return normalizePath(join$1(dirPath, importPath));
15941
+ };
15553
15942
  //#endregion
15554
15943
  //#region src/compiler/transformers/static-to-meta/visitor.ts
15555
15944
  const convertStaticToMeta = (config, compilerCtx, buildCtx, typeChecker, collection, transformOpts) => {
@@ -15559,6 +15948,7 @@ const convertStaticToMeta = (config, compilerCtx, buildCtx, typeChecker, collect
15559
15948
  const visitNode = (node) => {
15560
15949
  if (ts$1.isClassDeclaration(node)) return parseStaticComponentMeta(compilerCtx, typeChecker, node, moduleFile, buildCtx, transformOpts);
15561
15950
  else if (ts$1.isImportDeclaration(node)) parseModuleImport(config, compilerCtx, buildCtx, moduleFile, dirPath, node, !transformOpts.isolatedModules);
15951
+ else if (ts$1.isExportDeclaration(node)) parseModuleReExport(moduleFile, dirPath, node);
15562
15952
  else if (ts$1.isCallExpression(node)) parseCallExpression(moduleFile, node, typeChecker);
15563
15953
  else if (ts$1.isStringLiteral(node)) parseStringLiteral(moduleFile, node);
15564
15954
  return ts$1.visitEachChild(node, visitNode, transformCtx);
@@ -15665,6 +16055,7 @@ const transpileModule = (config, input, transformOpts) => {
15665
16055
  ...config,
15666
16056
  logger: createNodeLogger()
15667
16057
  };
16058
+ resetDeprecatedApiWarning();
15668
16059
  const compilerCtx = new CompilerContext();
15669
16060
  const buildCtx = new BuildContext(config, compilerCtx);
15670
16061
  const tsCompilerOptions = { ...config.tsCompilerOptions };
@@ -15842,6 +16233,7 @@ const transpileCss = async (transformInput, results) => {
15842
16233
  results.map = cssResults.map;
15843
16234
  results.imports = cssResults.imports.map((p) => ({ path: p.importPath }));
15844
16235
  results.diagnostics.push(...cssResults.diagnostics);
16236
+ if (transformInput.docs) results.styleDocs = cssResults.styleDocs;
15845
16237
  };
15846
16238
  const transpileCssSync = (transformInput, results) => {
15847
16239
  const cssResults = transformCssToEsmSync(transformInput);
@@ -15849,6 +16241,7 @@ const transpileCssSync = (transformInput, results) => {
15849
16241
  results.map = cssResults.map;
15850
16242
  results.imports = cssResults.imports.map((p) => ({ path: p.importPath }));
15851
16243
  results.diagnostics.push(...cssResults.diagnostics);
16244
+ if (transformInput.docs) results.styleDocs = cssResults.styleDocs;
15852
16245
  };
15853
16246
  const transpileJson = (results) => {
15854
16247
  results.code = dataToEsm(JSON.parse(results.code), {
@@ -16279,7 +16672,7 @@ const FORM_ASSOCIATED_ATTRIBUTES = [
16279
16672
  * @param cmp the metadata for the component that a type definition string is generated for
16280
16673
  * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions
16281
16674
  * @param areTypesInternal `true` if types being generated are for a project's internal purposes, `false` otherwise
16282
- * @param signalBacking `true` if the component is using signal backing for its props; includes the signals map on the element interface
16675
+ * @param signalBacking `true` if the component is using signal backing for its props; includes the signals map on the element interface and unions JSX prop types with `ReadonlySignal<T>`
16283
16676
  * @returns the generated types string alongside additional metadata
16284
16677
  */
16285
16678
  const generateComponentTypes = (cmp, typeImportData, areTypesInternal, signalBacking = false) => {
@@ -16296,8 +16689,12 @@ const generateComponentTypes = (cmp, typeImportData, areTypesInternal, signalBac
16296
16689
  const isDep = cmp.isCollectionDependency;
16297
16690
  const propNames = new Set(propAttributes.map((p) => p.name));
16298
16691
  const formAssociatedAttrs = cmp.formAssociated ? FORM_ASSOCIATED_ATTRIBUTES.filter((attr) => !propNames.has(attr.name)) : [];
16692
+ const jsxPropAttributes = signalBacking ? propAttributes.map((attr) => ({
16693
+ ...attr,
16694
+ type: `${attr.type} | ReadonlySignal<${attr.type}>`
16695
+ })) : propAttributes;
16299
16696
  const jsxAttributes = attributesToMultiLineString([
16300
- ...propAttributes,
16697
+ ...jsxPropAttributes,
16301
16698
  ...eventAttributes,
16302
16699
  ...formAssociatedAttrs
16303
16700
  ], true, areTypesInternal);