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

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-DIvBaMnB.mjs} +182 -70
  3. package/dist/compiler/browser.d.ts +114 -81
  4. package/dist/compiler/browser.js +743 -339
  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-BI12oAIV.mjs} +4840 -2899
  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 +62 -58
  12. package/dist/{index-DmHmu3y0.d.mts → index-BGUOG9Wc.d.mts} +6 -2
  13. package/dist/{index-BopBfjPu.d.mts → index-BogZpjP2.d.mts} +150 -127
  14. package/dist/{index-BXAcVN2j.d.ts → index-CicD4Pgn.d.ts} +59 -55
  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-D-21Ykxi.mjs} +41 -47
  20. package/dist/runtime/client/lazy.js +321 -200
  21. package/dist/runtime/client/runtime.d.ts +73 -66
  22. package/dist/runtime/client/runtime.js +321 -200
  23. package/dist/runtime/index.d.ts +4 -5
  24. package/dist/runtime/index.js +319 -198
  25. package/dist/runtime/server/index.d.mts +11 -11
  26. package/dist/runtime/server/index.mjs +371 -239
  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 +328 -212
  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.31";
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
@@ -12678,7 +12829,8 @@ const parseMethodDecorator = (config, diagnostics, tsSourceFile, typeChecker, pr
12678
12829
  const returnTypeNode = typeChecker.typeToTypeNode(returnType, method, ts$1.NodeBuilderFlags.NoTruncation | ts$1.NodeBuilderFlags.NoTypeReduction);
12679
12830
  let returnString = typeToString(typeChecker, returnType);
12680
12831
  let signatureString = typeChecker.signatureToString(signature, method, flags, ts$1.SignatureKind.Call);
12681
- if (!config._isTesting) {
12832
+ const isAsync = !!method.modifiers?.some((m) => m.kind === ts$1.SyntaxKind.AsyncKeyword);
12833
+ if (!config._isTesting && !isAsync) {
12682
12834
  if (returnString === "void") {
12683
12835
  const warn = buildWarn(diagnostics);
12684
12836
  warn.header = "@Method requires async";
@@ -13194,14 +13346,16 @@ const parseWatchDecorator = (typeChecker, method, decoratorName) => {
13194
13346
  * @param diagnostics for surfacing errors and warnings
13195
13347
  * @param typeChecker a TypeScript typechecker instance
13196
13348
  * @param program a {@link ts.Program} object
13349
+ * @param includeClassExpressions also convert `ts.ClassExpression` nodes (e.g. a mixin factory's
13350
+ * `(Base) => class extends Base {}`), not just named `ts.ClassDeclaration`s
13197
13351
  * @returns a TypeScript transformer factory which can be passed to
13198
13352
  * TypeScript to transform source code during the compilation process
13199
13353
  */
13200
- const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) => {
13354
+ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program, includeClassExpressions = false) => {
13201
13355
  return (transformCtx) => {
13202
13356
  let sourceFile;
13203
13357
  const visit = (node) => {
13204
- if (ts$1.isClassDeclaration(node)) return visitClassDeclaration(config, diagnostics, typeChecker, program, node, sourceFile);
13358
+ if (ts$1.isClassDeclaration(node) || includeClassExpressions && ts$1.isClassExpression(node)) return visitClassDeclaration(config, diagnostics, typeChecker, program, node, sourceFile);
13205
13359
  return ts$1.visitEachChild(node, visit, transformCtx);
13206
13360
  };
13207
13361
  return (tsSourceFile) => {
@@ -13211,10 +13365,10 @@ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) =>
13211
13365
  };
13212
13366
  };
13213
13367
  /**
13214
- * Visit {@link ts.ClassDeclaration} nodes as part of the tree-traversal
13368
+ * Visit {@link ts.ClassDeclaration}/{@link ts.ClassExpression} nodes as part of the tree-traversal
13215
13369
  * required for {@link convertDecoratorsToStatic} to work.
13216
13370
  *
13217
- * If a given class declaration node is not decorated with `@Component` this
13371
+ * If a given class node is not decorated with `@Component` this
13218
13372
  * function will simply return it as-is. If it _is_ decorated, then it will
13219
13373
  *
13220
13374
  * 1. Convert the arguments to the `@Component` decorator to static values.
@@ -13223,7 +13377,7 @@ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) =>
13223
13377
  * to static values.
13224
13378
  * 3. Validate that the various options selected by the component author are
13225
13379
  * valid, both individually and in combination.
13226
- * 4. Return an updated class declaration node which is ready to be used in
13380
+ * 4. Return an updated class node which is ready to be used in
13227
13381
  * the rest of the Stencil compilation pipeline (e.g. in output target
13228
13382
  * generation).
13229
13383
  *
@@ -13242,7 +13396,7 @@ const visitClassDeclaration = (config, diagnostics, typeChecker, program, classN
13242
13396
  const decoratedMembers = classMembers.filter((member) => (retrieveTsDecorators(member)?.length ?? 0) > 0);
13243
13397
  if (!decoratedMembers.length && !componentDecorator) return classNode;
13244
13398
  const filteredMethodsAndFields = removeStencilMethodDecorators(Array.from(classMembers), diagnostics, importAliasMap);
13245
- if (componentDecorator) componentDecoratorToStatic(config, typeChecker, diagnostics, classNode, filteredMethodsAndFields, componentDecorator);
13399
+ if (componentDecorator && ts$1.isClassDeclaration(classNode)) componentDecoratorToStatic(config, typeChecker, diagnostics, classNode, filteredMethodsAndFields, componentDecorator);
13246
13400
  if (decoratedMembers.length > 0) {
13247
13401
  const serializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("PropSerialize"), "PropSerialize", importAliasMap.get("Prop"));
13248
13402
  const deserializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("AttrDeserialize"), "AttrDeserialize", importAliasMap.get("Prop"));
@@ -13258,7 +13412,8 @@ const visitClassDeclaration = (config, diagnostics, typeChecker, program, classN
13258
13412
  validateMethods(diagnostics, classMembers);
13259
13413
  const currentDecorators = retrieveTsDecorators(classNode);
13260
13414
  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);
13415
+ const updatedModifiers = [...filterDecorators(currentDecorators, CLASS_DECORATORS_TO_REMOVE.map((decorator) => importAliasMap.get(decorator))) ?? [], ...retrieveTsModifiers(classNode) ?? []];
13416
+ 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
13417
  };
13263
13418
  /**
13264
13419
  * Take a list of `ClassElement` AST nodes and remove any decorators from
@@ -13524,12 +13679,18 @@ const gatherVdomMeta = (m, args, typeChecker) => {
13524
13679
  };
13525
13680
  //#endregion
13526
13681
  //#region src/compiler/transformers/static-to-meta/call-expression.ts
13527
- const parseCallExpression = (m, node, typeChecker) => {
13682
+ /**
13683
+ * @param m the module or component to record vdom metadata on
13684
+ * @param node the call expression to parse
13685
+ * @param typeChecker used to resolve functional components / JSX-returning calls to their source
13686
+ * @param moduleFile the module to record those dependencies on; defaults to `m` when it's a module
13687
+ */
13688
+ const parseCallExpression = (m, node, typeChecker, moduleFile = "functionalComponentDeps" in m ? m : void 0) => {
13528
13689
  if (node.arguments != null && node.arguments.length > 0) {
13529
- if (ts$1.isIdentifier(node.expression)) visitCallExpressionArgs(m, node.expression, node.arguments, typeChecker);
13690
+ if (ts$1.isIdentifier(node.expression)) visitCallExpressionArgs(m, node.expression, node.arguments, typeChecker, moduleFile);
13530
13691
  else if (ts$1.isPropertyAccessExpression(node.expression)) {
13531
13692
  const n = node.expression.name;
13532
- if (ts$1.isIdentifier(n) && n) visitCallExpressionArgs(m, n, node.arguments, typeChecker);
13693
+ if (ts$1.isIdentifier(n) && n) visitCallExpressionArgs(m, n, node.arguments, typeChecker, moduleFile);
13533
13694
  }
13534
13695
  } else if (ts$1.isPropertyAccessExpression(node.expression)) {
13535
13696
  if (ts$1.isIdentifier(node.expression.name)) {
@@ -13539,24 +13700,20 @@ const parseCallExpression = (m, node, typeChecker) => {
13539
13700
  if (!declarations || declarations.length === 0) return;
13540
13701
  const sourceFile = declarations[0].getSourceFile();
13541
13702
  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
- }
13703
+ addFunctionalComponentDep(moduleFile, sourceFile);
13547
13704
  }
13548
13705
  }
13549
13706
  };
13550
- const visitCallExpressionArgs = (m, callExpressionName, args, typeChecker) => {
13707
+ const visitCallExpressionArgs = (m, callExpressionName, args, typeChecker, moduleFile) => {
13551
13708
  const fnName = callExpressionName.escapedText;
13552
13709
  if (fnName === "h" || fnName === "__stencil_h" || fnName === "createElement") {
13553
- visitCallExpressionArg(m, args[0], typeChecker);
13710
+ visitCallExpressionArg(m, args[0], typeChecker, moduleFile);
13554
13711
  if (fnName === "h" || fnName === "__stencil_h") gatherVdomMeta(m, args, typeChecker);
13555
13712
  } else if (fnName === "jsx" || fnName === "jsxs" || fnName === "_jsx" || fnName === "_jsxs") {
13556
- visitCallExpressionArg(m, args[0], typeChecker);
13713
+ visitCallExpressionArg(m, args[0], typeChecker, moduleFile);
13557
13714
  gatherVdomMeta(m, args, typeChecker);
13558
13715
  if (args.length > 2 && args[2]) m.hasVdomKey = true;
13559
- } else if (args.length > 1 && fnName === "createElementNS") visitCallExpressionArg(m, args[1], typeChecker);
13716
+ } else if (args.length > 1 && fnName === "createElementNS") visitCallExpressionArg(m, args[1], typeChecker, moduleFile);
13560
13717
  else if (fnName === "require" && args.length > 0 && m.originalImports) {
13561
13718
  const arg = args[0];
13562
13719
  if (ts$1.isStringLiteral(arg)) {
@@ -13564,7 +13721,7 @@ const visitCallExpressionArgs = (m, callExpressionName, args, typeChecker) => {
13564
13721
  }
13565
13722
  }
13566
13723
  };
13567
- const visitCallExpressionArg = (m, arg, typeChecker) => {
13724
+ const visitCallExpressionArg = (m, arg, typeChecker, moduleFile) => {
13568
13725
  if (ts$1.isStringLiteral(arg)) {
13569
13726
  let tag = arg.text;
13570
13727
  if (typeof tag === "string") {
@@ -13572,31 +13729,31 @@ const visitCallExpressionArg = (m, arg, typeChecker) => {
13572
13729
  m.htmlTagNames.push(tag);
13573
13730
  if (tag.includes("-")) m.potentialCmpRefs.push(tag);
13574
13731
  }
13575
- } else if (typeChecker && ts$1.isIdentifier(arg)) resolveFunctionalComponentDep(m, arg, typeChecker);
13732
+ } else if (typeChecker && ts$1.isIdentifier(arg)) resolveFunctionalComponentDep(moduleFile, arg, typeChecker);
13576
13733
  };
13577
13734
  /**
13578
13735
  * Resolves a functional component identifier to its source file and tracks it
13579
13736
  * as a dependency so that build-conditionals can be properly propagated.
13737
+ * Follows import / re-export aliases through to the declaring file.
13580
13738
  *
13581
- * @param m the module or component metadata to track the dependency on
13739
+ * @param moduleFile the module to track the dependency on
13582
13740
  * @param identifier the identifier node representing the functional component
13583
13741
  * @param typeChecker the TypeScript type checker for symbol resolution
13584
13742
  */
13585
- const resolveFunctionalComponentDep = (m, identifier, typeChecker) => {
13743
+ const resolveFunctionalComponentDep = (moduleFile, identifier, typeChecker) => {
13744
+ if (!moduleFile) return;
13586
13745
  try {
13587
13746
  const symbol = typeChecker.getSymbolAtLocation(identifier);
13588
13747
  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
- }
13748
+ const sourceFile = (symbol.flags & ts$1.SymbolFlags.Alias ? typeChecker.getAliasedSymbol(symbol) : symbol).declarations?.[0]?.getSourceFile();
13749
+ if (sourceFile) addFunctionalComponentDep(moduleFile, sourceFile);
13598
13750
  } catch {}
13599
13751
  };
13752
+ const addFunctionalComponentDep = (moduleFile, sourceFile) => {
13753
+ const deps = moduleFile?.functionalComponentDeps;
13754
+ const sourceFilePath = normalizePath(sourceFile.fileName);
13755
+ if (deps && !deps.includes(sourceFilePath)) deps.push(sourceFilePath);
13756
+ };
13600
13757
  //#endregion
13601
13758
  //#region src/compiler/transformers/component-build-conditionals.ts
13602
13759
  const setComponentBuildConditionals = (cmpMeta) => {
@@ -13869,11 +14026,11 @@ const parseStaticWatchers = (staticMembers) => {
13869
14026
  //#endregion
13870
14027
  //#region src/compiler/transformers/static-to-meta/class-extension/shared.ts
13871
14028
  /**
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.
14029
+ * Warns when an `extends`/`Mixin(...)` target resolved to *something* but no class literal
14030
+ * could be found inside it - e.g. a mixin factory that returns an existing class by reference
14031
+ * (`(Base) => SomeExistingClass`) rather than a class literal. Without this, the target is
14032
+ * silently dropped: any `@Prop`/`@State` etc. it declares just never appears on the extending
14033
+ * component, with no diagnostic explaining why.
13877
14034
  * @param buildCtx used to surface the warning - omit to warn silently (e.g. from tests)
13878
14035
  * @param targetName the identifier the target was reached through
13879
14036
  * @param anchor the node to attach the warning to
@@ -13881,27 +14038,32 @@ const parseStaticWatchers = (staticMembers) => {
13881
14038
  function warnMixinFactoryClassNotFound(buildCtx, targetName, anchor) {
13882
14039
  if (!buildCtx) return;
13883
14040
  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.`;
14041
+ 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
14042
  if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, anchor);
13886
14043
  }
13887
14044
  /**
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 {}`).
14045
+ * Walks the AST looking for a class declaration or class expression, optionally by name -
14046
+ * descends into a mixin factory's wrapping function (arrow function or `function` declaration)
14047
+ * body too, since a mixin factory's class is always nested one level inside it. Recognizes all of:
14048
+ * `const Foo = (Base) => class extends Base {}` (concise arrow body), `const Foo = (Base) => {
14049
+ * return class extends Base {}; }` (block body, `return` of a class expression), and `const Foo =
14050
+ * (Base) => { class FooClass extends Base {} return FooClass; }` (block body, named declaration).
13892
14051
  * @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`
14052
+ * @param name if given, only matches a class with this name
14053
+ * @returns the found class, or `undefined`
13895
14054
  */
13896
14055
  function findClassWalk(node, name) {
13897
14056
  if (!node) return void 0;
13898
- if (ts$1.isClassDeclaration(node)) {
14057
+ if (ts$1.isClassDeclaration(node) || ts$1.isClassExpression(node)) {
13899
14058
  if (!name || node.name?.text === name) return node;
13900
14059
  } else if (ts$1.isVariableDeclaration(node) && (!name || name === node.name?.text) && node.initializer && ts$1.isArrowFunction(node.initializer)) {
14060
+ const body = node.initializer.body;
14061
+ if (ts$1.isClassExpression(body)) return body;
13901
14062
  let found;
13902
- ts$1.forEachChild(node.initializer.body, (child) => {
14063
+ ts$1.forEachChild(body, (child) => {
13903
14064
  if (found) return;
13904
14065
  if (ts$1.isClassDeclaration(child)) found = child;
14066
+ else if (ts$1.isReturnStatement(child) && child.expression && ts$1.isClassExpression(child.expression)) found = child.expression;
13905
14067
  });
13906
14068
  return found;
13907
14069
  }
@@ -13914,6 +14076,22 @@ function findClassWalk(node, name) {
13914
14076
  return found;
13915
14077
  }
13916
14078
  /**
14079
+ * The declared name of a mixin-factory statement (`function Foo() {}`, or `const Foo = ...`) -
14080
+ * survives the decorator-to-static-getter transform even when the factory's inner class doesn't
14081
+ * have a name of its own, so it can anchor a post-transform re-lookup via `findClassWalk`.
14082
+ * @param node the factory statement (or its variable declaration) to read a name from
14083
+ * @returns the declared name, or `undefined` if it can't be determined
14084
+ */
14085
+ function factoryDeclaredName(node) {
14086
+ if (!node) return void 0;
14087
+ if (ts$1.isFunctionDeclaration(node)) return node.name?.text;
14088
+ if (ts$1.isVariableDeclaration(node)) return ts$1.isIdentifier(node.name) ? node.name.text : void 0;
14089
+ if (ts$1.isVariableStatement(node)) {
14090
+ const decl = node.declarationList.declarations[0];
14091
+ return decl && ts$1.isIdentifier(decl.name) ? decl.name.text : void 0;
14092
+ }
14093
+ }
14094
+ /**
13917
14095
  * Matches a top-level class/function/variable declaration by name - the three
13918
14096
  * shapes a mixin or base-class export can take (a plain class, a mixin
13919
14097
  * factory function declaration, or a mixin factory assigned to a `const`).
@@ -13931,22 +14109,173 @@ function matchesNamedDeclaration(name) {
13931
14109
  };
13932
14110
  }
13933
14111
  /**
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).
14112
+ * Finds a re-export of `className` in `sourceFile`: `export { X } from './y'`, or the
14113
+ * bundler-split shape `import { X as name } from './y'; export { name };` (no `from` clause).
13938
14114
  * @param sourceFile the (barrel) source file to scan
13939
14115
  * @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
14116
+ * @returns the module specifier and name to look for there (before any `as` aliasing), or
14117
+ * `undefined` if not found
13942
14118
  */
13943
14119
  function findReExport(sourceFile, className) {
13944
14120
  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 {
14121
+ if (!ts$1.isExportDeclaration(stmt) || !stmt.exportClause || !ts$1.isNamedExports(stmt.exportClause)) continue;
14122
+ const element = stmt.exportClause.elements.find((el) => el.name.text === className);
14123
+ if (!element) continue;
14124
+ if (stmt.moduleSpecifier && ts$1.isStringLiteral(stmt.moduleSpecifier)) return {
13947
14125
  moduleSpecifier: stmt.moduleSpecifier.text,
13948
14126
  localName: element.propertyName?.text ?? element.name.text
13949
14127
  };
14128
+ const importOrigin = findImportOrigin(sourceFile, element.propertyName?.text ?? element.name.text);
14129
+ if (importOrigin) return importOrigin;
14130
+ }
14131
+ }
14132
+ /**
14133
+ * @param sourceFile the (barrel) source file to scan
14134
+ * @returns the module specifiers of its `export * from './x'` statements, in order
14135
+ */
14136
+ function findStarReExportSpecifiers(sourceFile) {
14137
+ return sourceFile.statements.flatMap((stmt) => ts$1.isExportDeclaration(stmt) && !stmt.exportClause && !stmt.isTypeOnly && stmt.moduleSpecifier && ts$1.isStringLiteral(stmt.moduleSpecifier) ? [stmt.moduleSpecifier.text] : []);
14138
+ }
14139
+ /**
14140
+ * Finds `name`'s import in `sourceFile` and returns its module and origin name (before any `as`
14141
+ * aliasing; `'default'` for a default import).
14142
+ * @param sourceFile the source file to scan for a matching import
14143
+ * @param name the local (post-aliasing) name an import bound
14144
+ * @returns the import's module specifier and origin name, or `undefined` if `name` isn't imported
14145
+ */
14146
+ function findImportOrigin(sourceFile, name) {
14147
+ for (const stmt of sourceFile.statements) {
14148
+ if (!ts$1.isImportDeclaration(stmt) || !stmt.importClause || !ts$1.isStringLiteral(stmt.moduleSpecifier)) continue;
14149
+ const moduleSpecifier = stmt.moduleSpecifier.text;
14150
+ if (stmt.importClause.name?.text === name) return {
14151
+ moduleSpecifier,
14152
+ localName: "default"
14153
+ };
14154
+ const bindings = stmt.importClause.namedBindings;
14155
+ if (!bindings || !ts$1.isNamedImports(bindings)) continue;
14156
+ const element = bindings.elements.find((el) => el.name.text === name);
14157
+ if (element) return {
14158
+ moduleSpecifier,
14159
+ localName: element.propertyName?.text ?? element.name.text
14160
+ };
14161
+ }
14162
+ }
14163
+ /**
14164
+ * Finds `name` as a top-level declaration in `sf` (see `matchesNamedDeclaration`), following a
14165
+ * same-file export alias if `name` is only ever the public side of a local rename
14166
+ * (`export { RealName as name }`, no `from` clause).
14167
+ * @param sf the source file to search
14168
+ * @param name the declaration name to look for, which may only exist as an export alias
14169
+ * @returns the matched statement, or `undefined`
14170
+ */
14171
+ function findStatementByName(sf, name) {
14172
+ const direct = sf.statements.find(matchesNamedDeclaration(name));
14173
+ if (direct) return direct;
14174
+ for (const stmt of sf.statements) {
14175
+ if (!ts$1.isExportDeclaration(stmt) || stmt.moduleSpecifier || !stmt.exportClause || !ts$1.isNamedExports(stmt.exportClause)) continue;
14176
+ const aliasedName = stmt.exportClause.elements.find((el) => el.name.text === name)?.propertyName?.text;
14177
+ if (aliasedName && aliasedName !== name) return sf.statements.find(matchesNamedDeclaration(aliasedName));
14178
+ }
14179
+ }
14180
+ /**
14181
+ * Picks the runtime target out of a `package.json` `exports` condition entry - prefers `import`
14182
+ * over `require`/`node`/`default`, recursing into nested condition objects.
14183
+ * @param entry an `exports` map value: a path string, or nested conditions
14184
+ * @returns the resolved relative path, or `undefined` if no usable condition was found
14185
+ */
14186
+ function pickJsCondition(entry) {
14187
+ if (typeof entry === "string") return entry;
14188
+ if (typeof entry !== "object" || entry === null) return;
14189
+ const conditions = entry;
14190
+ for (const key of [
14191
+ "import",
14192
+ "require",
14193
+ "node",
14194
+ "default"
14195
+ ]) if (key in conditions) {
14196
+ const picked = pickJsCondition(conditions[key]);
14197
+ if (picked) return picked;
14198
+ }
14199
+ }
14200
+ /**
14201
+ * Reads and parses `filePath` as JS, with parent nodes set - unlike `tsGetSourceFile`, which
14202
+ * never triggers binding, so `.parent` stays unset and `node.getSourceFile()` returns `undefined`.
14203
+ * @param config the current Stencil validated config
14204
+ * @param filePath the absolute path of the JS file to read and parse
14205
+ * @returns the parsed source file, or `undefined` if it couldn't be read
14206
+ */
14207
+ function readJsSourceFile(config, filePath) {
14208
+ try {
14209
+ const text = config.sys.readFileSync(filePath);
14210
+ if (typeof text !== "string") return;
14211
+ return ts$1.createSourceFile(filePath, text, ts$1.ScriptTarget.ESNext, true, ts$1.ScriptKind.JS);
14212
+ } catch {
14213
+ return;
14214
+ }
14215
+ }
14216
+ /**
14217
+ * Resolves the runtime JS entry for a bare (non-relative) module specifier by reading its
14218
+ * package's own `package.json` `exports` map, instead of `tsResolveModuleName` - which always
14219
+ * resolves to the package's `types` entry, an ambient signature with no body a mixin factory's
14220
+ * class can never be found inside.
14221
+ * @param config the current Stencil validated config
14222
+ * @param compilerCtx the current compiler context
14223
+ * @param moduleSpecifier the bare package specifier to resolve
14224
+ * @param containingFile the file the specifier was imported from
14225
+ * @returns the resolved JS source file, or `undefined` if it couldn't be resolved this way
14226
+ */
14227
+ function resolveModuleJsEntry(config, compilerCtx, moduleSpecifier, containingFile) {
14228
+ if (isLocalModule(moduleSpecifier)) return;
14229
+ const pkgJsonPath = tsResolveModuleNamePackageJsonPath(config, compilerCtx, moduleSpecifier, containingFile);
14230
+ if (!pkgJsonPath) return;
14231
+ let pkgJson;
14232
+ try {
14233
+ pkgJson = JSON.parse(config.sys.readFileSync(pkgJsonPath));
14234
+ } catch {
14235
+ return;
14236
+ }
14237
+ const pkgName = pkgJson.name;
14238
+ if (!pkgName || !moduleSpecifier.startsWith(pkgName) || !pkgJson.exports) return;
14239
+ const subpath = moduleSpecifier === pkgName ? "." : `.${moduleSpecifier.slice(pkgName.length)}`;
14240
+ const exportsMap = pkgJson.exports;
14241
+ const conditionEntry = typeof exportsMap === "string" ? subpath === "." ? exportsMap : void 0 : exportsMap[subpath] ?? (subpath === "." ? exportsMap : void 0);
14242
+ const target = conditionEntry && pickJsCondition(conditionEntry);
14243
+ if (!target) return;
14244
+ return readJsSourceFile(config, normalizePath(join$1(dirname(pkgJsonPath), target)));
14245
+ }
14246
+ /**
14247
+ * Finds `className`'s class inside a resolved JS entry (see `resolveModuleJsEntry`), following
14248
+ * re-export hops the same way `resolveAndProcessExtendedClass` walks a `.d.ts`/`.ts` source.
14249
+ * @param config the current Stencil validated config
14250
+ * @param compilerCtx the current compiler context
14251
+ * @param source the JS source file to search
14252
+ * @param className the class (or mixin factory) name to look for
14253
+ * @param hopsRemaining re-export hops still allowed before giving up
14254
+ * @returns the found class and the source file it's declared in, or `undefined`
14255
+ */
14256
+ function findClassInJsModule(config, compilerCtx, source, className, hopsRemaining = 3) {
14257
+ const matchedStatement = findStatementByName(source, className);
14258
+ if (matchedStatement) {
14259
+ const classNode = ts$1.isClassDeclaration(matchedStatement) ? matchedStatement : findClassWalk(matchedStatement);
14260
+ return classNode && {
14261
+ classNode,
14262
+ sourceFile: source
14263
+ };
14264
+ }
14265
+ if (hopsRemaining <= 0) return;
14266
+ const readReExported = (moduleSpecifier) => {
14267
+ const resolvedFileName = tsResolveModuleName(config, compilerCtx, moduleSpecifier, source.fileName)?.resolvedModule?.resolvedFileName;
14268
+ return resolvedFileName ? readJsSourceFile(config, resolvedFileName) : void 0;
14269
+ };
14270
+ const reExport = findReExport(source, className);
14271
+ if (reExport) {
14272
+ const nextSource = readReExported(reExport.moduleSpecifier);
14273
+ return nextSource && findClassInJsModule(config, compilerCtx, nextSource, reExport.localName, hopsRemaining - 1);
14274
+ }
14275
+ for (const moduleSpecifier of findStarReExportSpecifiers(source)) {
14276
+ const nextSource = readReExported(moduleSpecifier);
14277
+ const found = nextSource && findClassInJsModule(config, compilerCtx, nextSource, className, hopsRemaining - 1);
14278
+ if (found) return found;
13950
14279
  }
13951
14280
  }
13952
14281
  /**
@@ -14035,14 +14364,15 @@ function convertDiskSourceFileDecorators(sourceFile, config, target = ts$1.Scrip
14035
14364
  const program = ts$1.createProgram([sourceFile.fileName], compilerOptions, host);
14036
14365
  const typeChecker = program.getTypeChecker();
14037
14366
  const ownSourceFile = program.getSourceFile(sourceFile.fileName) ?? sourceFile;
14038
- const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program)]);
14367
+ const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program, true)]);
14039
14368
  const printed = ts$1.createPrinter({ removeComments: false }).printFile(result.transformed[0]);
14040
14369
  return ts$1.createSourceFile(sourceFile.fileName, printed, target, true);
14041
14370
  }
14042
14371
  /**
14043
14372
  * Resolves an `extends` target through a module specifier: resolves the
14044
14373
  * 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
14374
+ * own ancestors) to `dependentClasses`. Follows one level of re-export (barrel file, named or
14375
+ * `export *`) when the
14046
14376
  * declaration isn't found directly in the resolved module.
14047
14377
  * @param compilerCtx the current compiler context
14048
14378
  * @param buildCtx the current build context
@@ -14055,13 +14385,17 @@ function convertDiskSourceFileDecorators(sourceFile, config, target = ts$1.Scrip
14055
14385
  * @param ogModule the original module file of the class declaration
14056
14386
  * @param targetScriptTarget the script target to convert decorators with, if needed
14057
14387
  * @param barrelHopsRemaining re-export hops still allowed before giving up
14388
+ * @param originalModuleSpecifier the specifier this lookup started from, before any barrel hops
14389
+ * @param originalContainingFile the file `originalModuleSpecifier` was imported from
14058
14390
  * @returns the found class declaration, or `undefined`
14059
14391
  */
14060
- function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, currentSource, moduleSpecifier, className, dependentClasses, typeChecker, ogModule, targetScriptTarget = ts$1.ScriptTarget.ESNext, barrelHopsRemaining = 1) {
14392
+ function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, currentSource, moduleSpecifier, className, dependentClasses, typeChecker, ogModule, targetScriptTarget = ts$1.ScriptTarget.ESNext, barrelHopsRemaining = 1, originalModuleSpecifier = moduleSpecifier, originalContainingFile = currentSource.fileName) {
14061
14393
  let keepLooking = true;
14062
14394
  const foundFile = tsResolveModuleName(buildCtx.config, compilerCtx, moduleSpecifier, currentSource.fileName);
14063
14395
  if (!foundFile?.resolvedModule || !className) return;
14064
- let foundSource = compilerCtx.moduleMap.get(foundFile.resolvedModule.resolvedFileName)?.staticSourceFile;
14396
+ const resolvedFileName = foundFile.resolvedModule.resolvedFileName;
14397
+ let foundSource = compilerCtx.moduleMap.get(resolvedFileName)?.staticSourceFile;
14398
+ if (!foundSource && isJsFile(currentSource.fileName) && isJsFile(resolvedFileName)) foundSource = readJsSourceFile(buildCtx.config, resolvedFileName);
14065
14399
  if (!foundSource) {
14066
14400
  foundSource = tsGetSourceFile(buildCtx.config, foundFile);
14067
14401
  if (!foundSource) {
@@ -14073,10 +14407,10 @@ function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration,
14073
14407
  }
14074
14408
  foundSource = convertDiskSourceFileDecorators(foundSource, buildCtx.config, targetScriptTarget);
14075
14409
  }
14076
- const matchedStatement = foundSource.statements.find(matchesNamedDeclaration(className));
14410
+ const matchedStatement = findStatementByName(foundSource, className);
14077
14411
  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);
14412
+ const reExport = barrelHopsRemaining > 0 ? findReExport(foundSource, className) ?? findStarReExportOf(buildCtx.config, compilerCtx, foundSource, className) : void 0;
14413
+ if (reExport) return resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, foundSource, reExport.moduleSpecifier, reExport.localName, dependentClasses, typeChecker, ogModule, targetScriptTarget, barrelHopsRemaining - 1, originalModuleSpecifier, originalContainingFile);
14080
14414
  const err = buildWarn(buildCtx.diagnostics);
14081
14415
  err.messageText = `Unable to find "${className}" in the imported module "${moduleSpecifier}".
14082
14416
  Please import class / mixin-factory declarations directly and not via barrel files.`;
@@ -14084,21 +14418,61 @@ function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration,
14084
14418
  return;
14085
14419
  }
14086
14420
  let foundClassDeclaration = matchedStatement ? ts$1.isClassDeclaration(matchedStatement) ? matchedStatement : void 0 : void 0;
14087
- if (!foundClassDeclaration && matchedStatement) {
14421
+ let foundClassSource = foundSource;
14422
+ const findInJsEntry = () => {
14423
+ if (!isDtsFile(foundSource.fileName) || isLocalModule(originalModuleSpecifier)) return;
14424
+ const jsSource = resolveModuleJsEntry(buildCtx.config, compilerCtx, originalModuleSpecifier, originalContainingFile);
14425
+ return jsSource && findClassInJsModule(buildCtx.config, compilerCtx, jsSource, className);
14426
+ };
14427
+ if (foundClassDeclaration) {
14428
+ const foundInJs = findInJsEntry();
14429
+ if (foundInJs) {
14430
+ foundClassDeclaration = foundInJs.classNode;
14431
+ foundClassSource = foundInJs.sourceFile;
14432
+ }
14433
+ } else if (matchedStatement) {
14088
14434
  foundClassDeclaration = findClassWalk(matchedStatement);
14089
14435
  keepLooking = false;
14436
+ if (!foundClassDeclaration) {
14437
+ const foundInJs = findInJsEntry();
14438
+ if (foundInJs) {
14439
+ foundClassDeclaration = foundInJs.classNode;
14440
+ foundClassSource = foundInJs.sourceFile;
14441
+ }
14442
+ }
14090
14443
  if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, className, classDeclaration);
14091
14444
  }
14092
14445
  if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {
14093
14446
  dependentClasses.push({
14094
14447
  classNode: foundClassDeclaration,
14095
- sourceFile: foundSource,
14096
- fileName: foundFile.resolvedModule.resolvedFileName
14448
+ sourceFile: foundClassSource,
14449
+ fileName: foundClassSource.fileName
14097
14450
  });
14098
14451
  if (keepLooking) buildExtendsTree(compilerCtx, foundClassDeclaration, dependentClasses, typeChecker, buildCtx, ogModule);
14099
14452
  }
14100
14453
  return foundClassDeclaration;
14101
14454
  }
14455
+ /**
14456
+ * Finds the first `export * from './x'` in `barrel` whose target declares `className` directly.
14457
+ * @param config the current Stencil validated config
14458
+ * @param compilerCtx the current compiler context
14459
+ * @param barrel the source file to scan
14460
+ * @param className the declaration name to look for
14461
+ * @returns the re-export to follow, in `findReExport`'s shape, or `undefined`
14462
+ */
14463
+ function findStarReExportOf(config, compilerCtx, barrel, className) {
14464
+ for (const moduleSpecifier of findStarReExportSpecifiers(barrel)) {
14465
+ const resolved = tsResolveModuleName(config, compilerCtx, moduleSpecifier, barrel.fileName);
14466
+ const fileName = resolved?.resolvedModule?.resolvedFileName;
14467
+ if (!fileName) continue;
14468
+ const target = compilerCtx.moduleMap.get(fileName)?.staticSourceFile ?? (isJsFile(fileName) ? readJsSourceFile(config, fileName) : tsGetSourceFile(config, resolved));
14469
+ if (target && findStatementByName(target, className)) return {
14470
+ moduleSpecifier,
14471
+ localName: className
14472
+ };
14473
+ }
14474
+ }
14475
+ const isJsFile = (fileName) => /\.[cm]?js$/.test(fileName);
14102
14476
  function convertDtsToJs(declarationSourceFile, compilerCtx) {
14103
14477
  const jsPath = normalizePath(declarationSourceFile.replace(/\.d\.ts$/, ".js").replace("/types/", "/collection/"));
14104
14478
  return compilerCtx.moduleMap.get(jsPath)?.staticSourceFile;
@@ -14122,6 +14496,7 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
14122
14496
  const targetScriptTarget = (ogModule?.staticSourceFile)?.languageVersion ?? ts$1.ScriptTarget.ESNext;
14123
14497
  let classIdentifiers = [];
14124
14498
  let foundClassDeclaration;
14499
+ let foundClassName;
14125
14500
  let keepLooking = true;
14126
14501
  extendsClause.types.forEach((type) => {
14127
14502
  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 +14513,11 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
14138
14513
  declarations = [...source.statements];
14139
14514
  }
14140
14515
  foundClassDeclaration = declarations?.find(ts$1.isClassDeclaration);
14516
+ foundClassName = foundClassDeclaration?.name?.getText();
14141
14517
  if (!foundClassDeclaration) {
14142
14518
  const node = declarations?.[0];
14143
14519
  foundClassDeclaration = findClassWalk(node);
14520
+ foundClassName = foundClassDeclaration?.name?.getText() ?? factoryDeclaredName(node);
14144
14521
  if (!node) throw "revert to sad path";
14145
14522
  keepLooking = false;
14146
14523
  if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, extendee.getText(), classDeclaration);
@@ -14149,7 +14526,7 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
14149
14526
  const foundModule = compilerCtx.moduleMap.get(foundClassDeclaration.getSourceFile().fileName);
14150
14527
  if (foundModule) {
14151
14528
  const moduleSourceFile = foundModule.staticSourceFile;
14152
- const sourceClass = findClassWalk(moduleSourceFile, foundClassDeclaration.name?.getText());
14529
+ const sourceClass = findClassWalk(moduleSourceFile, foundClassName);
14153
14530
  if (sourceClass) {
14154
14531
  dependentClasses.push({
14155
14532
  classNode: sourceClass,
@@ -14170,20 +14547,24 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
14170
14547
  if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, classDeclaration);
14171
14548
  return;
14172
14549
  }
14173
- if (matchedStatement && ts$1.isClassDeclaration(matchedStatement)) foundClassDeclaration = matchedStatement;
14174
- else if (matchedStatement) {
14550
+ if (matchedStatement && ts$1.isClassDeclaration(matchedStatement)) {
14551
+ foundClassDeclaration = matchedStatement;
14552
+ foundClassName = foundClassDeclaration.name?.getText();
14553
+ } else if (matchedStatement) {
14175
14554
  foundClassDeclaration = findClassWalk(matchedStatement);
14555
+ foundClassName = foundClassDeclaration?.name?.getText() ?? extendee.getText();
14176
14556
  keepLooking = false;
14177
14557
  if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, extendee.getText(), classDeclaration);
14178
14558
  } else {
14179
14559
  foundClassDeclaration = findClassWalk(currentSource, extendee.getText());
14560
+ foundClassName = foundClassDeclaration?.name?.getText() ?? extendee.getText();
14180
14561
  keepLooking = false;
14181
14562
  }
14182
14563
  if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {
14183
14564
  const foundModule = compilerCtx.moduleMap.get(currentSource.fileName);
14184
14565
  if (foundModule?.staticSourceFile) {
14185
14566
  const transformedSource = foundModule.staticSourceFile;
14186
- const transformedClass = findClassWalk(transformedSource, foundClassDeclaration.name?.getText());
14567
+ const transformedClass = findClassWalk(transformedSource, foundClassName);
14187
14568
  if (transformedClass) {
14188
14569
  dependentClasses.push({
14189
14570
  classNode: transformedClass,
@@ -14468,7 +14849,7 @@ function convertInMemorySourceDecorators(sourceFile, config) {
14468
14849
  const program = ts$1.createProgram([sourceFile.fileName], compilerOptions, compilerHost);
14469
14850
  const typeChecker = program.getTypeChecker();
14470
14851
  const ownSourceFile = program.getSourceFile(sourceFile.fileName) ?? sourceFile;
14471
- const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program)]);
14852
+ const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program, true)]);
14472
14853
  const printed = ts$1.createPrinter({ removeComments: false }).printFile(result.transformed[0]);
14473
14854
  const scriptKind = sourceFile.fileName.endsWith(".tsx") || sourceFile.fileName.endsWith(".ts") ? ts$1.ScriptKind.TSX : ts$1.ScriptKind.JS;
14474
14855
  return ts$1.createSourceFile(sourceFile.fileName, printed, sourceFile.languageVersion, true, scriptKind);
@@ -14493,19 +14874,6 @@ function getExtendsClassNames(node) {
14493
14874
  if (ts$1.isCallExpression(expr) && expr.expression.getText() === "Mixin") return expr.arguments.filter(ts$1.isIdentifier).map((id) => id.text);
14494
14875
  return [];
14495
14876
  }
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
14877
  /**
14510
14878
  * A single-file mini-program (see `convertInMemorySourceDecorators`) can
14511
14879
  * never load an imported module's own `SourceFile`, so a type that's
@@ -14529,7 +14897,7 @@ function reclassifyGlobalTypeReferences(members, declaringSf, declaringPath, res
14529
14897
  if (!references) return;
14530
14898
  Object.entries(references).forEach(([typeName, reference]) => {
14531
14899
  if (reference.location !== "global") return;
14532
- const specifier = findImportSpecifier(declaringSf, typeName);
14900
+ const specifier = findImportOrigin(declaringSf, typeName)?.moduleSpecifier;
14533
14901
  if (!specifier) return;
14534
14902
  const resolved = resolveImport(specifier, declaringPath);
14535
14903
  reference.location = "import";
@@ -14541,7 +14909,7 @@ function reclassifyGlobalTypeReferences(members, declaringSf, declaringPath, res
14541
14909
  }
14542
14910
  /**
14543
14911
  * 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
14912
+ * re-export (barrel file, named or `export *`) via `resolveImport` - matching `compiler-ctx-merge.ts`'s equivalent
14545
14913
  * one-hop fallback (see `findReExport` in `shared.ts` for why it's capped at one hop).
14546
14914
  *
14547
14915
  * @param sf the source file to search
@@ -14552,26 +14920,31 @@ function reclassifyGlobalTypeReferences(members, declaringSf, declaringPath, res
14552
14920
  * differ from `sf`/`path` if resolved through a re-export), or `undefined`
14553
14921
  */
14554
14922
  function findDeclarationOrReExport(sf, path, name, resolveImport) {
14555
- const direct = sf.statements.find(matchesNamedDeclaration(name));
14923
+ const direct = findStatementByName(sf, name);
14556
14924
  if (direct) return {
14557
14925
  statement: direct,
14558
14926
  sourceFile: sf,
14559
14927
  path
14560
14928
  };
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
14929
+ const findIn = (moduleSpecifier, localName) => {
14930
+ const resolved = resolveImport(moduleSpecifier, path);
14931
+ if (!resolved) return void 0;
14932
+ const { code, path: resolvedPath } = resolved;
14933
+ const isTs = resolvedPath.endsWith(".tsx") || resolvedPath.endsWith(".ts");
14934
+ const reExportSf = ts$1.createSourceFile(resolvedPath, code, ts$1.ScriptTarget.ESNext, true, isTs ? ts$1.ScriptKind.TSX : ts$1.ScriptKind.JS);
14935
+ const statement = findStatementByName(reExportSf, localName);
14936
+ return statement && {
14937
+ statement,
14938
+ sourceFile: reExportSf,
14939
+ path: resolvedPath
14940
+ };
14574
14941
  };
14942
+ const reExport = findReExport(sf, name);
14943
+ if (reExport) return findIn(reExport.moduleSpecifier, reExport.localName);
14944
+ for (const moduleSpecifier of findStarReExportSpecifiers(sf)) {
14945
+ const found = findIn(moduleSpecifier, name);
14946
+ if (found) return found;
14947
+ }
14575
14948
  }
14576
14949
  /**
14577
14950
  * Recursively resolves a class's `extends` heritage into a flat, deduplicated
@@ -14602,7 +14975,7 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
14602
14975
  let foundSf = sf;
14603
14976
  let foundPath = path;
14604
14977
  let keepLooking = true;
14605
- const sameFileStatement = sf.statements.find(matchesNamedDeclaration(parentName));
14978
+ const sameFileStatement = findStatementByName(sf, parentName);
14606
14979
  if (sameFileStatement) {
14607
14980
  if (ts$1.isClassDeclaration(sameFileStatement)) foundClass = sameFileStatement;
14608
14981
  else {
@@ -14611,7 +14984,7 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
14611
14984
  if (!foundClass) warnMixinFactoryClassNotFound(buildCtx, parentName, rootClassDeclaration);
14612
14985
  }
14613
14986
  } else {
14614
- const specifier = findImportSpecifier(sf, parentName);
14987
+ const specifier = findImportOrigin(sf, parentName)?.moduleSpecifier;
14615
14988
  if (!specifier) continue;
14616
14989
  const resolved = resolveImport(specifier, path);
14617
14990
  if (!resolved) continue;
@@ -14643,7 +15016,8 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
14643
15016
  ancestors.push({
14644
15017
  classNode: foundClass,
14645
15018
  sourceFile: foundSf,
14646
- path: foundPath
15019
+ path: foundPath,
15020
+ factoryName: parentName
14647
15021
  });
14648
15022
  if (keepLooking) resolveAncestors(foundClass, foundSf, foundPath, resolveImport, visited, ancestors, rootClassDeclaration, buildCtx);
14649
15023
  }
@@ -14660,8 +15034,8 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
14660
15034
  * @returns the ancestor's metadata
14661
15035
  */
14662
15036
  function extractAncestorMeta(ancestor, cmpSourceFile, resolveImport, config) {
14663
- const { classNode, sourceFile: parentSf, path: resolvedPath } = ancestor;
14664
- const className = classNode.name?.text;
15037
+ const { classNode, sourceFile: parentSf, path: resolvedPath, factoryName } = ancestor;
15038
+ const className = classNode.name?.text ?? factoryName;
14665
15039
  const parentStaticMembers = classNode.members.filter(isStaticGetter);
14666
15040
  let resolvedClassNode = classNode;
14667
15041
  let resolvedStaticMembers = parentStaticMembers;
@@ -14671,6 +15045,8 @@ function extractAncestorMeta(ancestor, cmpSourceFile, resolveImport, config) {
14671
15045
  "events",
14672
15046
  "listeners",
14673
15047
  "watchers",
15048
+ "serializers",
15049
+ "deserializers",
14674
15050
  "methods"
14675
15051
  ].includes(m.name.text));
14676
15052
  if (!hasUsableStaticMembers && className) {
@@ -14690,6 +15066,8 @@ function extractAncestorMeta(ancestor, cmpSourceFile, resolveImport, config) {
14690
15066
  events: reanchorInheritedTypeReferences(reclassifyGlobalTypeReferences(parseStaticEvents(resolvedStaticMembers) ?? [], parentSf, resolvedPath, resolveImport), resolvedPath, cmpSourceFile.fileName),
14691
15067
  listeners: parseStaticListeners(resolvedStaticMembers) ?? [],
14692
15068
  watchers: parseStaticWatchers(resolvedStaticMembers) ?? [],
15069
+ serializers: parseStaticSerializers(resolvedStaticMembers, "serializers") ?? [],
15070
+ deserializers: parseStaticSerializers(resolvedStaticMembers, "deserializers") ?? [],
14693
15071
  methodNames: resolvedClassNode.members.filter(ts$1.isMethodDeclaration).map((m) => ts$1.isIdentifier(m.name) ? m.name.text : "").filter(Boolean)
14694
15072
  };
14695
15073
  }
@@ -14719,8 +15097,8 @@ function mergeExtendedClassMetaWithResolveImport(cmpNode, staticMembers, sourceF
14719
15097
  let events = parseStaticEvents(staticMembers);
14720
15098
  let watchers = parseStaticWatchers(staticMembers);
14721
15099
  let classMethods = cmpNode.members.filter(ts$1.isMethodDeclaration).map((m) => ts$1.isIdentifier(m.name) ? m.name.text : "").filter(Boolean);
14722
- const serializers = [];
14723
- const deserializers = [];
15100
+ let serializers = parseStaticSerializers(staticMembers, "serializers");
15101
+ let deserializers = parseStaticSerializers(staticMembers, "deserializers");
14724
15102
  const ancestors = [];
14725
15103
  resolveAncestors(cmpNode, sourceFile, sourceFile.fileName, resolveImport, /* @__PURE__ */ new Set(), ancestors, cmpNode, buildCtx);
14726
15104
  ancestors.forEach((ancestor) => {
@@ -14734,6 +15112,8 @@ function mergeExtendedClassMetaWithResolveImport(cmpNode, staticMembers, sourceF
14734
15112
  events = [...deDupeMembers(parentMeta.events, events), ...events];
14735
15113
  listeners = [...deDupeMembers(parentMeta.listeners, listeners), ...listeners];
14736
15114
  watchers = [...deDupeMembers(parentMeta.watchers, watchers), ...watchers];
15115
+ serializers = [...deDupeMembers(parentMeta.serializers ?? [], serializers), ...serializers];
15116
+ deserializers = [...deDupeMembers(parentMeta.deserializers ?? [], deserializers), ...deserializers];
14737
15117
  classMethods = [...classMethods, ...parentMeta.methodNames];
14738
15118
  });
14739
15119
  return {
@@ -14753,7 +15133,6 @@ function mergeExtendedClassMetaWithResolveImport(cmpNode, staticMembers, sourceF
14753
15133
  //#region src/compiler/transformers/static-to-meta/class-methods.ts
14754
15134
  const parseClassMethods = (classMethods, cmpMeta) => {
14755
15135
  if (!classMethods?.length) return;
14756
- const hasHostData = classMethods.includes("hostData");
14757
15136
  cmpMeta.hasAttributeChangedCallbackFn = classMethods.includes("attributeChangedCallback");
14758
15137
  cmpMeta.hasConnectedCallbackFn = classMethods.includes("connectedCallback");
14759
15138
  cmpMeta.hasDisconnectedCallbackFn = classMethods.includes("disconnectedCallback");
@@ -14765,8 +15144,7 @@ const parseClassMethods = (classMethods, cmpMeta) => {
14765
15144
  cmpMeta.hasComponentShouldUpdateFn = classMethods.includes("componentShouldUpdate");
14766
15145
  cmpMeta.hasComponentDidUpdateFn = classMethods.includes("componentDidUpdate");
14767
15146
  cmpMeta.hasLifecycle = cmpMeta.hasComponentWillLoadFn || cmpMeta.hasComponentDidLoadFn || cmpMeta.hasComponentWillUpdateFn || cmpMeta.hasComponentDidUpdateFn;
14768
- cmpMeta.hasRenderFn = classMethods.includes("render") || hasHostData;
14769
- cmpMeta.hasVdomRender = cmpMeta.hasVdomRender || hasHostData;
15147
+ cmpMeta.hasRenderFn = classMethods.includes("render");
14770
15148
  };
14771
15149
  //#endregion
14772
15150
  //#region src/compiler/transformers/static-to-meta/element-ref.ts
@@ -15146,13 +15524,13 @@ const parseStaticComponentMeta = (compilerCtx, typeChecker, cmpNode, moduleFile,
15146
15524
  hasPatchClone: false,
15147
15525
  hasPatchInsert: false
15148
15526
  };
15149
- const visitComponentChildNode = (node, ctx) => {
15150
- validateComponentMembers(node, ctx);
15151
- if (ts$1.isCallExpression(node)) parseCallExpression(cmp, node, typeChecker);
15527
+ if (!isCollectionDependency) validateComponentMembers(cmpNode, buildCtx);
15528
+ const visitComponentChildNode = (node) => {
15529
+ if (ts$1.isCallExpression(node)) parseCallExpression(cmp, node, typeChecker, moduleFile);
15152
15530
  else if (ts$1.isStringLiteral(node)) parseStringLiteral(cmp, node);
15153
- node.forEachChild((child) => visitComponentChildNode(child, ctx));
15531
+ node.forEachChild(visitComponentChildNode);
15154
15532
  };
15155
- visitComponentChildNode(cmpNode, buildCtx);
15533
+ visitComponentChildNode(cmpNode);
15156
15534
  parseClassMethods(classMethods, cmp);
15157
15535
  cmp.hasModernPropertyDecls = detectModernPropDeclarations(cmpNode) || doesExtend;
15158
15536
  cmp.htmlAttrNames = unique(cmp.htmlAttrNames);
@@ -15170,31 +15548,32 @@ const parseStaticComponentMeta = (compilerCtx, typeChecker, cmpNode, moduleFile,
15170
15548
  return cmpNode;
15171
15549
  };
15172
15550
  /**
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
15551
+ * Warn about members a Stencil component class should not define.
15552
+ * @param cmpNode the component class declaration
15553
+ * @param buildCtx the current build context, used to surface diagnostics
15177
15554
  */
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);
15555
+ const validateComponentMembers = (cmpNode, buildCtx) => {
15556
+ const componentName = cmpNode.name?.text ?? "";
15557
+ for (const member of cmpNode.members) {
15558
+ if (!member.name || !ts$1.isIdentifier(member.name)) continue;
15559
+ const memberName = member.name.text;
15560
+ /**
15561
+ * the component has a getter called "shadowRoot"
15562
+ */
15563
+ if (ts$1.isGetAccessorDeclaration(member) && BLACKLISTED_COMPONENT_METHODS.includes(memberName)) {
15564
+ const err = buildWarn(buildCtx.diagnostics);
15565
+ 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.`;
15566
+ augmentDiagnosticWithNode(err, ts$1.getOriginalNode(member));
15567
+ }
15568
+ /**
15569
+ * the component defines a "componentShouldUpdate" method with more than one parameter,
15570
+ * which was the pre-v5 per-prop signature "(newVal, oldVal, propName)"
15571
+ */
15572
+ if (ts$1.isMethodDeclaration(member) && memberName === "componentShouldUpdate" && member.parameters.length > 1) {
15573
+ const err = buildWarn(buildCtx.diagnostics);
15574
+ 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.`;
15575
+ augmentDiagnosticWithNode(err, ts$1.getOriginalNode(member));
15576
+ }
15198
15577
  }
15199
15578
  };
15200
15579
  const parseVirtualProps = (docs) => {
@@ -15368,6 +15747,9 @@ const updateModule = (config, compilerCtx, buildCtx, tsSourceFile, sourceFileTex
15368
15747
  } else if (ts$1.isImportDeclaration(node)) {
15369
15748
  parseModuleImport(config, compilerCtx, buildCtx, moduleFile, srcDirPath, node, true);
15370
15749
  return;
15750
+ } else if (ts$1.isExportDeclaration(node)) {
15751
+ parseModuleReExport(moduleFile, srcDirPath, node);
15752
+ return;
15371
15753
  } else if (ts$1.isCallExpression(node)) parseCallExpression(moduleFile, node, typeChecker);
15372
15754
  else if (ts$1.isStringLiteral(node)) parseStringLiteral(moduleFile, node);
15373
15755
  else if (ts$1.isVariableStatement(node)) node.declarationList.declarations.forEach((declaration) => {
@@ -15538,18 +15920,32 @@ const addExternalImport = (config, compilerCtx, buildCtx, moduleFile, containing
15538
15920
  //#region src/compiler/transformers/static-to-meta/import.ts
15539
15921
  const parseModuleImport = (config, compilerCtx, buildCtx, moduleFile, dirPath, importNode, resolveCollections) => {
15540
15922
  if (importNode.moduleSpecifier && ts$1.isStringLiteral(importNode.moduleSpecifier)) {
15541
- let importPath = importNode.moduleSpecifier.text;
15923
+ const importPath = importNode.moduleSpecifier.text;
15542
15924
  if (!moduleFile.originalImports.includes(importPath)) moduleFile.originalImports.push(importPath);
15543
15925
  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);
15926
+ const localPath = resolveLocalImportPath(dirPath, importPath);
15927
+ if (localPath) moduleFile.localImports.push(localPath);
15928
+ else addExternalImport(config, compilerCtx, buildCtx, moduleFile, moduleFile.sourceFilePath, importPath, resolveCollections, !importNode.importClause);
15551
15929
  }
15552
15930
  };
15931
+ /**
15932
+ * Record a local `export … from './x'` re-export as a local import, so build conditionals
15933
+ * propagate through barrel files. Bare-specifier re-exports are left alone.
15934
+ *
15935
+ * @param moduleFile the module containing the re-export
15936
+ * @param dirPath the module's (normalized) directory
15937
+ * @param exportNode the export declaration
15938
+ */
15939
+ const parseModuleReExport = (moduleFile, dirPath, exportNode) => {
15940
+ if (exportNode.moduleSpecifier && ts$1.isStringLiteral(exportNode.moduleSpecifier)) {
15941
+ const localPath = resolveLocalImportPath(dirPath, exportNode.moduleSpecifier.text);
15942
+ if (localPath && !moduleFile.localImports.includes(localPath)) moduleFile.localImports.push(localPath);
15943
+ }
15944
+ };
15945
+ const resolveLocalImportPath = (dirPath, importPath) => {
15946
+ if (isAbsolute(importPath)) return normalizePath(importPath);
15947
+ if (importPath.startsWith(".")) return normalizePath(join$1(dirPath, importPath));
15948
+ };
15553
15949
  //#endregion
15554
15950
  //#region src/compiler/transformers/static-to-meta/visitor.ts
15555
15951
  const convertStaticToMeta = (config, compilerCtx, buildCtx, typeChecker, collection, transformOpts) => {
@@ -15559,6 +15955,7 @@ const convertStaticToMeta = (config, compilerCtx, buildCtx, typeChecker, collect
15559
15955
  const visitNode = (node) => {
15560
15956
  if (ts$1.isClassDeclaration(node)) return parseStaticComponentMeta(compilerCtx, typeChecker, node, moduleFile, buildCtx, transformOpts);
15561
15957
  else if (ts$1.isImportDeclaration(node)) parseModuleImport(config, compilerCtx, buildCtx, moduleFile, dirPath, node, !transformOpts.isolatedModules);
15958
+ else if (ts$1.isExportDeclaration(node)) parseModuleReExport(moduleFile, dirPath, node);
15562
15959
  else if (ts$1.isCallExpression(node)) parseCallExpression(moduleFile, node, typeChecker);
15563
15960
  else if (ts$1.isStringLiteral(node)) parseStringLiteral(moduleFile, node);
15564
15961
  return ts$1.visitEachChild(node, visitNode, transformCtx);
@@ -15665,6 +16062,7 @@ const transpileModule = (config, input, transformOpts) => {
15665
16062
  ...config,
15666
16063
  logger: createNodeLogger()
15667
16064
  };
16065
+ resetDeprecatedApiWarning();
15668
16066
  const compilerCtx = new CompilerContext();
15669
16067
  const buildCtx = new BuildContext(config, compilerCtx);
15670
16068
  const tsCompilerOptions = { ...config.tsCompilerOptions };
@@ -15842,6 +16240,7 @@ const transpileCss = async (transformInput, results) => {
15842
16240
  results.map = cssResults.map;
15843
16241
  results.imports = cssResults.imports.map((p) => ({ path: p.importPath }));
15844
16242
  results.diagnostics.push(...cssResults.diagnostics);
16243
+ if (transformInput.docs) results.styleDocs = cssResults.styleDocs;
15845
16244
  };
15846
16245
  const transpileCssSync = (transformInput, results) => {
15847
16246
  const cssResults = transformCssToEsmSync(transformInput);
@@ -15849,6 +16248,7 @@ const transpileCssSync = (transformInput, results) => {
15849
16248
  results.map = cssResults.map;
15850
16249
  results.imports = cssResults.imports.map((p) => ({ path: p.importPath }));
15851
16250
  results.diagnostics.push(...cssResults.diagnostics);
16251
+ if (transformInput.docs) results.styleDocs = cssResults.styleDocs;
15852
16252
  };
15853
16253
  const transpileJson = (results) => {
15854
16254
  results.code = dataToEsm(JSON.parse(results.code), {
@@ -16279,7 +16679,7 @@ const FORM_ASSOCIATED_ATTRIBUTES = [
16279
16679
  * @param cmp the metadata for the component that a type definition string is generated for
16280
16680
  * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions
16281
16681
  * @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
16682
+ * @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
16683
  * @returns the generated types string alongside additional metadata
16284
16684
  */
16285
16685
  const generateComponentTypes = (cmp, typeImportData, areTypesInternal, signalBacking = false) => {
@@ -16296,8 +16696,12 @@ const generateComponentTypes = (cmp, typeImportData, areTypesInternal, signalBac
16296
16696
  const isDep = cmp.isCollectionDependency;
16297
16697
  const propNames = new Set(propAttributes.map((p) => p.name));
16298
16698
  const formAssociatedAttrs = cmp.formAssociated ? FORM_ASSOCIATED_ATTRIBUTES.filter((attr) => !propNames.has(attr.name)) : [];
16699
+ const jsxPropAttributes = signalBacking ? propAttributes.map((attr) => ({
16700
+ ...attr,
16701
+ type: `${attr.type} | ReadonlySignal<${attr.type}>`
16702
+ })) : propAttributes;
16299
16703
  const jsxAttributes = attributesToMultiLineString([
16300
- ...propAttributes,
16704
+ ...jsxPropAttributes,
16301
16705
  ...eventAttributes,
16302
16706
  ...formAssociatedAttrs
16303
16707
  ], true, areTypesInternal);