@stencil/core 5.0.0-beta.2 → 5.0.0-beta.20

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 (35) hide show
  1. package/dist/app-data/index.d.ts +1 -1
  2. package/dist/{client-BRu0GtRn.mjs → client-CVXS3JZ-.mjs} +105 -60
  3. package/dist/compiler/browser.d.ts +110 -79
  4. package/dist/compiler/browser.js +542 -241
  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-C8yf59oh.mjs → compiler-CUsOl_Kw.mjs} +4428 -2709
  9. package/dist/declarations/stencil-public-compiler.d.ts +144 -120
  10. package/dist/declarations/stencil-public-docs.d.ts +23 -0
  11. package/dist/declarations/stencil-public-runtime.d.ts +60 -58
  12. package/dist/{index-BopBfjPu.d.mts → index-B9-Byy8z.d.mts} +142 -118
  13. package/dist/{index-BXAcVN2j.d.ts → index-BHciXst1.d.ts} +57 -55
  14. package/dist/{index-DmHmu3y0.d.mts → index-Dz1G9pWZ.d.mts} +2 -2
  15. package/dist/index.d.mts +3 -0
  16. package/dist/index.mjs +1 -1
  17. package/dist/jsx-runtime.mjs +1 -1
  18. package/dist/{node-75gQKkFz.mjs → node-Bz2SOK7_.mjs} +6 -35
  19. package/dist/runtime/client/lazy.js +228 -180
  20. package/dist/runtime/client/runtime.d.ts +67 -66
  21. package/dist/runtime/client/runtime.js +228 -180
  22. package/dist/runtime/index.d.ts +4 -5
  23. package/dist/runtime/index.js +226 -178
  24. package/dist/runtime/server/index.d.mts +11 -11
  25. package/dist/runtime/server/index.mjs +287 -220
  26. package/dist/runtime/server/runner.d.mts +4 -4
  27. package/dist/runtime/server/runner.mjs +82 -54
  28. package/dist/signals/index.d.ts +11 -2
  29. package/dist/signals/index.js +11 -1
  30. package/dist/sys/node/index.d.mts +1 -1
  31. package/dist/sys/node/index.mjs +1 -1
  32. package/dist/sys/node/worker.mjs +2 -2
  33. package/dist/testing/index.d.mts +129 -112
  34. package/dist/testing/index.mjs +244 -193
  35. package/package.json +8 -4
@@ -1501,7 +1501,7 @@ const scopeSelector = (selector, scopeSelectorText, hostSelector, slotSelector)
1501
1501
  else return shallowPart.trim();
1502
1502
  }).join(", ");
1503
1503
  };
