@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.
- package/dist/app-data/index.d.ts +1 -1
- package/dist/{client-BRu0GtRn.mjs → client-DIvBaMnB.mjs} +182 -70
- package/dist/compiler/browser.d.ts +114 -81
- package/dist/compiler/browser.js +743 -339
- package/dist/compiler/index.d.mts +110 -2
- package/dist/compiler/index.mjs +3 -3
- package/dist/compiler/utils/index.d.mts +1 -1
- package/dist/{compiler-BPgV6bA4.mjs → compiler-BI12oAIV.mjs} +4840 -2899
- package/dist/declarations/stencil-public-compiler.d.ts +152 -129
- package/dist/declarations/stencil-public-docs.d.ts +23 -0
- package/dist/declarations/stencil-public-runtime.d.ts +62 -58
- package/dist/{index-DmHmu3y0.d.mts → index-BGUOG9Wc.d.mts} +6 -2
- package/dist/{index-BopBfjPu.d.mts → index-BogZpjP2.d.mts} +150 -127
- package/dist/{index-BXAcVN2j.d.ts → index-CicD4Pgn.d.ts} +59 -55
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +1 -1
- package/dist/jsx-runtime.d.mts +6 -0
- package/dist/jsx-runtime.mjs +1 -1
- package/dist/{node-75gQKkFz.mjs → node-D-21Ykxi.mjs} +41 -47
- package/dist/runtime/client/lazy.js +321 -200
- package/dist/runtime/client/runtime.d.ts +73 -66
- package/dist/runtime/client/runtime.js +321 -200
- package/dist/runtime/index.d.ts +4 -5
- package/dist/runtime/index.js +319 -198
- package/dist/runtime/server/index.d.mts +11 -11
- package/dist/runtime/server/index.mjs +371 -239
- package/dist/runtime/server/runner.d.mts +4 -4
- package/dist/runtime/server/runner.mjs +82 -54
- package/dist/signals/index.d.ts +11 -2
- package/dist/signals/index.js +14 -35
- package/dist/sys/node/index.d.mts +1 -1
- package/dist/sys/node/index.mjs +1 -1
- package/dist/sys/node/worker.mjs +2 -2
- package/dist/testing/index.d.mts +136 -120
- package/dist/testing/index.mjs +328 -212
- package/package.json +8 -4
package/dist/compiler/browser.js
CHANGED
|
@@ -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.
|
|
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() :
|
|
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"
|
|
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"
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
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
|
-
*
|
|
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
|
|
3962
|
+
let remainingText = styleText;
|
|
3963
|
+
let match = remainingText.match(CSS_DOC_START);
|
|
3888
3964
|
while (match !== null) {
|
|
3889
|
-
|
|
3890
|
-
const endIndex =
|
|
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,
|
|
3893
|
-
|
|
3894
|
-
match =
|
|
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(
|
|
3913
|
-
const
|
|
3914
|
-
if (!
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
4174
|
-
|
|
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
|
|
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
|
|
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
|
-
* /** Whether is currently active */
|
|
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
|
+
* /** Whether is currently active */
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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 = (
|
|
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
|
|
13590
|
-
if (
|
|
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
|
|
13873
|
-
* could be found inside it - e.g. a mixin factory
|
|
13874
|
-
* (`(Base) =>
|
|
13875
|
-
*
|
|
13876
|
-
*
|
|
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
|
|
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 -
|
|
13889
|
-
* into a mixin factory's wrapping function (arrow function or `function`
|
|
13890
|
-
*
|
|
13891
|
-
*
|
|
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
|
|
13894
|
-
* @returns the found class
|
|
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(
|
|
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
|
|
13935
|
-
* `
|
|
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
|
|
13941
|
-
*
|
|
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.
|
|
13946
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
14096
|
-
fileName:
|
|
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,
|
|
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))
|
|
14174
|
-
|
|
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,
|
|
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 =
|
|
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
|
|
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
|
|
14562
|
-
|
|
14563
|
-
|
|
14564
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
|
|
14569
|
-
|
|
14570
|
-
|
|
14571
|
-
|
|
14572
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
14723
|
-
|
|
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")
|
|
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
|
-
|
|
15150
|
-
|
|
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(
|
|
15531
|
+
node.forEachChild(visitComponentChildNode);
|
|
15154
15532
|
};
|
|
15155
|
-
visitComponentChildNode(cmpNode
|
|
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
|
-
*
|
|
15174
|
-
*
|
|
15175
|
-
* @param
|
|
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
|
|
15179
|
-
const
|
|
15180
|
-
|
|
15181
|
-
|
|
15182
|
-
const
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
|
|
15191
|
-
|
|
15192
|
-
|
|
15193
|
-
|
|
15194
|
-
|
|
15195
|
-
|
|
15196
|
-
|
|
15197
|
-
|
|
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
|
-
|
|
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
|
-
|
|
15545
|
-
|
|
15546
|
-
|
|
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
|
-
...
|
|
16704
|
+
...jsxPropAttributes,
|
|
16301
16705
|
...eventAttributes,
|
|
16302
16706
|
...formAssociatedAttrs
|
|
16303
16707
|
], true, areTypesInternal);
|