1504
- const isScopableAtRule = (selector) => selector.startsWith("@media") || selector.startsWith("@supports") || selector.startsWith("@page") || selector.startsWith("@document") || selector.startsWith("@layer");
1504
+ const isScopableAtRule = (selector) => selector.startsWith("@media") || selector.startsWith("@supports") || selector.startsWith("@page") || selector.startsWith("@document") || selector.startsWith("@layer") || selector.startsWith("@container");
1505
1505
  const scopeSelectors = (cssText, scopeSelectorText, hostSelector, slotSelector, commentOriginalSelector) => {
1506
1506
  return processRules(cssText, (rule) => {
1507
1507
  let selector = rule.selector;
@@ -1693,6 +1693,18 @@ const createJsVarName = (fileName) => {
1693
1693
  }
1694
1694
  return fileName;
1695
1695
  };
1696
+ /**
1697
+ * Create a function that lowercases the first string parameter before passing it to the provided function
1698
+ * @param fn the function to pass the lowercased path to
1699
+ * @returns the result of the provided function
1700
+ */
1701
+ const lowerPathParam = (fn) => (p) => fn(p.toLowerCase());
1702
+ /**
1703
+ * Determine if a stringified file path is a TypeScript declaration file based on the extension at the end of the path.
1704
+ * @param p the path to evaluate
1705
+ * @returns `true` if the path ends in `.d.ts` (case-sensitive), `false` otherwise.
1706
+ */
1707
+ const isDtsFile = lowerPathParam((p) => p.endsWith(".d.ts") || p.endsWith(".d.mts") || p.endsWith(".d.cts"));
1696
1708
  function getTextDocs(docs) {
1697
1709
  if (docs == null) return "";
1698
1710
  return [escapeWithPattern(docs.text.replace(LINE_BREAK_REGEX, " "), /\*\//, "*\\/", true), ...docs.tags.filter((tag) => tag.name !== "internal").map((tag) => {
@@ -1832,7 +1844,7 @@ const validateComponentTag = (tag) => {
1832
1844
  };
1833
1845
  //#endregion
1834
1846
  //#region src/version.ts
1835
- const version = "5.0.0-beta.2";
1847
+ const version = "5.0.0-beta.20";
1836
1848
  //#endregion
1837
1849
  //#region src/compiler/events.ts
1838
1850
  const buildEvents = () => {
@@ -1895,6 +1907,7 @@ const resolve = (id, _opts, cb) => {
1895
1907
  };
1896
1908
  //#endregion
1897
1909
  //#region src/compiler/sys/resolve/resolve-utils.ts
1910
+ const isLocalModule = (p) => p.startsWith(".") || p.startsWith("/");
1898
1911
  const isNodeModulePath = (p) => normalizePath(p).split("/").includes("node_modules");
1899
1912
  const getModuleId = (orgImport) => {
1900
1913
  if (orgImport.startsWith("~")) orgImport = orgImport.substring(1);
@@ -2345,15 +2358,6 @@ const createSystem = (c) => {
2345
2358
  }
2346
2359
  return results;
2347
2360
  };
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
2361
  const writeFile = async (p, data) => writeFileSync(p, data);
2358
2362
  const tmpDirSync = () => "/.tmp";
2359
2363
  const tick = Promise.resolve();
@@ -2364,6 +2368,7 @@ const createSystem = (c) => {
2364
2368
  if (typeof hashLength === "number") hashHex = hashHex.slice(0, hashLength);
2365
2369
  return hashHex;
2366
2370
  };
2371
+ const generateFileHash = async (filePath, hashLength) => generateContentHash(readFileSync(filePath), hashLength);
2367
2372
  const copy = async (copyTasks, srcDir) => {
2368
2373
  const results = {
2369
2374
  diagnostics: [],
@@ -2373,9 +2378,6 @@ const createSystem = (c) => {
2373
2378
  logger.info("todo, copy task", copyTasks.length, srcDir);
2374
2379
  return results;
2375
2380
  };
2376
- const getEnvironmentVar = (key) => {
2377
- return process$1?.env[key];
2378
- };
2379
2381
  const getLocalModulePath = (opts) => join$1(opts.rootDir, "node_modules", opts.moduleId, opts.path);
2380
2382
  const getRemoteModuleUrl = (opts) => {
2381
2383
  const npmBaseUrl = "https://cdn.jsdelivr.net/npm/";
@@ -2391,13 +2393,14 @@ const createSystem = (c) => {
2391
2393
  access,
2392
2394
  accessSync,
2393
2395
  addDestroy,
2396
+ checkVersion: async () => noop,
2394
2397
  copyFile,
2395
2398
  createDir,
2396
2399
  createDirSync,
2397
2400
  homeDir,
2398
2401
  isTTY,
2399
- getEnvironmentVar,
2400
2402
  destroy,
2403
+ dynamicImport: (p) => import(p),
2401
2404
  encodeToBase64,
2402
2405
  exit: async (exitCode) => logger.warn(`exit ${exitCode}`),
2403
2406
  getCurrentDirectory,
@@ -2408,6 +2411,7 @@ const createSystem = (c) => {
2408
2411
  isSymbolicLink,
2409
2412
  nextTick,
2410
2413
  normalizePath: normalize,
2414
+ onProcessInterrupt: noop,
2411
2415
  platformPath: path,
2412
2416
  readDir,
2413
2417
  readDirSync,
@@ -2417,7 +2421,6 @@ const createSystem = (c) => {
2417
2421
  realpathSync,
2418
2422
  removeDestroy,
2419
2423
  rename,
2420
- fetch,
2421
2424
  resolvePath,
2422
2425
  removeDir,
2423
2426
  removeDirSync,
@@ -2432,6 +2435,7 @@ const createSystem = (c) => {
2432
2435
  writeFile,
2433
2436
  writeFileSync,
2434
2437
  generateContentHash,
2438
+ generateFileHash,
2435
2439
  createWorkerController: null,
2436
2440
  details: {
2437
2441
  cpuModel: "",
@@ -2633,7 +2637,8 @@ const getTranspileCssConfig = (compileOpts, importData, results) => {
2633
2637
  minify: false,
2634
2638
  autoprefixer: false,
2635
2639
  module: compileOpts.module,
2636
- styleImportData: compileOpts.styleImportData
2640
+ styleImportData: compileOpts.styleImportData,
2641
+ docs: compileOpts.docs === true
2637
2642
  };
2638
2643
  };
2639
2644
  const getTranspileConfigOpt = (value, validValues, defaultValue) => {
@@ -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,137 @@ 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
+ //#endregion
3873
3925
  //#region src/compiler/docs/style-docs.ts
3874
3926
  /**
3875
3927
  * Parse CSS docstrings that Stencil supports, as documented here:
3876
3928
  * https://stenciljs.com/docs/docs-json#css-variables
3877
3929
  *
3878
- * Docstrings found in the supplied style text will be added to the
3879
- * `styleDocs` param
3930
+ * Docstrings found in the supplied style text will be added to the `styleDocs` param, via three
3931
+ * mechanisms, in order of precedence (an earlier mechanism always wins over a later one for the
3932
+ * same custom property name):
3933
+ * 1. An explicit `@prop`/`@cssprop`/`@cssproperty` annotation in a block comment, anywhere in the file.
3934
+ * 2. A doc-commented `--foo: value;` declaration inside the component's "root" rule - `:host`
3935
+ * for `shadow`/`scoped` encapsulation, or the component's own tag selector for `none`.
3936
+ * 3. A native `@property --foo { ... }` at-rule, with the `syntax`/`initial-value` descriptors
3937
+ * surfaced as `syntax`/`default`. Not scoped - `@property` is a global registration.
3880
3938
  *
3881
3939
  * @param styleDocs the array to hold formatted CSS docstrings
3882
3940
  * @param styleText the CSS text we're working with
3883
3941
  * @param mode a mode associated with the parsed style, if applicable (e.g. this is not applicable for global styles)
3942
+ * @param tag the component's tag name, used to scope auto-detection for `none` encapsulation
3943
+ * @param encapsulation the component's encapsulation, used to pick the "root" scope for auto-detection
3884
3944
  */
3885
- function parseStyleDocs(styleDocs, styleText, mode) {
3945
+ function parseStyleDocs(styleDocs, styleText, mode, tag, encapsulation) {
3886
3946
  if (typeof styleText !== "string") return;
3887
- let match = styleText.match(CSS_DOC_START);
3947
+ let remainingText = styleText;
3948
+ let match = remainingText.match(CSS_DOC_START);
3888
3949
  while (match !== null) {
3889
- styleText = styleText.substring(match.index + match[0].length);
3890
- const endIndex = styleText.indexOf(CSS_DOC_END);
3950
+ remainingText = remainingText.substring(match.index + match[0].length);
3951
+ const endIndex = remainingText.indexOf(CSS_DOC_END);
3891
3952
  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);
3953
+ parseCssComment(styleDocs, remainingText.substring(0, endIndex), mode);
3954
+ remainingText = remainingText.substring(endIndex + CSS_DOC_END.length);
3955
+ match = remainingText.match(CSS_DOC_START);
3956
+ }
3957
+ if (styleText.includes("--")) parseScopedAndNativeStyleDocs(styleDocs, styleText, mode, tag, encapsulation);
3958
+ }
3959
+ /**
3960
+ * Auto-detect doc-commented custom-property declarations within the component's "root" rule,
3961
+ * and native `@property` at-rule registrations, merging them into `styleDocs`. Mirrors the
3962
+ * equivalent detection for CSS-only components in `css-components/parse-css-component.ts`.
3963
+ *
3964
+ * @param styleDocs the array to hold formatted CSS docstrings - also consulted so an explicit
3965
+ * `@prop`/`@cssprop` annotation always wins over an auto-detected entry for the same name
3966
+ * @param styleText the CSS text we're working with
3967
+ * @param mode a mode associated with the parsed style, if applicable
3968
+ * @param tag the component's tag name
3969
+ * @param encapsulation the component's encapsulation
3970
+ */
3971
+ function parseScopedAndNativeStyleDocs(styleDocs, styleText, mode, tag, encapsulation) {
3972
+ let root;
3973
+ try {
3974
+ root = postcss().process(styleText, { from: void 0 }).root;
3975
+ } catch {
3976
+ return;
3895
3977
  }
3978
+ const hasName = (name) => styleDocs.some((styleDoc) => styleDoc.name === name);
3979
+ const rootSelector = encapsulation === "shadow" || encapsulation === "scoped" ? ":host" : tag;
3980
+ if (rootSelector) root.walkRules((rule) => {
3981
+ if (!rule.selectors.some((selector) => selector.trim() === rootSelector)) return;
3982
+ const children = rule.nodes;
3983
+ for (let i = 0; i < children.length; i++) {
3984
+ const child = children[i];
3985
+ if (child.type !== "decl" || !child.prop.startsWith("--") || hasName(child.prop)) continue;
3986
+ const prev = children[i - 1];
3987
+ if (!prev || prev.type !== "comment" || !isJsDocComment(prev.text)) continue;
3988
+ styleDocs.push({
3989
+ name: child.prop,
3990
+ docs: normalizeJsDocText(prev.text),
3991
+ annotation: "prop",
3992
+ mode
3993
+ });
3994
+ }
3995
+ });
3996
+ root.walkAtRules("property", (node) => {
3997
+ const propName = node.params.trim();
3998
+ if (!propName.startsWith("--") || hasName(propName)) return;
3999
+ const { syntax, initialValue } = parsePropertyAtRuleDescriptors(node);
4000
+ const prev = node.prev();
4001
+ const docs = prev && prev.type === "comment" && isJsDocComment(prev.text) ? normalizeJsDocText(prev.text) : "";
4002
+ styleDocs.push({
4003
+ name: propName,
4004
+ docs,
4005
+ annotation: "prop",
4006
+ mode,
4007
+ ...syntax && { syntax },
4008
+ ...initialValue && { default: initialValue }
4009
+ });
4010
+ });
3896
4011
  }
3897
4012
  /**
3898
4013
  * Parse a CSS comment string and insert it into the provided array of
@@ -3909,7 +4024,7 @@ function parseCssComment(styleDocs, comment, mode) {
3909
4024
  return line;
3910
4025
  }).join(" ").replace(/\t/g, " ").trim();
3911
4026
  while (comment.includes(" ")) comment = comment.replace(" ", " ");
3912
- comment.split(CSS_PROP_ANNOTATION).forEach((d) => {
4027
+ comment.split(CSS_PROP_ANNOTATION_RE).forEach((d) => {
3913
4028
  const cssDocument = d.trim();
3914
4029
  if (!cssDocument.startsWith(`--`)) return;
3915
4030
  const splt = cssDocument.split(`:`);
@@ -3932,9 +4047,11 @@ const CSS_DOC_START = /\/\*(\*|!)/;
3932
4047
  */
3933
4048
  const CSS_DOC_END = "*/";
3934
4049
  /**
3935
- * The `@prop` annotation we support within CSS docstrings
4050
+ * The `@prop` annotation we support within CSS docstrings. `@cssprop`/`@cssproperty` are also
4051
+ * recognized as synonyms (the more common names in other web-component-analyzer/docgen
4052
+ * ecosystems).
3936
4053
  */
3937
- const CSS_PROP_ANNOTATION = "@prop";
4054
+ const CSS_PROP_ANNOTATION_RE = /@(?:cssproperty|cssprop|prop)\b/;
3938
4055
  //#endregion
3939
4056
  //#region src/compiler/sys/browser-stubs/browserslist.ts
3940
4057
  const browserslist = (_query) => [];
@@ -4046,6 +4163,39 @@ const DEFAULT_BROWSER_TARGETS = [
4046
4163
  //#endregion
4047
4164
  //#region src/compiler/style/css-parser/parse-css.ts
4048
4165
  /**
4166
+ * Splits a selector list on top-level commas in a single pass: a comma only
4167
+ * splits when it's outside a quoted string and at paren depth 0, so commas in
4168
+ * `:is(:a,:has(:b))` or `[title="a,b"]` aren't treated as separators.
4169
+ * Backslash escapes (inside or outside a string) are skipped so they can't shift state,
4170
+ * so e.g. `[title="a\,b"]` is treated as a single selector.
4171
+ * @param selectors The selector list to split
4172
+ * @returns An array of selectors, with whitespace trimmed from each selector
4173
+ */
4174
+ const splitSelectorList = (selectors) => {
4175
+ const parts = [];
4176
+ let depth = 0;
4177
+ let quote = null;
4178
+ let start = 0;
4179
+ for (let i = 0; i < selectors.length; i++) {
4180
+ const ch = selectors[i];
4181
+ if (quote) {
4182
+ if (ch === "\\") i++;
4183
+ else if (ch === quote) quote = null;
4184
+ continue;
4185
+ }
4186
+ if (ch === "\"" || ch === "'") quote = ch;
4187
+ else if (ch === "\\") i++;
4188
+ else if (ch === "(") depth++;
4189
+ else if (ch === ")") depth = Math.max(0, depth - 1);
4190
+ else if (ch === "," && depth === 0) {
4191
+ parts.push(selectors.slice(start, i));
4192
+ start = i + 1;
4193
+ }
4194
+ }
4195
+ parts.push(selectors.slice(start));
4196
+ return parts.map((s) => s.trim());
4197
+ };
4198
+ /**
4049
4199
  * Parses CSS string input into an AST representation.
4050
4200
  * Used for minification, finding & resolving URLs and during SSR / prerendering, removing unused selectors.
4051
4201
  *
@@ -4170,11 +4320,8 @@ const parseCss = (css, filePath) => {
4170
4320
  const selector = () => {
4171
4321
  const m = match(/^([^{]+)/);
4172
4322
  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
- });
4323
+ const cleaned = trim(m[0]).replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*\/+/g, "");
4324
+ return splitSelectorList(cleaned);
4178
4325
  };
4179
4326
  const declaration = () => {
4180
4327
  const pos = position();
@@ -4772,12 +4919,10 @@ const optimizeCss = async (inputOpts) => {
4772
4919
  const CREATE_EVENT = "__stencil_createEvent";
4773
4920
  const DEFINE_CUSTOM_ELEMENT = "__stencil_defineCustomElement";
4774
4921
  const GET_ELEMENT = "__stencil_getElement";
4775
- const HOST = "__stencil_Host";
4776
4922
  const HTML_ELEMENT = "HTMLElement";
4777
4923
  const PROXY_CUSTOM_ELEMENT = "__stencil_proxyCustomElement";
4778
4924
  const REGISTER_INSTANCE = "__stencil_registerInstance";
4779
4925
  const REGISTER_HOST = "__stencil_registerHost";
4780
- const H = "__stencil_h";
4781
4926
  const TRANSFORM_TAG = "__stencil_transformTag";
4782
4927
  const GET_REGISTRY = "__stencil_getRegistry";
4783
4928
  const INJECT_SIDE_EFFECT_STYLE = "__stencil_injectSideEffectStyle";
@@ -4785,9 +4930,7 @@ const RUNTIME_APIS = {
4785
4930
  createEvent: `createEvent as ${CREATE_EVENT}`,
4786
4931
  defineCustomElement: `defineCustomElement as ${DEFINE_CUSTOM_ELEMENT}`,
4787
4932
  getElement: `getElement as ${GET_ELEMENT}`,
4788
- h: `h as ${H}`,
4789
4933
  legacyH: `h`,
4790
- Host: `Host as ${HOST}`,
4791
4934
  HTMLElement: HTML_ELEMENT,
4792
4935
  proxyCustomElement: `proxyCustomElement as ${PROXY_CUSTOM_ELEMENT}`,
4793
4936
  registerHost: `registerHost as ${REGISTER_HOST}`,
@@ -9186,9 +9329,9 @@ const serializeSymbol = (checker, symbol) => {
9186
9329
  };
9187
9330
  };
9188
9331
  /**
9189
- * Maps a TypeScript 4.3+ JSDocTagInfo to a flattened Stencil CompilerJsDocTagInfo.
9332
+ * Maps a TypeScript 4.3+ JSDocTagInfo to a flattened Stencil JsonDocsTag.
9190
9333
  * @param tags A readonly array of JSDocTagInfo objects.
9191
- * @returns An array of CompilerJsDocTagInfo objects.
9334
+ * @returns An array of JsonDocsTag objects.
9192
9335
  */
9193
9336
  const mapJSDocTagInfo = (tags) => {
9194
9337
  return tags.map((tag) => ({
@@ -9599,7 +9742,7 @@ const transformCssToEsmModule = (input) => {
9599
9742
  defaultVarName: createCssVarName(input.file, input.mode),
9600
9743
  styleDocs: []
9601
9744
  };
9602
- if (input.docs) parseStyleDocs(results.styleDocs, input.input, input.mode);
9745
+ if (input.docs) parseStyleDocs(results.styleDocs, input.input, input.mode, input.tag, input.encapsulation);
9603
9746
  try {
9604
9747
  const varNames = /* @__PURE__ */ new Set([results.defaultVarName]);
9605
9748
  if (isString$1(input.tag) && input.encapsulation === "scoped") {
@@ -9696,7 +9839,7 @@ const getCssToEsmImports = (varNames, cssText, filePath, modeName) => {
9696
9839
  isNodeModule: false
9697
9840
  };
9698
9841
  if (!isLocalCssImport(cssImportData.srcImportText)) continue;
9699
- else if (cssImportData.url === "stencil-globals" || cssImportData.url === "stencil-hydrate") continue;
9842
+ else if (cssImportData.url === "stencil-component-globals" || cssImportData.url === "stencil-hydrate" || cssImportData.url === "stencil-css-components") continue;
9700
9843
  else if (isCssNodeModule(cssImportData.url)) {
9701
9844
  cssImportData.filePath = cssImportData.url.substring(1);
9702
9845
  cssImportData.isNodeModule = true;
@@ -9911,6 +10054,7 @@ var BuildContext = class {
9911
10054
  completedTasks = [];
9912
10055
  compilerCtx;
9913
10056
  components = [];
10057
+ cssOnlyComponents = [];
9914
10058
  componentGraph = /* @__PURE__ */ new Map();
9915
10059
  config;
9916
10060
  data = {};
@@ -9952,6 +10096,7 @@ var BuildContext = class {
9952
10096
  styleBuildCount = 0;
9953
10097
  stylesPromise = null;
9954
10098
  stylesUpdated = [];
10099
+ globalStylesUpdated = [];
9955
10100
  timeSpan = null;
9956
10101
  timestamp;
9957
10102
  transpileBuildCount = 0;
@@ -10132,12 +10277,18 @@ var CompilerContext = class {
10132
10277
  */
10133
10278
  prevStylesMap = /* @__PURE__ */ new Map();
10134
10279
  globalStyleCache = /* @__PURE__ */ new Map();
10280
+ cssOnlyComponentsCache = /* @__PURE__ */ new Map();
10281
+ stencilCss;
10282
+ globalStyleVirtualImports = /* @__PURE__ */ new Map();
10135
10283
  styleModeNames = /* @__PURE__ */ new Set();
10136
10284
  worker = null;
10137
10285
  reset() {
10138
10286
  this.cache.clear();
10139
10287
  this.cssModuleImports.clear();
10140
10288
  this.globalStyleCache.clear();
10289
+ this.cssOnlyComponentsCache.clear();
10290
+ this.stencilCss = void 0;
10291
+ this.globalStyleVirtualImports.clear();
10141
10292
  this.collections.length = 0;
10142
10293
  this.compilerOptions = null;
10143
10294
  this.hasSuccessfulBuild = false;
@@ -10742,31 +10893,6 @@ const createIdentifierFromStyleIdentifier = (styleIdentifier, externalStyleIds)
10742
10893
  return ts$1.factory.createBinaryExpression(createIdentifierFromStyleIdentifier(styleIdentifier, [id]), ts$1.SyntaxKind.PlusToken, createIdentifierFromStyleIdentifier(styleIdentifier, externalStyleIds.slice(1)));
10743
10894
  };
10744
10895
  //#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
10896
  //#region src/compiler/transformers/reactive-handler-meta-transform.ts
10771
10897
  /**
10772
10898
  * Add a getter to a class for a static representation of the watchers
@@ -10848,7 +10974,6 @@ const updateLazyComponentMembers = (transformOpts, styleStatements, classNode, m
10848
10974
  addReactivePropHandlers(classMembers, cmp, "watchers");
10849
10975
  addReactivePropHandlers(classMembers, cmp, "serializers");
10850
10976
  addReactivePropHandlers(classMembers, cmp, "deserializers");
10851
- transformHostData(classMembers, moduleFile);
10852
10977
  if (transformOpts.style === "static") addStaticStylePropertyToClass(styleStatements, cmp, buildCtx);
10853
10978
  return classMembers;
10854
10979
  };
@@ -11296,7 +11421,6 @@ const updateNativeHostComponentMembers = (transformOpts, classNode, moduleFile,
11296
11421
  addReactivePropHandlers(classMembers, cmp, "deserializers");
11297
11422
  if (cmp.isPlain) addNativeComponentMeta(classMembers, cmp);
11298
11423
  if (transformOpts.style === "static") addNativeStaticStyle(classMembers, cmp, buildCtx);
11299
- transformHostData(classMembers, moduleFile);
11300
11424
  return classMembers;
11301
11425
  };
11302
11426
  //#endregion
@@ -11499,110 +11623,6 @@ const isDecoratorNamed = (propName) => {
11499
11623
  };
11500
11624
  };
11501
11625
  //#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
11626
  //#region src/compiler/transformers/decorators-to-static/style-to-static.ts
11607
11627
  const styleToStatic = (newMembers, componentOptions) => {
11608
11628
  const defaultModeStyles = [];
@@ -11667,6 +11687,12 @@ const normalizeStyleUrl = (style) => {
11667
11687
  //#region src/compiler/transformers/decorators-to-static/component-decorator.ts
11668
11688
  let hasShownDeprecatedApiError = false;
11669
11689
  /**
11690
+ * Reset the deprecated API error flag. Call this at the start of each build.
11691
+ */
11692
+ const resetDeprecatedApiWarning = () => {
11693
+ hasShownDeprecatedApiError = false;
11694
+ };
11695
+ /**
11670
11696
  * Perform code generation to create new class members for a Stencil component
11671
11697
  * which will drive the runtime functionality specified by various options
11672
11698
  * passed to the `@Component` decorator.
@@ -11867,6 +11893,110 @@ const findTagNode = (propName, node) => {
11867
11893
  return out;
11868
11894
  };
11869
11895
  //#endregion
11896
+ //#region src/compiler/transformers/decorators-to-static/attach-internals.ts
11897
+ /**
11898
+ * Convert the attach internals decorator to static, saving the name of the
11899
+ * decorated property so an `ElementInternals` object can be bound to it later
11900
+ * on.
11901
+ *
11902
+ * The `@AttachInternals` decorator is used to indicate a field on a class
11903
+ * where the return value of the `HTMLElement.attachInternals` method should be
11904
+ * bound. This then allows component authors to use that interface to make their
11905
+ * Stencil components rich participants in whatever `HTMLFormElement` instances
11906
+ * they find themselves inside of in the future.
11907
+ *
11908
+ * The decorator also accepts an optional `states` option to define initial
11909
+ * custom states that will be set on the `ElementInternals.states` CustomStateSet.
11910
+ * Each state property can have a JSDoc comment that will be extracted for documentation.
11911
+ *
11912
+ * **Note**: this function will mutate the `newMembers` parameter in order to
11913
+ * add new members to the class.
11914
+ *
11915
+ * @param diagnostics for reporting errors and warnings
11916
+ * @param decoratedMembers the decorated members found on the class
11917
+ * @param newMembers an out param for new class members
11918
+ * @param typeChecker a TypeScript typechecker, needed for resolving the prop
11919
+ * declaration name
11920
+ * @param decoratorName the name of the decorator to look for
11921
+ */
11922
+ const attachInternalsDecoratorsToStatic = (diagnostics, decoratedMembers, newMembers, typeChecker, decoratorName) => {
11923
+ const attachInternalsMembers = decoratedMembers.filter(ts$1.isPropertyDeclaration).filter((prop) => {
11924
+ return !!retrieveTsDecorators(prop)?.find(isDecoratorNamed(decoratorName));
11925
+ });
11926
+ if (attachInternalsMembers.length === 0) return;
11927
+ if (attachInternalsMembers.length > 1) {
11928
+ const error = buildError(diagnostics);
11929
+ error.messageText = `Stencil does not support adding more than one AttachInternals() decorator to a component`;
11930
+ return;
11931
+ }
11932
+ const [decoratedProp] = attachInternalsMembers;
11933
+ const { staticName: name } = tsPropDeclName(decoratedProp, typeChecker);
11934
+ const decorator = retrieveTsDecorators(decoratedProp)?.find(isDecoratorNamed(decoratorName));
11935
+ const customStates = parseCustomStatesFromDecorator(decorator, typeChecker);
11936
+ const formAssociated = parseFormAssociatedFromDecorator(decorator);
11937
+ newMembers.push(createStaticGetter("attachInternalsMemberName", convertValueToLiteral(name)));
11938
+ if (customStates.length > 0) newMembers.push(createStaticGetter("attachInternalsCustomStates", convertValueToLiteral(customStates)));
11939
+ if (formAssociated) newMembers.push(createStaticGetter("formAssociated", convertValueToLiteral(true)));
11940
+ };
11941
+ /**
11942
+ * Parse the formAssociated option from the decorator.
11943
+ * Returns true (form-associated) unless explicitly set to false.
11944
+ *
11945
+ * @param decorator the decorator node to parse
11946
+ * @returns whether the component should be form-associated
11947
+ */
11948
+ function parseFormAssociatedFromDecorator(decorator) {
11949
+ if (!decorator || !ts$1.isCallExpression(decorator.expression)) return true;
11950
+ const [firstArg] = decorator.expression.arguments;
11951
+ if (!firstArg || !ts$1.isObjectLiteralExpression(firstArg)) return true;
11952
+ const formAssociatedProp = firstArg.properties.find((prop) => ts$1.isPropertyAssignment(prop) && ts$1.isIdentifier(prop.name) && prop.name.text === "formAssociated");
11953
+ if (!formAssociatedProp) return true;
11954
+ if (formAssociatedProp.initializer.kind === ts$1.SyntaxKind.FalseKeyword) return false;
11955
+ return true;
11956
+ }
11957
+ /**
11958
+ * Parse custom states from the decorator AST, including JSDoc comments.
11959
+ *
11960
+ * Supports JSDoc comments on state properties:
11961
+ * ```ts
11962
+ * @AttachInternals({
11963
+ * states: {
11964
+ * hovered: false,
11965
+ * /&#42;&#42; Whether is currently active &#42;/
11966
+ * active: true
11967
+ * }
11968
+ * })
11969
+ * ```
11970
+ *
11971
+ * @param decorator the decorator node to parse
11972
+ * @param typeChecker a TypeScript typechecker for resolving symbols
11973
+ * @returns array of custom state metadata with docs
11974
+ */
11975
+ function parseCustomStatesFromDecorator(decorator, typeChecker) {
11976
+ if (!decorator || !ts$1.isCallExpression(decorator.expression)) return [];
11977
+ const [firstArg] = decorator.expression.arguments;
11978
+ if (!firstArg || !ts$1.isObjectLiteralExpression(firstArg)) return [];
11979
+ const statesProp = firstArg.properties.find((prop) => ts$1.isPropertyAssignment(prop) && ts$1.isIdentifier(prop.name) && prop.name.text === "states");
11980
+ if (!statesProp || !ts$1.isObjectLiteralExpression(statesProp.initializer)) return [];
11981
+ const customStates = [];
11982
+ for (const prop of statesProp.initializer.properties) {
11983
+ if (!ts$1.isPropertyAssignment(prop)) continue;
11984
+ const stateName = ts$1.isIdentifier(prop.name) ? prop.name.text : ts$1.isStringLiteral(prop.name) ? prop.name.text : null;
11985
+ if (!stateName) continue;
11986
+ let initialValue = false;
11987
+ if (prop.initializer.kind === ts$1.SyntaxKind.TrueKeyword) initialValue = true;
11988
+ else if (prop.initializer.kind === ts$1.SyntaxKind.FalseKeyword) initialValue = false;
11989
+ const symbol = typeChecker.getSymbolAtLocation(prop.name);
11990
+ const docs = symbol ? ts$1.displayPartsToString(symbol.getDocumentationComment(typeChecker)) : "";
11991
+ customStates.push({
11992
+ name: stateName,
11993
+ initialValue,
11994
+ docs
11995
+ });
11996
+ }
11997
+ return customStates;
11998
+ }
11999
+ //#endregion
11870
12000
  //#region src/compiler/transformers/decorators-to-static/decorators-constants.ts
11871
12001
  /**
11872
12002
  * All the decorators supported by Stencil
@@ -13194,14 +13324,16 @@ const parseWatchDecorator = (typeChecker, method, decoratorName) => {
13194
13324
  * @param diagnostics for surfacing errors and warnings
13195
13325
  * @param typeChecker a TypeScript typechecker instance
13196
13326
  * @param program a {@link ts.Program} object
13327
+ * @param includeClassExpressions also convert `ts.ClassExpression` nodes (e.g. a mixin factory's
13328
+ * `(Base) => class extends Base {}`), not just named `ts.ClassDeclaration`s
13197
13329
  * @returns a TypeScript transformer factory which can be passed to
13198
13330
  * TypeScript to transform source code during the compilation process
13199
13331
  */
13200
- const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) => {
13332
+ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program, includeClassExpressions = false) => {
13201
13333
  return (transformCtx) => {
13202
13334
  let sourceFile;
13203
13335
  const visit = (node) => {
13204
- if (ts$1.isClassDeclaration(node)) return visitClassDeclaration(config, diagnostics, typeChecker, program, node, sourceFile);
13336
+ if (ts$1.isClassDeclaration(node) || includeClassExpressions && ts$1.isClassExpression(node)) return visitClassDeclaration(config, diagnostics, typeChecker, program, node, sourceFile);
13205
13337
  return ts$1.visitEachChild(node, visit, transformCtx);
13206
13338
  };
13207
13339
  return (tsSourceFile) => {
@@ -13211,10 +13343,10 @@ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) =>
13211
13343
  };
13212
13344
  };
13213
13345
  /**
13214
- * Visit {@link ts.ClassDeclaration} nodes as part of the tree-traversal
13346
+ * Visit {@link ts.ClassDeclaration}/{@link ts.ClassExpression} nodes as part of the tree-traversal
13215
13347
  * required for {@link convertDecoratorsToStatic} to work.
13216
13348
  *
13217
- * If a given class declaration node is not decorated with `@Component` this
13349
+ * If a given class node is not decorated with `@Component` this
13218
13350
  * function will simply return it as-is. If it _is_ decorated, then it will
13219
13351
  *
13220
13352
  * 1. Convert the arguments to the `@Component` decorator to static values.
@@ -13223,7 +13355,7 @@ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) =>
13223
13355
  * to static values.
13224
13356
  * 3. Validate that the various options selected by the component author are
13225
13357
  * valid, both individually and in combination.
13226
- * 4. Return an updated class declaration node which is ready to be used in
13358
+ * 4. Return an updated class node which is ready to be used in
13227
13359
  * the rest of the Stencil compilation pipeline (e.g. in output target
13228
13360
  * generation).
13229
13361
  *
@@ -13242,7 +13374,7 @@ const visitClassDeclaration = (config, diagnostics, typeChecker, program, classN
13242
13374
  const decoratedMembers = classMembers.filter((member) => (retrieveTsDecorators(member)?.length ?? 0) > 0);
13243
13375
  if (!decoratedMembers.length && !componentDecorator) return classNode;
13244
13376
  const filteredMethodsAndFields = removeStencilMethodDecorators(Array.from(classMembers), diagnostics, importAliasMap);
13245
- if (componentDecorator) componentDecoratorToStatic(config, typeChecker, diagnostics, classNode, filteredMethodsAndFields, componentDecorator);
13377
+ if (componentDecorator && ts$1.isClassDeclaration(classNode)) componentDecoratorToStatic(config, typeChecker, diagnostics, classNode, filteredMethodsAndFields, componentDecorator);
13246
13378
  if (decoratedMembers.length > 0) {
13247
13379
  const serializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("PropSerialize"), "PropSerialize", importAliasMap.get("Prop"));
13248
13380
  const deserializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("AttrDeserialize"), "AttrDeserialize", importAliasMap.get("Prop"));
@@ -13258,7 +13390,8 @@ const visitClassDeclaration = (config, diagnostics, typeChecker, program, classN
13258
13390
  validateMethods(diagnostics, classMembers);
13259
13391
  const currentDecorators = retrieveTsDecorators(classNode);
13260
13392
  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);
13393
+ const updatedModifiers = [...filterDecorators(currentDecorators, CLASS_DECORATORS_TO_REMOVE.map((decorator) => importAliasMap.get(decorator))) ?? [], ...retrieveTsModifiers(classNode) ?? []];
13394
+ 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
13395
  };
13263
13396
  /**
13264
13397
  * Take a list of `ClassElement` AST nodes and remove any decorators from
@@ -13869,11 +14002,11 @@ const parseStaticWatchers = (staticMembers) => {
13869
14002
  //#endregion
13870
14003
  //#region src/compiler/transformers/static-to-meta/class-extension/shared.ts
13871
14004
  /**
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.
14005
+ * Warns when an `extends`/`Mixin(...)` target resolved to *something* but no class literal
14006
+ * could be found inside it - e.g. a mixin factory that returns an existing class by reference
14007
+ * (`(Base) => SomeExistingClass`) rather than a class literal. Without this, the target is
14008
+ * silently dropped: any `@Prop`/`@State` etc. it declares just never appears on the extending
14009
+ * component, with no diagnostic explaining why.
13877
14010
  * @param buildCtx used to surface the warning - omit to warn silently (e.g. from tests)
13878
14011
  * @param targetName the identifier the target was reached through
13879
14012
  * @param anchor the node to attach the warning to
@@ -13881,27 +14014,32 @@ const parseStaticWatchers = (staticMembers) => {
13881
14014
  function warnMixinFactoryClassNotFound(buildCtx, targetName, anchor) {
13882
14015
  if (!buildCtx) return;
13883
14016
  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.`;
14017
+ 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
14018
  if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, anchor);
13886
14019
  }
13887
14020
  /**
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 {}`).
14021
+ * Walks the AST looking for a class declaration or class expression, optionally by name -
14022
+ * descends into a mixin factory's wrapping function (arrow function or `function` declaration)
14023
+ * body too, since a mixin factory's class is always nested one level inside it. Recognizes all of:
14024
+ * `const Foo = (Base) => class extends Base {}` (concise arrow body), `const Foo = (Base) => {
14025
+ * return class extends Base {}; }` (block body, `return` of a class expression), and `const Foo =
14026
+ * (Base) => { class FooClass extends Base {} return FooClass; }` (block body, named declaration).
13892
14027
  * @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`
14028
+ * @param name if given, only matches a class with this name
14029
+ * @returns the found class, or `undefined`
13895
14030
  */
13896
14031
  function findClassWalk(node, name) {
13897
14032
  if (!node) return void 0;
13898
- if (ts$1.isClassDeclaration(node)) {
14033
+ if (ts$1.isClassDeclaration(node) || ts$1.isClassExpression(node)) {
13899
14034
  if (!name || node.name?.text === name) return node;
13900
14035
  } else if (ts$1.isVariableDeclaration(node) && (!name || name === node.name?.text) && node.initializer && ts$1.isArrowFunction(node.initializer)) {
14036
+ const body = node.initializer.body;
14037
+ if (ts$1.isClassExpression(body)) return body;
13901
14038
  let found;
13902
- ts$1.forEachChild(node.initializer.body, (child) => {
14039
+ ts$1.forEachChild(body, (child) => {
13903
14040
  if (found) return;
13904
14041
  if (ts$1.isClassDeclaration(child)) found = child;
14042
+ else if (ts$1.isReturnStatement(child) && child.expression && ts$1.isClassExpression(child.expression)) found = child.expression;
13905
14043
  });
13906
14044
  return found;
13907
14045
  }
@@ -13914,6 +14052,22 @@ function findClassWalk(node, name) {
13914
14052
  return found;
13915
14053
  }
13916
14054
  /**
14055
+ * The declared name of a mixin-factory statement (`function Foo() {}`, or `const Foo = ...`) -
14056
+ * survives the decorator-to-static-getter transform even when the factory's inner class doesn't
14057
+ * have a name of its own, so it can anchor a post-transform re-lookup via `findClassWalk`.
14058
+ * @param node the factory statement (or its variable declaration) to read a name from
14059
+ * @returns the declared name, or `undefined` if it can't be determined
14060
+ */
14061
+ function factoryDeclaredName(node) {
14062
+ if (!node) return void 0;
14063
+ if (ts$1.isFunctionDeclaration(node)) return node.name?.text;
14064
+ if (ts$1.isVariableDeclaration(node)) return ts$1.isIdentifier(node.name) ? node.name.text : void 0;
14065
+ if (ts$1.isVariableStatement(node)) {
14066
+ const decl = node.declarationList.declarations[0];
14067
+ return decl && ts$1.isIdentifier(decl.name) ? decl.name.text : void 0;
14068
+ }
14069
+ }
14070
+ /**
13917
14071
  * Matches a top-level class/function/variable declaration by name - the three
13918
14072
  * shapes a mixin or base-class export can take (a plain class, a mixin
13919
14073
  * factory function declaration, or a mixin factory assigned to a `const`).
@@ -13931,25 +14085,161 @@ function matchesNamedDeclaration(name) {
13931
14085
  };
13932
14086
  }
13933
14087
  /**
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).
14088
+ * Finds a re-export of `className` in `sourceFile`: `export { X } from './y'`, or the
14089
+ * bundler-split shape `import { X as name } from './y'; export { name };` (no `from` clause).
13938
14090
  * @param sourceFile the (barrel) source file to scan
13939
14091
  * @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
14092
+ * @returns the module specifier and name to look for there (before any `as` aliasing), or
14093
+ * `undefined` if not found
13942
14094
  */
13943
14095
  function findReExport(sourceFile, className) {
13944
14096
  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 {
14097
+ if (!ts$1.isExportDeclaration(stmt) || !stmt.exportClause || !ts$1.isNamedExports(stmt.exportClause)) continue;
14098
+ const element = stmt.exportClause.elements.find((el) => el.name.text === className);
14099
+ if (!element) continue;
14100
+ if (stmt.moduleSpecifier && ts$1.isStringLiteral(stmt.moduleSpecifier)) return {
13947
14101
  moduleSpecifier: stmt.moduleSpecifier.text,
13948
14102
  localName: element.propertyName?.text ?? element.name.text
13949
14103
  };
14104
+ const importOrigin = findImportOrigin(sourceFile, element.propertyName?.text ?? element.name.text);
14105
+ if (importOrigin) return importOrigin;
14106
+ }
14107
+ }
14108
+ /**
14109
+ * Finds `name`'s import in `sourceFile` and returns its module and origin name (before any `as`
14110
+ * aliasing; `'default'` for a default import).
14111
+ * @param sourceFile the source file to scan for a matching import
14112
+ * @param name the local (post-aliasing) name an import bound
14113
+ * @returns the import's module specifier and origin name, or `undefined` if `name` isn't imported
14114
+ */
14115
+ function findImportOrigin(sourceFile, name) {
14116
+ for (const stmt of sourceFile.statements) {
14117
+ if (!ts$1.isImportDeclaration(stmt) || !stmt.importClause || !ts$1.isStringLiteral(stmt.moduleSpecifier)) continue;
14118
+ const moduleSpecifier = stmt.moduleSpecifier.text;
14119
+ if (stmt.importClause.name?.text === name) return {
14120
+ moduleSpecifier,
14121
+ localName: "default"
14122
+ };
14123
+ const bindings = stmt.importClause.namedBindings;
14124
+ if (!bindings || !ts$1.isNamedImports(bindings)) continue;
14125
+ const element = bindings.elements.find((el) => el.name.text === name);
14126
+ if (element) return {
14127
+ moduleSpecifier,
14128
+ localName: element.propertyName?.text ?? element.name.text
14129
+ };
13950
14130
  }
13951
14131
  }
13952
14132
  /**
14133
+ * Finds `name` as a top-level declaration in `sf` (see `matchesNamedDeclaration`), following a
14134
+ * same-file export alias if `name` is only ever the public side of a local rename
14135
+ * (`export { RealName as name }`, no `from` clause).
14136
+ * @param sf the source file to search
14137
+ * @param name the declaration name to look for, which may only exist as an export alias
14138
+ * @returns the matched statement, or `undefined`
14139
+ */
14140
+ function findStatementByName(sf, name) {
14141
+ const direct = sf.statements.find(matchesNamedDeclaration(name));
14142
+ if (direct) return direct;
14143
+ for (const stmt of sf.statements) {
14144
+ if (!ts$1.isExportDeclaration(stmt) || stmt.moduleSpecifier || !stmt.exportClause || !ts$1.isNamedExports(stmt.exportClause)) continue;
14145
+ const aliasedName = stmt.exportClause.elements.find((el) => el.name.text === name)?.propertyName?.text;
14146
+ if (aliasedName && aliasedName !== name) return sf.statements.find(matchesNamedDeclaration(aliasedName));
14147
+ }
14148
+ }
14149
+ /**
14150
+ * Picks the runtime target out of a `package.json` `exports` condition entry - prefers `import`
14151
+ * over `require`/`node`/`default`, recursing into nested condition objects.
14152
+ * @param entry an `exports` map value: a path string, or nested conditions
14153
+ * @returns the resolved relative path, or `undefined` if no usable condition was found
14154
+ */
14155
+ function pickJsCondition(entry) {
14156
+ if (typeof entry === "string") return entry;
14157
+ if (typeof entry !== "object" || entry === null) return;
14158
+ const conditions = entry;
14159
+ for (const key of [
14160
+ "import",
14161
+ "require",
14162
+ "node",
14163
+ "default"
14164
+ ]) if (key in conditions) {
14165
+ const picked = pickJsCondition(conditions[key]);
14166
+ if (picked) return picked;
14167
+ }
14168
+ }
14169
+ /**
14170
+ * Reads and parses `filePath` as JS, with parent nodes set - unlike `tsGetSourceFile`, which
14171
+ * never triggers binding, so `.parent` stays unset and `node.getSourceFile()` returns `undefined`.
14172
+ * @param config the current Stencil validated config
14173
+ * @param filePath the absolute path of the JS file to read and parse
14174
+ * @returns the parsed source file, or `undefined` if it couldn't be read
14175
+ */
14176
+ function readJsSourceFile(config, filePath) {
14177
+ try {
14178
+ const text = config.sys.readFileSync(filePath);
14179
+ if (typeof text !== "string") return;
14180
+ return ts$1.createSourceFile(filePath, text, ts$1.ScriptTarget.ESNext, true, ts$1.ScriptKind.JS);
14181
+ } catch {
14182
+ return;
14183
+ }
14184
+ }
14185
+ /**
14186
+ * Resolves the runtime JS entry for a bare (non-relative) module specifier by reading its
14187
+ * package's own `package.json` `exports` map, instead of `tsResolveModuleName` - which always
14188
+ * resolves to the package's `types` entry, an ambient signature with no body a mixin factory's
14189
+ * class can never be found inside.
14190
+ * @param config the current Stencil validated config
14191
+ * @param compilerCtx the current compiler context
14192
+ * @param moduleSpecifier the bare package specifier to resolve
14193
+ * @param containingFile the file the specifier was imported from
14194
+ * @returns the resolved JS source file, or `undefined` if it couldn't be resolved this way
14195
+ */
14196
+ function resolveModuleJsEntry(config, compilerCtx, moduleSpecifier, containingFile) {
14197
+ if (isLocalModule(moduleSpecifier)) return;
14198
+ const pkgJsonPath = tsResolveModuleNamePackageJsonPath(config, compilerCtx, moduleSpecifier, containingFile);
14199
+ if (!pkgJsonPath) return;
14200
+ let pkgJson;
14201
+ try {
14202
+ pkgJson = JSON.parse(config.sys.readFileSync(pkgJsonPath));
14203
+ } catch {
14204
+ return;
14205
+ }
14206
+ const pkgName = pkgJson.name;
14207
+ if (!pkgName || !moduleSpecifier.startsWith(pkgName) || !pkgJson.exports) return;
14208
+ const subpath = moduleSpecifier === pkgName ? "." : `.${moduleSpecifier.slice(pkgName.length)}`;
14209
+ const exportsMap = pkgJson.exports;
14210
+ const conditionEntry = typeof exportsMap === "string" ? subpath === "." ? exportsMap : void 0 : exportsMap[subpath] ?? (subpath === "." ? exportsMap : void 0);
14211
+ const target = conditionEntry && pickJsCondition(conditionEntry);
14212
+ if (!target) return;
14213
+ return readJsSourceFile(config, normalizePath(join$1(dirname(pkgJsonPath), target)));
14214
+ }
14215
+ /**
14216
+ * Finds `className`'s class inside a resolved JS entry (see `resolveModuleJsEntry`), following
14217
+ * re-export hops the same way `resolveAndProcessExtendedClass` walks a `.d.ts`/`.ts` source.
14218
+ * @param config the current Stencil validated config
14219
+ * @param compilerCtx the current compiler context
14220
+ * @param source the JS source file to search
14221
+ * @param className the class (or mixin factory) name to look for
14222
+ * @param hopsRemaining re-export hops still allowed before giving up
14223
+ * @returns the found class and the source file it's declared in, or `undefined`
14224
+ */
14225
+ function findClassInJsModule(config, compilerCtx, source, className, hopsRemaining = 3) {
14226
+ const matchedStatement = findStatementByName(source, className);
14227
+ if (matchedStatement) {
14228
+ const classNode = ts$1.isClassDeclaration(matchedStatement) ? matchedStatement : findClassWalk(matchedStatement);
14229
+ return classNode && {
14230
+ classNode,
14231
+ sourceFile: source
14232
+ };
14233
+ }
14234
+ if (hopsRemaining <= 0) return;
14235
+ const reExport = findReExport(source, className);
14236
+ if (!reExport) return;
14237
+ const resolvedFileName = tsResolveModuleName(config, compilerCtx, reExport.moduleSpecifier, source.fileName)?.resolvedModule?.resolvedFileName;
14238
+ const nextSource = resolvedFileName && readJsSourceFile(config, resolvedFileName);
14239
+ if (!nextSource) return;
14240
+ return findClassInJsModule(config, compilerCtx, nextSource, reExport.localName, hopsRemaining - 1);
14241
+ }
14242
+ /**
13953
14243
  * Filters `dedupeMembers` down to entries not already present in `staticMembers`
13954
14244
  * (by name, or `methodName` for change handlers) - used so an extending
13955
14245
  * class's own members win over inherited ones.
@@ -14035,7 +14325,7 @@ function convertDiskSourceFileDecorators(sourceFile, config, target = ts$1.Scrip
14035
14325
  const program = ts$1.createProgram([sourceFile.fileName], compilerOptions, host);
14036
14326
  const typeChecker = program.getTypeChecker();
14037
14327
  const ownSourceFile = program.getSourceFile(sourceFile.fileName) ?? sourceFile;
14038
- const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program)]);
14328
+ const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program, true)]);
14039
14329
  const printed = ts$1.createPrinter({ removeComments: false }).printFile(result.transformed[0]);
14040
14330
  return ts$1.createSourceFile(sourceFile.fileName, printed, target, true);
14041
14331
  }
@@ -14055,9 +14345,11 @@ function convertDiskSourceFileDecorators(sourceFile, config, target = ts$1.Scrip
14055
14345
  * @param ogModule the original module file of the class declaration
14056
14346
  * @param targetScriptTarget the script target to convert decorators with, if needed
14057
14347
  * @param barrelHopsRemaining re-export hops still allowed before giving up
14348
+ * @param originalModuleSpecifier the specifier this lookup started from, before any barrel hops
14349
+ * @param originalContainingFile the file `originalModuleSpecifier` was imported from
14058
14350
  * @returns the found class declaration, or `undefined`
14059
14351
  */
14060
- function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, currentSource, moduleSpecifier, className, dependentClasses, typeChecker, ogModule, targetScriptTarget = ts$1.ScriptTarget.ESNext, barrelHopsRemaining = 1) {
14352
+ function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, currentSource, moduleSpecifier, className, dependentClasses, typeChecker, ogModule, targetScriptTarget = ts$1.ScriptTarget.ESNext, barrelHopsRemaining = 1, originalModuleSpecifier = moduleSpecifier, originalContainingFile = currentSource.fileName) {
14061
14353
  let keepLooking = true;
14062
14354
  const foundFile = tsResolveModuleName(buildCtx.config, compilerCtx, moduleSpecifier, currentSource.fileName);
14063
14355
  if (!foundFile?.resolvedModule || !className) return;
@@ -14073,10 +14365,10 @@ function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration,
14073
14365
  }
14074
14366
  foundSource = convertDiskSourceFileDecorators(foundSource, buildCtx.config, targetScriptTarget);
14075
14367
  }
14076
- const matchedStatement = foundSource.statements.find(matchesNamedDeclaration(className));
14368
+ const matchedStatement = findStatementByName(foundSource, className);
14077
14369
  if (!matchedStatement) {
14078
14370
  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);
14371
+ if (reExport) return resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, foundSource, reExport.moduleSpecifier, reExport.localName, dependentClasses, typeChecker, ogModule, targetScriptTarget, barrelHopsRemaining - 1, originalModuleSpecifier, originalContainingFile);
14080
14372
  const err = buildWarn(buildCtx.diagnostics);
14081
14373
  err.messageText = `Unable to find "${className}" in the imported module "${moduleSpecifier}".
14082
14374
  Please import class / mixin-factory declarations directly and not via barrel files.`;
@@ -14084,16 +14376,25 @@ function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration,
14084
14376
  return;
14085
14377
  }
14086
14378
  let foundClassDeclaration = matchedStatement ? ts$1.isClassDeclaration(matchedStatement) ? matchedStatement : void 0 : void 0;
14379
+ let foundClassSource = foundSource;
14087
14380
  if (!foundClassDeclaration && matchedStatement) {
14088
14381
  foundClassDeclaration = findClassWalk(matchedStatement);
14089
14382
  keepLooking = false;
14383
+ if (!foundClassDeclaration && isDtsFile(foundSource.fileName) && !isLocalModule(originalModuleSpecifier)) {
14384
+ const jsSource = resolveModuleJsEntry(buildCtx.config, compilerCtx, originalModuleSpecifier, originalContainingFile);
14385
+ const foundInJs = jsSource && findClassInJsModule(buildCtx.config, compilerCtx, jsSource, className);
14386
+ if (foundInJs) {
14387
+ foundClassDeclaration = foundInJs.classNode;
14388
+ foundClassSource = foundInJs.sourceFile;
14389
+ }
14390
+ }
14090
14391
  if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, className, classDeclaration);
14091
14392
  }
14092
14393
  if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {
14093
14394
  dependentClasses.push({
14094
14395
  classNode: foundClassDeclaration,
14095
- sourceFile: foundSource,
14096
- fileName: foundFile.resolvedModule.resolvedFileName
14396
+ sourceFile: foundClassSource,
14397
+ fileName: foundClassSource.fileName
14097
14398
  });
14098
14399
  if (keepLooking) buildExtendsTree(compilerCtx, foundClassDeclaration, dependentClasses, typeChecker, buildCtx, ogModule);
14099
14400
  }
@@ -14122,6 +14423,7 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
14122
14423
  const targetScriptTarget = (ogModule?.staticSourceFile)?.languageVersion ?? ts$1.ScriptTarget.ESNext;
14123
14424
  let classIdentifiers = [];
14124
14425
  let foundClassDeclaration;
14426
+ let foundClassName;
14125
14427
  let keepLooking = true;
14126
14428
  extendsClause.types.forEach((type) => {
14127
14429
  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 +14440,11 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
14138
14440
  declarations = [...source.statements];
14139
14441
  }
14140
14442
  foundClassDeclaration = declarations?.find(ts$1.isClassDeclaration);
14443
+ foundClassName = foundClassDeclaration?.name?.getText();
14141
14444
  if (!foundClassDeclaration) {
14142
14445
  const node = declarations?.[0];
14143
14446
  foundClassDeclaration = findClassWalk(node);
14447
+ foundClassName = foundClassDeclaration?.name?.getText() ?? factoryDeclaredName(node);
14144
14448
  if (!node) throw "revert to sad path";
14145
14449
  keepLooking = false;
14146
14450
  if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, extendee.getText(), classDeclaration);
@@ -14149,7 +14453,7 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
14149
14453
  const foundModule = compilerCtx.moduleMap.get(foundClassDeclaration.getSourceFile().fileName);
14150
14454
  if (foundModule) {
14151
14455
  const moduleSourceFile = foundModule.staticSourceFile;
14152
- const sourceClass = findClassWalk(moduleSourceFile, foundClassDeclaration.name?.getText());
14456
+ const sourceClass = findClassWalk(moduleSourceFile, foundClassName);
14153
14457
  if (sourceClass) {
14154
14458
  dependentClasses.push({
14155
14459
  classNode: sourceClass,
@@ -14170,20 +14474,24 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
14170
14474
  if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, classDeclaration);
14171
14475
  return;
14172
14476
  }
14173
- if (matchedStatement && ts$1.isClassDeclaration(matchedStatement)) foundClassDeclaration = matchedStatement;
14174
- else if (matchedStatement) {
14477
+ if (matchedStatement && ts$1.isClassDeclaration(matchedStatement)) {
14478
+ foundClassDeclaration = matchedStatement;
14479
+ foundClassName = foundClassDeclaration.name?.getText();
14480
+ } else if (matchedStatement) {
14175
14481
  foundClassDeclaration = findClassWalk(matchedStatement);
14482
+ foundClassName = foundClassDeclaration?.name?.getText() ?? extendee.getText();
14176
14483
  keepLooking = false;
14177
14484
  if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, extendee.getText(), classDeclaration);
14178
14485
  } else {
14179
14486
  foundClassDeclaration = findClassWalk(currentSource, extendee.getText());
14487
+ foundClassName = foundClassDeclaration?.name?.getText() ?? extendee.getText();
14180
14488
  keepLooking = false;
14181
14489
  }
14182
14490
  if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {
14183
14491
  const foundModule = compilerCtx.moduleMap.get(currentSource.fileName);
14184
14492
  if (foundModule?.staticSourceFile) {
14185
14493
  const transformedSource = foundModule.staticSourceFile;
14186
- const transformedClass = findClassWalk(transformedSource, foundClassDeclaration.name?.getText());
14494
+ const transformedClass = findClassWalk(transformedSource, foundClassName);
14187
14495
  if (transformedClass) {
14188
14496
  dependentClasses.push({
14189
14497
  classNode: transformedClass,
@@ -14468,7 +14776,7 @@ function convertInMemorySourceDecorators(sourceFile, config) {
14468
14776
  const program = ts$1.createProgram([sourceFile.fileName], compilerOptions, compilerHost);
14469
14777
  const typeChecker = program.getTypeChecker();
14470
14778
  const ownSourceFile = program.getSourceFile(sourceFile.fileName) ?? sourceFile;
14471
- const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program)]);
14779
+ const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program, true)]);
14472
14780
  const printed = ts$1.createPrinter({ removeComments: false }).printFile(result.transformed[0]);
14473
14781
  const scriptKind = sourceFile.fileName.endsWith(".tsx") || sourceFile.fileName.endsWith(".ts") ? ts$1.ScriptKind.TSX : ts$1.ScriptKind.JS;
14474
14782
  return ts$1.createSourceFile(sourceFile.fileName, printed, sourceFile.languageVersion, true, scriptKind);
@@ -14493,19 +14801,6 @@ function getExtendsClassNames(node) {
14493
14801
  if (ts$1.isCallExpression(expr) && expr.expression.getText() === "Mixin") return expr.arguments.filter(ts$1.isIdentifier).map((id) => id.text);
14494
14802
  return [];
14495
14803
  }
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
14804
  /**
14510
14805
  * A single-file mini-program (see `convertInMemorySourceDecorators`) can
14511
14806
  * never load an imported module's own `SourceFile`, so a type that's
@@ -14529,7 +14824,7 @@ function reclassifyGlobalTypeReferences(members, declaringSf, declaringPath, res
14529
14824
  if (!references) return;
14530
14825
  Object.entries(references).forEach(([typeName, reference]) => {
14531
14826
  if (reference.location !== "global") return;
14532
- const specifier = findImportSpecifier(declaringSf, typeName);
14827
+ const specifier = findImportOrigin(declaringSf, typeName)?.moduleSpecifier;
14533
14828
  if (!specifier) return;
14534
14829
  const resolved = resolveImport(specifier, declaringPath);
14535
14830
  reference.location = "import";
@@ -14552,7 +14847,7 @@ function reclassifyGlobalTypeReferences(members, declaringSf, declaringPath, res
14552
14847
  * differ from `sf`/`path` if resolved through a re-export), or `undefined`
14553
14848
  */
14554
14849
  function findDeclarationOrReExport(sf, path, name, resolveImport) {
14555
- const direct = sf.statements.find(matchesNamedDeclaration(name));
14850
+ const direct = findStatementByName(sf, name);
14556
14851
  if (direct) return {
14557
14852
  statement: direct,
14558
14853
  sourceFile: sf,
@@ -14565,7 +14860,7 @@ function findDeclarationOrReExport(sf, path, name, resolveImport) {
14565
14860
  const { code, path: resolvedPath } = resolved;
14566
14861
  const isTs = resolvedPath.endsWith(".tsx") || resolvedPath.endsWith(".ts");
14567
14862
  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));
14863
+ const statement = findStatementByName(reExportSf, reExport.localName);
14569
14864
  if (!statement) return void 0;
14570
14865
  return {
14571
14866
  statement,
@@ -14602,7 +14897,7 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
14602
14897
  let foundSf = sf;
14603
14898
  let foundPath = path;
14604
14899
  let keepLooking = true;
14605
- const sameFileStatement = sf.statements.find(matchesNamedDeclaration(parentName));
14900
+ const sameFileStatement = findStatementByName(sf, parentName);
14606
14901
  if (sameFileStatement) {
14607
14902
  if (ts$1.isClassDeclaration(sameFileStatement)) foundClass = sameFileStatement;
14608
14903
  else {
@@ -14611,7 +14906,7 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
14611
14906
  if (!foundClass) warnMixinFactoryClassNotFound(buildCtx, parentName, rootClassDeclaration);
14612
14907
  }
14613
14908
  } else {
14614
- const specifier = findImportSpecifier(sf, parentName);
14909
+ const specifier = findImportOrigin(sf, parentName)?.moduleSpecifier;
14615
14910
  if (!specifier) continue;
14616
14911
  const resolved = resolveImport(specifier, path);
14617
14912
  if (!resolved) continue;
@@ -14643,7 +14938,8 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
14643
14938
  ancestors.push({
14644
14939
  classNode: foundClass,
14645
14940
  sourceFile: foundSf,
14646
- path: foundPath
14941
+ path: foundPath,
14942
+ factoryName: parentName
14647
14943
  });
14648
14944
  if (keepLooking) resolveAncestors(foundClass, foundSf, foundPath, resolveImport, visited, ancestors, rootClassDeclaration, buildCtx);
14649
14945
  }
@@ -14660,8 +14956,8 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
14660
14956
  * @returns the ancestor's metadata
14661
14957
  */
14662
14958
  function extractAncestorMeta(ancestor, cmpSourceFile, resolveImport, config) {
14663
- const { classNode, sourceFile: parentSf, path: resolvedPath } = ancestor;
14664
- const className = classNode.name?.text;
14959
+ const { classNode, sourceFile: parentSf, path: resolvedPath, factoryName } = ancestor;
14960
+ const className = classNode.name?.text ?? factoryName;
14665
14961
  const parentStaticMembers = classNode.members.filter(isStaticGetter);
14666
14962
  let resolvedClassNode = classNode;
14667
14963
  let resolvedStaticMembers = parentStaticMembers;
@@ -14753,7 +15049,6 @@ function mergeExtendedClassMetaWithResolveImport(cmpNode, staticMembers, sourceF
14753
15049
  //#region src/compiler/transformers/static-to-meta/class-methods.ts
14754
15050
  const parseClassMethods = (classMethods, cmpMeta) => {
14755
15051
  if (!classMethods?.length) return;
14756
- const hasHostData = classMethods.includes("hostData");
14757
15052
  cmpMeta.hasAttributeChangedCallbackFn = classMethods.includes("attributeChangedCallback");
14758
15053
  cmpMeta.hasConnectedCallbackFn = classMethods.includes("connectedCallback");
14759
15054
  cmpMeta.hasDisconnectedCallbackFn = classMethods.includes("disconnectedCallback");
@@ -14765,8 +15060,7 @@ const parseClassMethods = (classMethods, cmpMeta) => {
14765
15060
  cmpMeta.hasComponentShouldUpdateFn = classMethods.includes("componentShouldUpdate");
14766
15061
  cmpMeta.hasComponentDidUpdateFn = classMethods.includes("componentDidUpdate");
14767
15062
  cmpMeta.hasLifecycle = cmpMeta.hasComponentWillLoadFn || cmpMeta.hasComponentDidLoadFn || cmpMeta.hasComponentWillUpdateFn || cmpMeta.hasComponentDidUpdateFn;
14768
- cmpMeta.hasRenderFn = classMethods.includes("render") || hasHostData;
14769
- cmpMeta.hasVdomRender = cmpMeta.hasVdomRender || hasHostData;
15063
+ cmpMeta.hasRenderFn = classMethods.includes("render");
14770
15064
  };
14771
15065
  //#endregion
14772
15066
  //#region src/compiler/transformers/static-to-meta/element-ref.ts
@@ -15665,6 +15959,7 @@ const transpileModule = (config, input, transformOpts) => {
15665
15959
  ...config,
15666
15960
  logger: createNodeLogger()
15667
15961
  };
15962
+ resetDeprecatedApiWarning();
15668
15963
  const compilerCtx = new CompilerContext();
15669
15964
  const buildCtx = new BuildContext(config, compilerCtx);
15670
15965
  const tsCompilerOptions = { ...config.tsCompilerOptions };
@@ -15842,6 +16137,7 @@ const transpileCss = async (transformInput, results) => {
15842
16137
  results.map = cssResults.map;
15843
16138
  results.imports = cssResults.imports.map((p) => ({ path: p.importPath }));
15844
16139
  results.diagnostics.push(...cssResults.diagnostics);
16140
+ if (transformInput.docs) results.styleDocs = cssResults.styleDocs;
15845
16141
  };
15846
16142
  const transpileCssSync = (transformInput, results) => {
15847
16143
  const cssResults = transformCssToEsmSync(transformInput);
@@ -15849,6 +16145,7 @@ const transpileCssSync = (transformInput, results) => {
15849
16145
  results.map = cssResults.map;
15850
16146
  results.imports = cssResults.imports.map((p) => ({ path: p.importPath }));
15851
16147
  results.diagnostics.push(...cssResults.diagnostics);
16148
+ if (transformInput.docs) results.styleDocs = cssResults.styleDocs;
15852
16149
  };
15853
16150
  const transpileJson = (results) => {
15854
16151
  results.code = dataToEsm(JSON.parse(results.code), {
@@ -16279,7 +16576,7 @@ const FORM_ASSOCIATED_ATTRIBUTES = [
16279
16576
  * @param cmp the metadata for the component that a type definition string is generated for
16280
16577
  * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions
16281
16578
  * @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
16579
+ * @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
16580
  * @returns the generated types string alongside additional metadata
16284
16581
  */
16285
16582
  const generateComponentTypes = (cmp, typeImportData, areTypesInternal, signalBacking = false) => {
@@ -16296,8 +16593,12 @@ const generateComponentTypes = (cmp, typeImportData, areTypesInternal, signalBac
16296
16593
  const isDep = cmp.isCollectionDependency;
16297
16594
  const propNames = new Set(propAttributes.map((p) => p.name));
16298
16595
  const formAssociatedAttrs = cmp.formAssociated ? FORM_ASSOCIATED_ATTRIBUTES.filter((attr) => !propNames.has(attr.name)) : [];
16596
+ const jsxPropAttributes = signalBacking ? propAttributes.map((attr) => ({
16597
+ ...attr,
16598
+ type: `${attr.type} | ReadonlySignal<${attr.type}>`
16599
+ })) : propAttributes;
16299
16600
  const jsxAttributes = attributesToMultiLineString([
16300
- ...propAttributes,
16601
+ ...jsxPropAttributes,
16301
16602
  ...eventAttributes,
16302
16603
  ...formAssociatedAttrs
16303
16604
  ], true, areTypesInternal);