@stencil/core 5.0.0-beta.3 → 5.0.0-beta.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app-data/index.d.ts +1 -1
- package/dist/{client-BRu0GtRn.mjs → client-BYvfR_Hx.mjs} +127 -68
- package/dist/compiler/browser.d.ts +114 -81
- package/dist/compiler/browser.js +733 -336
- 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-6RhuOkQ0.mjs} +4829 -2895
- 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 +60 -58
- package/dist/{index-DmHmu3y0.d.mts → index-BGUOG9Wc.d.mts} +6 -2
- package/dist/{index-BXAcVN2j.d.ts → index-BHciXst1.d.ts} +57 -55
- package/dist/{index-BopBfjPu.d.mts → index-BogZpjP2.d.mts} +150 -127
- 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-CvPPhnWO.mjs} +41 -47
- package/dist/runtime/client/lazy.js +252 -189
- package/dist/runtime/client/runtime.d.ts +71 -66
- package/dist/runtime/client/runtime.js +252 -189
- package/dist/runtime/index.d.ts +4 -5
- package/dist/runtime/index.js +250 -187
- package/dist/runtime/server/index.d.mts +11 -11
- package/dist/runtime/server/index.mjs +302 -228
- 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 +259 -201
- 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.30";
|
|
1836
1847
|
//#endregion
|
|
1837
1848
|
//#region src/compiler/events.ts
|
|
1838
1849
|
const buildEvents = () => {
|
|
@@ -1895,6 +1906,7 @@ const resolve = (id, _opts, cb) => {
|
|
|
1895
1906
|
};
|
|
1896
1907
|
//#endregion
|
|
1897
1908
|
//#region src/compiler/sys/resolve/resolve-utils.ts
|
|
1909
|
+
const isLocalModule = (p) => p.startsWith(".") || p.startsWith("/");
|
|
1898
1910
|
const isNodeModulePath = (p) => normalizePath(p).split("/").includes("node_modules");
|
|
1899
1911
|
const getModuleId = (orgImport) => {
|
|
1900
1912
|
if (orgImport.startsWith("~")) orgImport = orgImport.substring(1);
|
|
@@ -2345,15 +2357,6 @@ const createSystem = (c) => {
|
|
|
2345
2357
|
}
|
|
2346
2358
|
return results;
|
|
2347
2359
|
};
|
|
2348
|
-
/**
|
|
2349
|
-
* `self` is the global namespace object used within a web worker.
|
|
2350
|
-
* `window` is the browser's global namespace object (I reorganized this to check the reference on that second)
|
|
2351
|
-
* `global` is Node's global namespace object. https://nodejs.org/api/globals.html#globals_global
|
|
2352
|
-
*
|
|
2353
|
-
* loading in this order should allow workers, which are most common, then browser,
|
|
2354
|
-
* then Node to grab the reference to fetch correctly.
|
|
2355
|
-
*/
|
|
2356
|
-
const fetch = typeof self !== "undefined" ? self?.fetch : typeof window !== "undefined" ? window?.fetch : typeof global !== "undefined" ? global?.fetch : void 0;
|
|
2357
2360
|
const writeFile = async (p, data) => writeFileSync(p, data);
|
|
2358
2361
|
const tmpDirSync = () => "/.tmp";
|
|
2359
2362
|
const tick = Promise.resolve();
|
|
@@ -2364,6 +2367,7 @@ const createSystem = (c) => {
|
|
|
2364
2367
|
if (typeof hashLength === "number") hashHex = hashHex.slice(0, hashLength);
|
|
2365
2368
|
return hashHex;
|
|
2366
2369
|
};
|
|
2370
|
+
const generateFileHash = async (filePath, hashLength) => generateContentHash(readFileSync(filePath), hashLength);
|
|
2367
2371
|
const copy = async (copyTasks, srcDir) => {
|
|
2368
2372
|
const results = {
|
|
2369
2373
|
diagnostics: [],
|
|
@@ -2373,9 +2377,6 @@ const createSystem = (c) => {
|
|
|
2373
2377
|
logger.info("todo, copy task", copyTasks.length, srcDir);
|
|
2374
2378
|
return results;
|
|
2375
2379
|
};
|
|
2376
|
-
const getEnvironmentVar = (key) => {
|
|
2377
|
-
return process$1?.env[key];
|
|
2378
|
-
};
|
|
2379
2380
|
const getLocalModulePath = (opts) => join$1(opts.rootDir, "node_modules", opts.moduleId, opts.path);
|
|
2380
2381
|
const getRemoteModuleUrl = (opts) => {
|
|
2381
2382
|
const npmBaseUrl = "https://cdn.jsdelivr.net/npm/";
|
|
@@ -2391,13 +2392,14 @@ const createSystem = (c) => {
|
|
|
2391
2392
|
access,
|
|
2392
2393
|
accessSync,
|
|
2393
2394
|
addDestroy,
|
|
2395
|
+
checkVersion: async () => noop,
|
|
2394
2396
|
copyFile,
|
|
2395
2397
|
createDir,
|
|
2396
2398
|
createDirSync,
|
|
2397
2399
|
homeDir,
|
|
2398
2400
|
isTTY,
|
|
2399
|
-
getEnvironmentVar,
|
|
2400
2401
|
destroy,
|
|
2402
|
+
dynamicImport: (p) => import(p),
|
|
2401
2403
|
encodeToBase64,
|
|
2402
2404
|
exit: async (exitCode) => logger.warn(`exit ${exitCode}`),
|
|
2403
2405
|
getCurrentDirectory,
|
|
@@ -2408,6 +2410,7 @@ const createSystem = (c) => {
|
|
|
2408
2410
|
isSymbolicLink,
|
|
2409
2411
|
nextTick,
|
|
2410
2412
|
normalizePath: normalize,
|
|
2413
|
+
onProcessInterrupt: noop,
|
|
2411
2414
|
platformPath: path,
|
|
2412
2415
|
readDir,
|
|
2413
2416
|
readDirSync,
|
|
@@ -2417,7 +2420,6 @@ const createSystem = (c) => {
|
|
|
2417
2420
|
realpathSync,
|
|
2418
2421
|
removeDestroy,
|
|
2419
2422
|
rename,
|
|
2420
|
-
fetch,
|
|
2421
2423
|
resolvePath,
|
|
2422
2424
|
removeDir,
|
|
2423
2425
|
removeDirSync,
|
|
@@ -2432,6 +2434,7 @@ const createSystem = (c) => {
|
|
|
2432
2434
|
writeFile,
|
|
2433
2435
|
writeFileSync,
|
|
2434
2436
|
generateContentHash,
|
|
2437
|
+
generateFileHash,
|
|
2435
2438
|
createWorkerController: null,
|
|
2436
2439
|
details: {
|
|
2437
2440
|
cpuModel: "",
|
|
@@ -2633,19 +2636,20 @@ const getTranspileCssConfig = (compileOpts, importData, results) => {
|
|
|
2633
2636
|
minify: false,
|
|
2634
2637
|
autoprefixer: false,
|
|
2635
2638
|
module: compileOpts.module,
|
|
2636
|
-
styleImportData: compileOpts.styleImportData
|
|
2639
|
+
styleImportData: compileOpts.styleImportData,
|
|
2640
|
+
docs: compileOpts.docs === true
|
|
2637
2641
|
};
|
|
2638
2642
|
};
|
|
2639
2643
|
const getTranspileConfigOpt = (value, validValues, defaultValue) => {
|
|
2640
2644
|
if (value === null || value === "null") return null;
|
|
2641
|
-
value = isString$1(value) ? value.toLowerCase().trim() :
|
|
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
|
|
@@ -13194,14 +13345,16 @@ const parseWatchDecorator = (typeChecker, method, decoratorName) => {
|
|
|
13194
13345
|
* @param diagnostics for surfacing errors and warnings
|
|
13195
13346
|
* @param typeChecker a TypeScript typechecker instance
|
|
13196
13347
|
* @param program a {@link ts.Program} object
|
|
13348
|
+
* @param includeClassExpressions also convert `ts.ClassExpression` nodes (e.g. a mixin factory's
|
|
13349
|
+
* `(Base) => class extends Base {}`), not just named `ts.ClassDeclaration`s
|
|
13197
13350
|
* @returns a TypeScript transformer factory which can be passed to
|
|
13198
13351
|
* TypeScript to transform source code during the compilation process
|
|
13199
13352
|
*/
|
|
13200
|
-
const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) => {
|
|
13353
|
+
const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program, includeClassExpressions = false) => {
|
|
13201
13354
|
return (transformCtx) => {
|
|
13202
13355
|
let sourceFile;
|
|
13203
13356
|
const visit = (node) => {
|
|
13204
|
-
if (ts$1.isClassDeclaration(node)) return visitClassDeclaration(config, diagnostics, typeChecker, program, node, sourceFile);
|
|
13357
|
+
if (ts$1.isClassDeclaration(node) || includeClassExpressions && ts$1.isClassExpression(node)) return visitClassDeclaration(config, diagnostics, typeChecker, program, node, sourceFile);
|
|
13205
13358
|
return ts$1.visitEachChild(node, visit, transformCtx);
|
|
13206
13359
|
};
|
|
13207
13360
|
return (tsSourceFile) => {
|
|
@@ -13211,10 +13364,10 @@ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) =>
|
|
|
13211
13364
|
};
|
|
13212
13365
|
};
|
|
13213
13366
|
/**
|
|
13214
|
-
* Visit {@link ts.ClassDeclaration} nodes as part of the tree-traversal
|
|
13367
|
+
* Visit {@link ts.ClassDeclaration}/{@link ts.ClassExpression} nodes as part of the tree-traversal
|
|
13215
13368
|
* required for {@link convertDecoratorsToStatic} to work.
|
|
13216
13369
|
*
|
|
13217
|
-
* If a given class
|
|
13370
|
+
* If a given class node is not decorated with `@Component` this
|
|
13218
13371
|
* function will simply return it as-is. If it _is_ decorated, then it will
|
|
13219
13372
|
*
|
|
13220
13373
|
* 1. Convert the arguments to the `@Component` decorator to static values.
|
|
@@ -13223,7 +13376,7 @@ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) =>
|
|
|
13223
13376
|
* to static values.
|
|
13224
13377
|
* 3. Validate that the various options selected by the component author are
|
|
13225
13378
|
* valid, both individually and in combination.
|
|
13226
|
-
* 4. Return an updated class
|
|
13379
|
+
* 4. Return an updated class node which is ready to be used in
|
|
13227
13380
|
* the rest of the Stencil compilation pipeline (e.g. in output target
|
|
13228
13381
|
* generation).
|
|
13229
13382
|
*
|
|
@@ -13242,7 +13395,7 @@ const visitClassDeclaration = (config, diagnostics, typeChecker, program, classN
|
|
|
13242
13395
|
const decoratedMembers = classMembers.filter((member) => (retrieveTsDecorators(member)?.length ?? 0) > 0);
|
|
13243
13396
|
if (!decoratedMembers.length && !componentDecorator) return classNode;
|
|
13244
13397
|
const filteredMethodsAndFields = removeStencilMethodDecorators(Array.from(classMembers), diagnostics, importAliasMap);
|
|
13245
|
-
if (componentDecorator) componentDecoratorToStatic(config, typeChecker, diagnostics, classNode, filteredMethodsAndFields, componentDecorator);
|
|
13398
|
+
if (componentDecorator && ts$1.isClassDeclaration(classNode)) componentDecoratorToStatic(config, typeChecker, diagnostics, classNode, filteredMethodsAndFields, componentDecorator);
|
|
13246
13399
|
if (decoratedMembers.length > 0) {
|
|
13247
13400
|
const serializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("PropSerialize"), "PropSerialize", importAliasMap.get("Prop"));
|
|
13248
13401
|
const deserializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("AttrDeserialize"), "AttrDeserialize", importAliasMap.get("Prop"));
|
|
@@ -13258,7 +13411,8 @@ const visitClassDeclaration = (config, diagnostics, typeChecker, program, classN
|
|
|
13258
13411
|
validateMethods(diagnostics, classMembers);
|
|
13259
13412
|
const currentDecorators = retrieveTsDecorators(classNode);
|
|
13260
13413
|
const updatedClassFields = updateConstructor(classNode, filteredMethodsAndFields, []);
|
|
13261
|
-
|
|
13414
|
+
const updatedModifiers = [...filterDecorators(currentDecorators, CLASS_DECORATORS_TO_REMOVE.map((decorator) => importAliasMap.get(decorator))) ?? [], ...retrieveTsModifiers(classNode) ?? []];
|
|
13415
|
+
return ts$1.isClassDeclaration(classNode) ? ts$1.factory.updateClassDeclaration(classNode, updatedModifiers, classNode.name, classNode.typeParameters, classNode.heritageClauses, updatedClassFields) : ts$1.factory.updateClassExpression(classNode, updatedModifiers, classNode.name, classNode.typeParameters, classNode.heritageClauses, updatedClassFields);
|
|
13262
13416
|
};
|
|
13263
13417
|
/**
|
|
13264
13418
|
* Take a list of `ClassElement` AST nodes and remove any decorators from
|
|
@@ -13524,12 +13678,18 @@ const gatherVdomMeta = (m, args, typeChecker) => {
|
|
|
13524
13678
|
};
|
|
13525
13679
|
//#endregion
|
|
13526
13680
|
//#region src/compiler/transformers/static-to-meta/call-expression.ts
|
|
13527
|
-
|
|
13681
|
+
/**
|
|
13682
|
+
* @param m the module or component to record vdom metadata on
|
|
13683
|
+
* @param node the call expression to parse
|
|
13684
|
+
* @param typeChecker used to resolve functional components / JSX-returning calls to their source
|
|
13685
|
+
* @param moduleFile the module to record those dependencies on; defaults to `m` when it's a module
|
|
13686
|
+
*/
|
|
13687
|
+
const parseCallExpression = (m, node, typeChecker, moduleFile = "functionalComponentDeps" in m ? m : void 0) => {
|
|
13528
13688
|
if (node.arguments != null && node.arguments.length > 0) {
|
|
13529
|
-
if (ts$1.isIdentifier(node.expression)) visitCallExpressionArgs(m, node.expression, node.arguments, typeChecker);
|
|
13689
|
+
if (ts$1.isIdentifier(node.expression)) visitCallExpressionArgs(m, node.expression, node.arguments, typeChecker, moduleFile);
|
|
13530
13690
|
else if (ts$1.isPropertyAccessExpression(node.expression)) {
|
|
13531
13691
|
const n = node.expression.name;
|
|
13532
|
-
if (ts$1.isIdentifier(n) && n) visitCallExpressionArgs(m, n, node.arguments, typeChecker);
|
|
13692
|
+
if (ts$1.isIdentifier(n) && n) visitCallExpressionArgs(m, n, node.arguments, typeChecker, moduleFile);
|
|
13533
13693
|
}
|
|
13534
13694
|
} else if (ts$1.isPropertyAccessExpression(node.expression)) {
|
|
13535
13695
|
if (ts$1.isIdentifier(node.expression.name)) {
|
|
@@ -13539,24 +13699,20 @@ const parseCallExpression = (m, node, typeChecker) => {
|
|
|
13539
13699
|
if (!declarations || declarations.length === 0) return;
|
|
13540
13700
|
const sourceFile = declarations[0].getSourceFile();
|
|
13541
13701
|
if (!sourceFile) return;
|
|
13542
|
-
|
|
13543
|
-
const moduleFile = m;
|
|
13544
|
-
if (moduleFile.functionalComponentDeps) {
|
|
13545
|
-
if (!moduleFile.functionalComponentDeps.includes(sourceFilePath)) moduleFile.functionalComponentDeps.push(sourceFilePath);
|
|
13546
|
-
}
|
|
13702
|
+
addFunctionalComponentDep(moduleFile, sourceFile);
|
|
13547
13703
|
}
|
|
13548
13704
|
}
|
|
13549
13705
|
};
|
|
13550
|
-
const visitCallExpressionArgs = (m, callExpressionName, args, typeChecker) => {
|
|
13706
|
+
const visitCallExpressionArgs = (m, callExpressionName, args, typeChecker, moduleFile) => {
|
|
13551
13707
|
const fnName = callExpressionName.escapedText;
|
|
13552
13708
|
if (fnName === "h" || fnName === "__stencil_h" || fnName === "createElement") {
|
|
13553
|
-
visitCallExpressionArg(m, args[0], typeChecker);
|
|
13709
|
+
visitCallExpressionArg(m, args[0], typeChecker, moduleFile);
|
|
13554
13710
|
if (fnName === "h" || fnName === "__stencil_h") gatherVdomMeta(m, args, typeChecker);
|
|
13555
13711
|
} else if (fnName === "jsx" || fnName === "jsxs" || fnName === "_jsx" || fnName === "_jsxs") {
|
|
13556
|
-
visitCallExpressionArg(m, args[0], typeChecker);
|
|
13712
|
+
visitCallExpressionArg(m, args[0], typeChecker, moduleFile);
|
|
13557
13713
|
gatherVdomMeta(m, args, typeChecker);
|
|
13558
13714
|
if (args.length > 2 && args[2]) m.hasVdomKey = true;
|
|
13559
|
-
} else if (args.length > 1 && fnName === "createElementNS") visitCallExpressionArg(m, args[1], typeChecker);
|
|
13715
|
+
} else if (args.length > 1 && fnName === "createElementNS") visitCallExpressionArg(m, args[1], typeChecker, moduleFile);
|
|
13560
13716
|
else if (fnName === "require" && args.length > 0 && m.originalImports) {
|
|
13561
13717
|
const arg = args[0];
|
|
13562
13718
|
if (ts$1.isStringLiteral(arg)) {
|
|
@@ -13564,7 +13720,7 @@ const visitCallExpressionArgs = (m, callExpressionName, args, typeChecker) => {
|
|
|
13564
13720
|
}
|
|
13565
13721
|
}
|
|
13566
13722
|
};
|
|
13567
|
-
const visitCallExpressionArg = (m, arg, typeChecker) => {
|
|
13723
|
+
const visitCallExpressionArg = (m, arg, typeChecker, moduleFile) => {
|
|
13568
13724
|
if (ts$1.isStringLiteral(arg)) {
|
|
13569
13725
|
let tag = arg.text;
|
|
13570
13726
|
if (typeof tag === "string") {
|
|
@@ -13572,31 +13728,31 @@ const visitCallExpressionArg = (m, arg, typeChecker) => {
|
|
|
13572
13728
|
m.htmlTagNames.push(tag);
|
|
13573
13729
|
if (tag.includes("-")) m.potentialCmpRefs.push(tag);
|
|
13574
13730
|
}
|
|
13575
|
-
} else if (typeChecker && ts$1.isIdentifier(arg)) resolveFunctionalComponentDep(
|
|
13731
|
+
} else if (typeChecker && ts$1.isIdentifier(arg)) resolveFunctionalComponentDep(moduleFile, arg, typeChecker);
|
|
13576
13732
|
};
|
|
13577
13733
|
/**
|
|
13578
13734
|
* Resolves a functional component identifier to its source file and tracks it
|
|
13579
13735
|
* as a dependency so that build-conditionals can be properly propagated.
|
|
13736
|
+
* Follows import / re-export aliases through to the declaring file.
|
|
13580
13737
|
*
|
|
13581
|
-
* @param
|
|
13738
|
+
* @param moduleFile the module to track the dependency on
|
|
13582
13739
|
* @param identifier the identifier node representing the functional component
|
|
13583
13740
|
* @param typeChecker the TypeScript type checker for symbol resolution
|
|
13584
13741
|
*/
|
|
13585
|
-
const resolveFunctionalComponentDep = (
|
|
13742
|
+
const resolveFunctionalComponentDep = (moduleFile, identifier, typeChecker) => {
|
|
13743
|
+
if (!moduleFile) return;
|
|
13586
13744
|
try {
|
|
13587
13745
|
const symbol = typeChecker.getSymbolAtLocation(identifier);
|
|
13588
13746
|
if (!symbol) return;
|
|
13589
|
-
const
|
|
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
|
-
}
|
|
13747
|
+
const sourceFile = (symbol.flags & ts$1.SymbolFlags.Alias ? typeChecker.getAliasedSymbol(symbol) : symbol).declarations?.[0]?.getSourceFile();
|
|
13748
|
+
if (sourceFile) addFunctionalComponentDep(moduleFile, sourceFile);
|
|
13598
13749
|
} catch {}
|
|
13599
13750
|
};
|
|
13751
|
+
const addFunctionalComponentDep = (moduleFile, sourceFile) => {
|
|
13752
|
+
const deps = moduleFile?.functionalComponentDeps;
|
|
13753
|
+
const sourceFilePath = normalizePath(sourceFile.fileName);
|
|
13754
|
+
if (deps && !deps.includes(sourceFilePath)) deps.push(sourceFilePath);
|
|
13755
|
+
};
|
|
13600
13756
|
//#endregion
|
|
13601
13757
|
//#region src/compiler/transformers/component-build-conditionals.ts
|
|
13602
13758
|
const setComponentBuildConditionals = (cmpMeta) => {
|
|
@@ -13869,11 +14025,11 @@ const parseStaticWatchers = (staticMembers) => {
|
|
|
13869
14025
|
//#endregion
|
|
13870
14026
|
//#region src/compiler/transformers/static-to-meta/class-extension/shared.ts
|
|
13871
14027
|
/**
|
|
13872
|
-
* Warns when an `extends`/`Mixin(...)` target resolved to *something* but no class
|
|
13873
|
-
* could be found inside it - e.g. a mixin factory
|
|
13874
|
-
* (`(Base) =>
|
|
13875
|
-
*
|
|
13876
|
-
*
|
|
14028
|
+
* Warns when an `extends`/`Mixin(...)` target resolved to *something* but no class literal
|
|
14029
|
+
* could be found inside it - e.g. a mixin factory that returns an existing class by reference
|
|
14030
|
+
* (`(Base) => SomeExistingClass`) rather than a class literal. Without this, the target is
|
|
14031
|
+
* silently dropped: any `@Prop`/`@State` etc. it declares just never appears on the extending
|
|
14032
|
+
* component, with no diagnostic explaining why.
|
|
13877
14033
|
* @param buildCtx used to surface the warning - omit to warn silently (e.g. from tests)
|
|
13878
14034
|
* @param targetName the identifier the target was reached through
|
|
13879
14035
|
* @param anchor the node to attach the warning to
|
|
@@ -13881,27 +14037,32 @@ const parseStaticWatchers = (staticMembers) => {
|
|
|
13881
14037
|
function warnMixinFactoryClassNotFound(buildCtx, targetName, anchor) {
|
|
13882
14038
|
if (!buildCtx) return;
|
|
13883
14039
|
const err = buildWarn(buildCtx.diagnostics);
|
|
13884
|
-
err.messageText = `Found "${targetName}", but couldn't find a class
|
|
14040
|
+
err.messageText = `Found "${targetName}", but couldn't find a class inside it. If it's meant to be a mixin factory, make sure it returns a class literal directly, e.g. \`(Base) => class extends Base {}\` or \`(Base) => { class ${targetName}Class extends Base {} return ${targetName}Class; }\` - returning an existing class by reference (\`(Base) => SomeExistingClass\`) isn't recognized, and any \`@Prop\`/\`@State\`/etc. it declares won't be applied.`;
|
|
13885
14041
|
if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, anchor);
|
|
13886
14042
|
}
|
|
13887
14043
|
/**
|
|
13888
|
-
* Walks the AST looking for a class declaration, optionally by name -
|
|
13889
|
-
* into a mixin factory's wrapping function (arrow function or `function`
|
|
13890
|
-
*
|
|
13891
|
-
*
|
|
14044
|
+
* Walks the AST looking for a class declaration or class expression, optionally by name -
|
|
14045
|
+
* descends into a mixin factory's wrapping function (arrow function or `function` declaration)
|
|
14046
|
+
* body too, since a mixin factory's class is always nested one level inside it. Recognizes all of:
|
|
14047
|
+
* `const Foo = (Base) => class extends Base {}` (concise arrow body), `const Foo = (Base) => {
|
|
14048
|
+
* return class extends Base {}; }` (block body, `return` of a class expression), and `const Foo =
|
|
14049
|
+
* (Base) => { class FooClass extends Base {} return FooClass; }` (block body, named declaration).
|
|
13892
14050
|
* @param node the node to search from
|
|
13893
|
-
* @param name if given, only matches a class
|
|
13894
|
-
* @returns the found class
|
|
14051
|
+
* @param name if given, only matches a class with this name
|
|
14052
|
+
* @returns the found class, or `undefined`
|
|
13895
14053
|
*/
|
|
13896
14054
|
function findClassWalk(node, name) {
|
|
13897
14055
|
if (!node) return void 0;
|
|
13898
|
-
if (ts$1.isClassDeclaration(node)) {
|
|
14056
|
+
if (ts$1.isClassDeclaration(node) || ts$1.isClassExpression(node)) {
|
|
13899
14057
|
if (!name || node.name?.text === name) return node;
|
|
13900
14058
|
} else if (ts$1.isVariableDeclaration(node) && (!name || name === node.name?.text) && node.initializer && ts$1.isArrowFunction(node.initializer)) {
|
|
14059
|
+
const body = node.initializer.body;
|
|
14060
|
+
if (ts$1.isClassExpression(body)) return body;
|
|
13901
14061
|
let found;
|
|
13902
|
-
ts$1.forEachChild(
|
|
14062
|
+
ts$1.forEachChild(body, (child) => {
|
|
13903
14063
|
if (found) return;
|
|
13904
14064
|
if (ts$1.isClassDeclaration(child)) found = child;
|
|
14065
|
+
else if (ts$1.isReturnStatement(child) && child.expression && ts$1.isClassExpression(child.expression)) found = child.expression;
|
|
13905
14066
|
});
|
|
13906
14067
|
return found;
|
|
13907
14068
|
}
|
|
@@ -13914,6 +14075,22 @@ function findClassWalk(node, name) {
|
|
|
13914
14075
|
return found;
|
|
13915
14076
|
}
|
|
13916
14077
|
/**
|
|
14078
|
+
* The declared name of a mixin-factory statement (`function Foo() {}`, or `const Foo = ...`) -
|
|
14079
|
+
* survives the decorator-to-static-getter transform even when the factory's inner class doesn't
|
|
14080
|
+
* have a name of its own, so it can anchor a post-transform re-lookup via `findClassWalk`.
|
|
14081
|
+
* @param node the factory statement (or its variable declaration) to read a name from
|
|
14082
|
+
* @returns the declared name, or `undefined` if it can't be determined
|
|
14083
|
+
*/
|
|
14084
|
+
function factoryDeclaredName(node) {
|
|
14085
|
+
if (!node) return void 0;
|
|
14086
|
+
if (ts$1.isFunctionDeclaration(node)) return node.name?.text;
|
|
14087
|
+
if (ts$1.isVariableDeclaration(node)) return ts$1.isIdentifier(node.name) ? node.name.text : void 0;
|
|
14088
|
+
if (ts$1.isVariableStatement(node)) {
|
|
14089
|
+
const decl = node.declarationList.declarations[0];
|
|
14090
|
+
return decl && ts$1.isIdentifier(decl.name) ? decl.name.text : void 0;
|
|
14091
|
+
}
|
|
14092
|
+
}
|
|
14093
|
+
/**
|
|
13917
14094
|
* Matches a top-level class/function/variable declaration by name - the three
|
|
13918
14095
|
* shapes a mixin or base-class export can take (a plain class, a mixin
|
|
13919
14096
|
* factory function declaration, or a mixin factory assigned to a `const`).
|
|
@@ -13931,22 +14108,173 @@ function matchesNamedDeclaration(name) {
|
|
|
13931
14108
|
};
|
|
13932
14109
|
}
|
|
13933
14110
|
/**
|
|
13934
|
-
* Finds a re-export of `className` in `sourceFile
|
|
13935
|
-
* `
|
|
13936
|
-
* public `index.d.mts`, which re-exports its runtime API from `./declarations/stencil-public-runtime`
|
|
13937
|
-
* rather than declaring it directly).
|
|
14111
|
+
* Finds a re-export of `className` in `sourceFile`: `export { X } from './y'`, or the
|
|
14112
|
+
* bundler-split shape `import { X as name } from './y'; export { name };` (no `from` clause).
|
|
13938
14113
|
* @param sourceFile the (barrel) source file to scan
|
|
13939
14114
|
* @param className the exported name to look for
|
|
13940
|
-
* @returns the module specifier and
|
|
13941
|
-
*
|
|
14115
|
+
* @returns the module specifier and name to look for there (before any `as` aliasing), or
|
|
14116
|
+
* `undefined` if not found
|
|
13942
14117
|
*/
|
|
13943
14118
|
function findReExport(sourceFile, className) {
|
|
13944
14119
|
for (const stmt of sourceFile.statements) {
|
|
13945
|
-
if (!ts$1.isExportDeclaration(stmt) || !stmt.
|
|
13946
|
-
|
|
14120
|
+
if (!ts$1.isExportDeclaration(stmt) || !stmt.exportClause || !ts$1.isNamedExports(stmt.exportClause)) continue;
|
|
14121
|
+
const element = stmt.exportClause.elements.find((el) => el.name.text === className);
|
|
14122
|
+
if (!element) continue;
|
|
14123
|
+
if (stmt.moduleSpecifier && ts$1.isStringLiteral(stmt.moduleSpecifier)) return {
|
|
13947
14124
|
moduleSpecifier: stmt.moduleSpecifier.text,
|
|
13948
14125
|
localName: element.propertyName?.text ?? element.name.text
|
|
13949
14126
|
};
|
|
14127
|
+
const importOrigin = findImportOrigin(sourceFile, element.propertyName?.text ?? element.name.text);
|
|
14128
|
+
if (importOrigin) return importOrigin;
|
|
14129
|
+
}
|
|
14130
|
+
}
|
|
14131
|
+
/**
|
|
14132
|
+
* @param sourceFile the (barrel) source file to scan
|
|
14133
|
+
* @returns the module specifiers of its `export * from './x'` statements, in order
|
|
14134
|
+
*/
|
|
14135
|
+
function findStarReExportSpecifiers(sourceFile) {
|
|
14136
|
+
return sourceFile.statements.flatMap((stmt) => ts$1.isExportDeclaration(stmt) && !stmt.exportClause && !stmt.isTypeOnly && stmt.moduleSpecifier && ts$1.isStringLiteral(stmt.moduleSpecifier) ? [stmt.moduleSpecifier.text] : []);
|
|
14137
|
+
}
|
|
14138
|
+
/**
|
|
14139
|
+
* Finds `name`'s import in `sourceFile` and returns its module and origin name (before any `as`
|
|
14140
|
+
* aliasing; `'default'` for a default import).
|
|
14141
|
+
* @param sourceFile the source file to scan for a matching import
|
|
14142
|
+
* @param name the local (post-aliasing) name an import bound
|
|
14143
|
+
* @returns the import's module specifier and origin name, or `undefined` if `name` isn't imported
|
|
14144
|
+
*/
|
|
14145
|
+
function findImportOrigin(sourceFile, name) {
|
|
14146
|
+
for (const stmt of sourceFile.statements) {
|
|
14147
|
+
if (!ts$1.isImportDeclaration(stmt) || !stmt.importClause || !ts$1.isStringLiteral(stmt.moduleSpecifier)) continue;
|
|
14148
|
+
const moduleSpecifier = stmt.moduleSpecifier.text;
|
|
14149
|
+
if (stmt.importClause.name?.text === name) return {
|
|
14150
|
+
moduleSpecifier,
|
|
14151
|
+
localName: "default"
|
|
14152
|
+
};
|
|
14153
|
+
const bindings = stmt.importClause.namedBindings;
|
|
14154
|
+
if (!bindings || !ts$1.isNamedImports(bindings)) continue;
|
|
14155
|
+
const element = bindings.elements.find((el) => el.name.text === name);
|
|
14156
|
+
if (element) return {
|
|
14157
|
+
moduleSpecifier,
|
|
14158
|
+
localName: element.propertyName?.text ?? element.name.text
|
|
14159
|
+
};
|
|
14160
|
+
}
|
|
14161
|
+
}
|
|
14162
|
+
/**
|
|
14163
|
+
* Finds `name` as a top-level declaration in `sf` (see `matchesNamedDeclaration`), following a
|
|
14164
|
+
* same-file export alias if `name` is only ever the public side of a local rename
|
|
14165
|
+
* (`export { RealName as name }`, no `from` clause).
|
|
14166
|
+
* @param sf the source file to search
|
|
14167
|
+
* @param name the declaration name to look for, which may only exist as an export alias
|
|
14168
|
+
* @returns the matched statement, or `undefined`
|
|
14169
|
+
*/
|
|
14170
|
+
function findStatementByName(sf, name) {
|
|
14171
|
+
const direct = sf.statements.find(matchesNamedDeclaration(name));
|
|
14172
|
+
if (direct) return direct;
|
|
14173
|
+
for (const stmt of sf.statements) {
|
|
14174
|
+
if (!ts$1.isExportDeclaration(stmt) || stmt.moduleSpecifier || !stmt.exportClause || !ts$1.isNamedExports(stmt.exportClause)) continue;
|
|
14175
|
+
const aliasedName = stmt.exportClause.elements.find((el) => el.name.text === name)?.propertyName?.text;
|
|
14176
|
+
if (aliasedName && aliasedName !== name) return sf.statements.find(matchesNamedDeclaration(aliasedName));
|
|
14177
|
+
}
|
|
14178
|
+
}
|
|
14179
|
+
/**
|
|
14180
|
+
* Picks the runtime target out of a `package.json` `exports` condition entry - prefers `import`
|
|
14181
|
+
* over `require`/`node`/`default`, recursing into nested condition objects.
|
|
14182
|
+
* @param entry an `exports` map value: a path string, or nested conditions
|
|
14183
|
+
* @returns the resolved relative path, or `undefined` if no usable condition was found
|
|
14184
|
+
*/
|
|
14185
|
+
function pickJsCondition(entry) {
|
|
14186
|
+
if (typeof entry === "string") return entry;
|
|
14187
|
+
if (typeof entry !== "object" || entry === null) return;
|
|
14188
|
+
const conditions = entry;
|
|
14189
|
+
for (const key of [
|
|
14190
|
+
"import",
|
|
14191
|
+
"require",
|
|
14192
|
+
"node",
|
|
14193
|
+
"default"
|
|
14194
|
+
]) if (key in conditions) {
|
|
14195
|
+
const picked = pickJsCondition(conditions[key]);
|
|
14196
|
+
if (picked) return picked;
|
|
14197
|
+
}
|
|
14198
|
+
}
|
|
14199
|
+
/**
|
|
14200
|
+
* Reads and parses `filePath` as JS, with parent nodes set - unlike `tsGetSourceFile`, which
|
|
14201
|
+
* never triggers binding, so `.parent` stays unset and `node.getSourceFile()` returns `undefined`.
|
|
14202
|
+
* @param config the current Stencil validated config
|
|
14203
|
+
* @param filePath the absolute path of the JS file to read and parse
|
|
14204
|
+
* @returns the parsed source file, or `undefined` if it couldn't be read
|
|
14205
|
+
*/
|
|
14206
|
+
function readJsSourceFile(config, filePath) {
|
|
14207
|
+
try {
|
|
14208
|
+
const text = config.sys.readFileSync(filePath);
|
|
14209
|
+
if (typeof text !== "string") return;
|
|
14210
|
+
return ts$1.createSourceFile(filePath, text, ts$1.ScriptTarget.ESNext, true, ts$1.ScriptKind.JS);
|
|
14211
|
+
} catch {
|
|
14212
|
+
return;
|
|
14213
|
+
}
|
|
14214
|
+
}
|
|
14215
|
+
/**
|
|
14216
|
+
* Resolves the runtime JS entry for a bare (non-relative) module specifier by reading its
|
|
14217
|
+
* package's own `package.json` `exports` map, instead of `tsResolveModuleName` - which always
|
|
14218
|
+
* resolves to the package's `types` entry, an ambient signature with no body a mixin factory's
|
|
14219
|
+
* class can never be found inside.
|
|
14220
|
+
* @param config the current Stencil validated config
|
|
14221
|
+
* @param compilerCtx the current compiler context
|
|
14222
|
+
* @param moduleSpecifier the bare package specifier to resolve
|
|
14223
|
+
* @param containingFile the file the specifier was imported from
|
|
14224
|
+
* @returns the resolved JS source file, or `undefined` if it couldn't be resolved this way
|
|
14225
|
+
*/
|
|
14226
|
+
function resolveModuleJsEntry(config, compilerCtx, moduleSpecifier, containingFile) {
|
|
14227
|
+
if (isLocalModule(moduleSpecifier)) return;
|
|
14228
|
+
const pkgJsonPath = tsResolveModuleNamePackageJsonPath(config, compilerCtx, moduleSpecifier, containingFile);
|
|
14229
|
+
if (!pkgJsonPath) return;
|
|
14230
|
+
let pkgJson;
|
|
14231
|
+
try {
|
|
14232
|
+
pkgJson = JSON.parse(config.sys.readFileSync(pkgJsonPath));
|
|
14233
|
+
} catch {
|
|
14234
|
+
return;
|
|
14235
|
+
}
|
|
14236
|
+
const pkgName = pkgJson.name;
|
|
14237
|
+
if (!pkgName || !moduleSpecifier.startsWith(pkgName) || !pkgJson.exports) return;
|
|
14238
|
+
const subpath = moduleSpecifier === pkgName ? "." : `.${moduleSpecifier.slice(pkgName.length)}`;
|
|
14239
|
+
const exportsMap = pkgJson.exports;
|
|
14240
|
+
const conditionEntry = typeof exportsMap === "string" ? subpath === "." ? exportsMap : void 0 : exportsMap[subpath] ?? (subpath === "." ? exportsMap : void 0);
|
|
14241
|
+
const target = conditionEntry && pickJsCondition(conditionEntry);
|
|
14242
|
+
if (!target) return;
|
|
14243
|
+
return readJsSourceFile(config, normalizePath(join$1(dirname(pkgJsonPath), target)));
|
|
14244
|
+
}
|
|
14245
|
+
/**
|
|
14246
|
+
* Finds `className`'s class inside a resolved JS entry (see `resolveModuleJsEntry`), following
|
|
14247
|
+
* re-export hops the same way `resolveAndProcessExtendedClass` walks a `.d.ts`/`.ts` source.
|
|
14248
|
+
* @param config the current Stencil validated config
|
|
14249
|
+
* @param compilerCtx the current compiler context
|
|
14250
|
+
* @param source the JS source file to search
|
|
14251
|
+
* @param className the class (or mixin factory) name to look for
|
|
14252
|
+
* @param hopsRemaining re-export hops still allowed before giving up
|
|
14253
|
+
* @returns the found class and the source file it's declared in, or `undefined`
|
|
14254
|
+
*/
|
|
14255
|
+
function findClassInJsModule(config, compilerCtx, source, className, hopsRemaining = 3) {
|
|
14256
|
+
const matchedStatement = findStatementByName(source, className);
|
|
14257
|
+
if (matchedStatement) {
|
|
14258
|
+
const classNode = ts$1.isClassDeclaration(matchedStatement) ? matchedStatement : findClassWalk(matchedStatement);
|
|
14259
|
+
return classNode && {
|
|
14260
|
+
classNode,
|
|
14261
|
+
sourceFile: source
|
|
14262
|
+
};
|
|
14263
|
+
}
|
|
14264
|
+
if (hopsRemaining <= 0) return;
|
|
14265
|
+
const readReExported = (moduleSpecifier) => {
|
|
14266
|
+
const resolvedFileName = tsResolveModuleName(config, compilerCtx, moduleSpecifier, source.fileName)?.resolvedModule?.resolvedFileName;
|
|
14267
|
+
return resolvedFileName ? readJsSourceFile(config, resolvedFileName) : void 0;
|
|
14268
|
+
};
|
|
14269
|
+
const reExport = findReExport(source, className);
|
|
14270
|
+
if (reExport) {
|
|
14271
|
+
const nextSource = readReExported(reExport.moduleSpecifier);
|
|
14272
|
+
return nextSource && findClassInJsModule(config, compilerCtx, nextSource, reExport.localName, hopsRemaining - 1);
|
|
14273
|
+
}
|
|
14274
|
+
for (const moduleSpecifier of findStarReExportSpecifiers(source)) {
|
|
14275
|
+
const nextSource = readReExported(moduleSpecifier);
|
|
14276
|
+
const found = nextSource && findClassInJsModule(config, compilerCtx, nextSource, className, hopsRemaining - 1);
|
|
14277
|
+
if (found) return found;
|
|
13950
14278
|
}
|
|
13951
14279
|
}
|
|
13952
14280
|
/**
|
|
@@ -14035,14 +14363,15 @@ function convertDiskSourceFileDecorators(sourceFile, config, target = ts$1.Scrip
|
|
|
14035
14363
|
const program = ts$1.createProgram([sourceFile.fileName], compilerOptions, host);
|
|
14036
14364
|
const typeChecker = program.getTypeChecker();
|
|
14037
14365
|
const ownSourceFile = program.getSourceFile(sourceFile.fileName) ?? sourceFile;
|
|
14038
|
-
const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program)]);
|
|
14366
|
+
const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program, true)]);
|
|
14039
14367
|
const printed = ts$1.createPrinter({ removeComments: false }).printFile(result.transformed[0]);
|
|
14040
14368
|
return ts$1.createSourceFile(sourceFile.fileName, printed, target, true);
|
|
14041
14369
|
}
|
|
14042
14370
|
/**
|
|
14043
14371
|
* Resolves an `extends` target through a module specifier: resolves the
|
|
14044
14372
|
* module, finds the named class/mixin-factory export, and adds it (and its
|
|
14045
|
-
* own ancestors) to `dependentClasses`. Follows one level of re-export (barrel file
|
|
14373
|
+
* own ancestors) to `dependentClasses`. Follows one level of re-export (barrel file, named or
|
|
14374
|
+
* `export *`) when the
|
|
14046
14375
|
* declaration isn't found directly in the resolved module.
|
|
14047
14376
|
* @param compilerCtx the current compiler context
|
|
14048
14377
|
* @param buildCtx the current build context
|
|
@@ -14055,13 +14384,17 @@ function convertDiskSourceFileDecorators(sourceFile, config, target = ts$1.Scrip
|
|
|
14055
14384
|
* @param ogModule the original module file of the class declaration
|
|
14056
14385
|
* @param targetScriptTarget the script target to convert decorators with, if needed
|
|
14057
14386
|
* @param barrelHopsRemaining re-export hops still allowed before giving up
|
|
14387
|
+
* @param originalModuleSpecifier the specifier this lookup started from, before any barrel hops
|
|
14388
|
+
* @param originalContainingFile the file `originalModuleSpecifier` was imported from
|
|
14058
14389
|
* @returns the found class declaration, or `undefined`
|
|
14059
14390
|
*/
|
|
14060
|
-
function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, currentSource, moduleSpecifier, className, dependentClasses, typeChecker, ogModule, targetScriptTarget = ts$1.ScriptTarget.ESNext, barrelHopsRemaining = 1) {
|
|
14391
|
+
function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, currentSource, moduleSpecifier, className, dependentClasses, typeChecker, ogModule, targetScriptTarget = ts$1.ScriptTarget.ESNext, barrelHopsRemaining = 1, originalModuleSpecifier = moduleSpecifier, originalContainingFile = currentSource.fileName) {
|
|
14061
14392
|
let keepLooking = true;
|
|
14062
14393
|
const foundFile = tsResolveModuleName(buildCtx.config, compilerCtx, moduleSpecifier, currentSource.fileName);
|
|
14063
14394
|
if (!foundFile?.resolvedModule || !className) return;
|
|
14064
|
-
|
|
14395
|
+
const resolvedFileName = foundFile.resolvedModule.resolvedFileName;
|
|
14396
|
+
let foundSource = compilerCtx.moduleMap.get(resolvedFileName)?.staticSourceFile;
|
|
14397
|
+
if (!foundSource && isJsFile(currentSource.fileName) && isJsFile(resolvedFileName)) foundSource = readJsSourceFile(buildCtx.config, resolvedFileName);
|
|
14065
14398
|
if (!foundSource) {
|
|
14066
14399
|
foundSource = tsGetSourceFile(buildCtx.config, foundFile);
|
|
14067
14400
|
if (!foundSource) {
|
|
@@ -14073,10 +14406,10 @@ function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration,
|
|
|
14073
14406
|
}
|
|
14074
14407
|
foundSource = convertDiskSourceFileDecorators(foundSource, buildCtx.config, targetScriptTarget);
|
|
14075
14408
|
}
|
|
14076
|
-
const matchedStatement = foundSource
|
|
14409
|
+
const matchedStatement = findStatementByName(foundSource, className);
|
|
14077
14410
|
if (!matchedStatement) {
|
|
14078
|
-
const reExport = barrelHopsRemaining > 0 ? findReExport(foundSource, className) : void 0;
|
|
14079
|
-
if (reExport) return resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, foundSource, reExport.moduleSpecifier, reExport.localName, dependentClasses, typeChecker, ogModule, targetScriptTarget, barrelHopsRemaining - 1);
|
|
14411
|
+
const reExport = barrelHopsRemaining > 0 ? findReExport(foundSource, className) ?? findStarReExportOf(buildCtx.config, compilerCtx, foundSource, className) : void 0;
|
|
14412
|
+
if (reExport) return resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration, foundSource, reExport.moduleSpecifier, reExport.localName, dependentClasses, typeChecker, ogModule, targetScriptTarget, barrelHopsRemaining - 1, originalModuleSpecifier, originalContainingFile);
|
|
14080
14413
|
const err = buildWarn(buildCtx.diagnostics);
|
|
14081
14414
|
err.messageText = `Unable to find "${className}" in the imported module "${moduleSpecifier}".
|
|
14082
14415
|
Please import class / mixin-factory declarations directly and not via barrel files.`;
|
|
@@ -14084,21 +14417,61 @@ function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration,
|
|
|
14084
14417
|
return;
|
|
14085
14418
|
}
|
|
14086
14419
|
let foundClassDeclaration = matchedStatement ? ts$1.isClassDeclaration(matchedStatement) ? matchedStatement : void 0 : void 0;
|
|
14087
|
-
|
|
14420
|
+
let foundClassSource = foundSource;
|
|
14421
|
+
const findInJsEntry = () => {
|
|
14422
|
+
if (!isDtsFile(foundSource.fileName) || isLocalModule(originalModuleSpecifier)) return;
|
|
14423
|
+
const jsSource = resolveModuleJsEntry(buildCtx.config, compilerCtx, originalModuleSpecifier, originalContainingFile);
|
|
14424
|
+
return jsSource && findClassInJsModule(buildCtx.config, compilerCtx, jsSource, className);
|
|
14425
|
+
};
|
|
14426
|
+
if (foundClassDeclaration) {
|
|
14427
|
+
const foundInJs = findInJsEntry();
|
|
14428
|
+
if (foundInJs) {
|
|
14429
|
+
foundClassDeclaration = foundInJs.classNode;
|
|
14430
|
+
foundClassSource = foundInJs.sourceFile;
|
|
14431
|
+
}
|
|
14432
|
+
} else if (matchedStatement) {
|
|
14088
14433
|
foundClassDeclaration = findClassWalk(matchedStatement);
|
|
14089
14434
|
keepLooking = false;
|
|
14435
|
+
if (!foundClassDeclaration) {
|
|
14436
|
+
const foundInJs = findInJsEntry();
|
|
14437
|
+
if (foundInJs) {
|
|
14438
|
+
foundClassDeclaration = foundInJs.classNode;
|
|
14439
|
+
foundClassSource = foundInJs.sourceFile;
|
|
14440
|
+
}
|
|
14441
|
+
}
|
|
14090
14442
|
if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, className, classDeclaration);
|
|
14091
14443
|
}
|
|
14092
14444
|
if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {
|
|
14093
14445
|
dependentClasses.push({
|
|
14094
14446
|
classNode: foundClassDeclaration,
|
|
14095
|
-
sourceFile:
|
|
14096
|
-
fileName:
|
|
14447
|
+
sourceFile: foundClassSource,
|
|
14448
|
+
fileName: foundClassSource.fileName
|
|
14097
14449
|
});
|
|
14098
14450
|
if (keepLooking) buildExtendsTree(compilerCtx, foundClassDeclaration, dependentClasses, typeChecker, buildCtx, ogModule);
|
|
14099
14451
|
}
|
|
14100
14452
|
return foundClassDeclaration;
|
|
14101
14453
|
}
|
|
14454
|
+
/**
|
|
14455
|
+
* Finds the first `export * from './x'` in `barrel` whose target declares `className` directly.
|
|
14456
|
+
* @param config the current Stencil validated config
|
|
14457
|
+
* @param compilerCtx the current compiler context
|
|
14458
|
+
* @param barrel the source file to scan
|
|
14459
|
+
* @param className the declaration name to look for
|
|
14460
|
+
* @returns the re-export to follow, in `findReExport`'s shape, or `undefined`
|
|
14461
|
+
*/
|
|
14462
|
+
function findStarReExportOf(config, compilerCtx, barrel, className) {
|
|
14463
|
+
for (const moduleSpecifier of findStarReExportSpecifiers(barrel)) {
|
|
14464
|
+
const resolved = tsResolveModuleName(config, compilerCtx, moduleSpecifier, barrel.fileName);
|
|
14465
|
+
const fileName = resolved?.resolvedModule?.resolvedFileName;
|
|
14466
|
+
if (!fileName) continue;
|
|
14467
|
+
const target = compilerCtx.moduleMap.get(fileName)?.staticSourceFile ?? (isJsFile(fileName) ? readJsSourceFile(config, fileName) : tsGetSourceFile(config, resolved));
|
|
14468
|
+
if (target && findStatementByName(target, className)) return {
|
|
14469
|
+
moduleSpecifier,
|
|
14470
|
+
localName: className
|
|
14471
|
+
};
|
|
14472
|
+
}
|
|
14473
|
+
}
|
|
14474
|
+
const isJsFile = (fileName) => /\.[cm]?js$/.test(fileName);
|
|
14102
14475
|
function convertDtsToJs(declarationSourceFile, compilerCtx) {
|
|
14103
14476
|
const jsPath = normalizePath(declarationSourceFile.replace(/\.d\.ts$/, ".js").replace("/types/", "/collection/"));
|
|
14104
14477
|
return compilerCtx.moduleMap.get(jsPath)?.staticSourceFile;
|
|
@@ -14122,6 +14495,7 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
|
|
|
14122
14495
|
const targetScriptTarget = (ogModule?.staticSourceFile)?.languageVersion ?? ts$1.ScriptTarget.ESNext;
|
|
14123
14496
|
let classIdentifiers = [];
|
|
14124
14497
|
let foundClassDeclaration;
|
|
14498
|
+
let foundClassName;
|
|
14125
14499
|
let keepLooking = true;
|
|
14126
14500
|
extendsClause.types.forEach((type) => {
|
|
14127
14501
|
if (ts$1.isExpressionWithTypeArguments(type) && ts$1.isCallExpression(type.expression) && type.expression.expression.getText() === "Mixin") classIdentifiers = type.expression.arguments.filter(ts$1.isIdentifier);
|
|
@@ -14138,9 +14512,11 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
|
|
|
14138
14512
|
declarations = [...source.statements];
|
|
14139
14513
|
}
|
|
14140
14514
|
foundClassDeclaration = declarations?.find(ts$1.isClassDeclaration);
|
|
14515
|
+
foundClassName = foundClassDeclaration?.name?.getText();
|
|
14141
14516
|
if (!foundClassDeclaration) {
|
|
14142
14517
|
const node = declarations?.[0];
|
|
14143
14518
|
foundClassDeclaration = findClassWalk(node);
|
|
14519
|
+
foundClassName = foundClassDeclaration?.name?.getText() ?? factoryDeclaredName(node);
|
|
14144
14520
|
if (!node) throw "revert to sad path";
|
|
14145
14521
|
keepLooking = false;
|
|
14146
14522
|
if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, extendee.getText(), classDeclaration);
|
|
@@ -14149,7 +14525,7 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
|
|
|
14149
14525
|
const foundModule = compilerCtx.moduleMap.get(foundClassDeclaration.getSourceFile().fileName);
|
|
14150
14526
|
if (foundModule) {
|
|
14151
14527
|
const moduleSourceFile = foundModule.staticSourceFile;
|
|
14152
|
-
const sourceClass = findClassWalk(moduleSourceFile,
|
|
14528
|
+
const sourceClass = findClassWalk(moduleSourceFile, foundClassName);
|
|
14153
14529
|
if (sourceClass) {
|
|
14154
14530
|
dependentClasses.push({
|
|
14155
14531
|
classNode: sourceClass,
|
|
@@ -14170,20 +14546,24 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
|
|
|
14170
14546
|
if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, classDeclaration);
|
|
14171
14547
|
return;
|
|
14172
14548
|
}
|
|
14173
|
-
if (matchedStatement && ts$1.isClassDeclaration(matchedStatement))
|
|
14174
|
-
|
|
14549
|
+
if (matchedStatement && ts$1.isClassDeclaration(matchedStatement)) {
|
|
14550
|
+
foundClassDeclaration = matchedStatement;
|
|
14551
|
+
foundClassName = foundClassDeclaration.name?.getText();
|
|
14552
|
+
} else if (matchedStatement) {
|
|
14175
14553
|
foundClassDeclaration = findClassWalk(matchedStatement);
|
|
14554
|
+
foundClassName = foundClassDeclaration?.name?.getText() ?? extendee.getText();
|
|
14176
14555
|
keepLooking = false;
|
|
14177
14556
|
if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, extendee.getText(), classDeclaration);
|
|
14178
14557
|
} else {
|
|
14179
14558
|
foundClassDeclaration = findClassWalk(currentSource, extendee.getText());
|
|
14559
|
+
foundClassName = foundClassDeclaration?.name?.getText() ?? extendee.getText();
|
|
14180
14560
|
keepLooking = false;
|
|
14181
14561
|
}
|
|
14182
14562
|
if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {
|
|
14183
14563
|
const foundModule = compilerCtx.moduleMap.get(currentSource.fileName);
|
|
14184
14564
|
if (foundModule?.staticSourceFile) {
|
|
14185
14565
|
const transformedSource = foundModule.staticSourceFile;
|
|
14186
|
-
const transformedClass = findClassWalk(transformedSource,
|
|
14566
|
+
const transformedClass = findClassWalk(transformedSource, foundClassName);
|
|
14187
14567
|
if (transformedClass) {
|
|
14188
14568
|
dependentClasses.push({
|
|
14189
14569
|
classNode: transformedClass,
|
|
@@ -14468,7 +14848,7 @@ function convertInMemorySourceDecorators(sourceFile, config) {
|
|
|
14468
14848
|
const program = ts$1.createProgram([sourceFile.fileName], compilerOptions, compilerHost);
|
|
14469
14849
|
const typeChecker = program.getTypeChecker();
|
|
14470
14850
|
const ownSourceFile = program.getSourceFile(sourceFile.fileName) ?? sourceFile;
|
|
14471
|
-
const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program)]);
|
|
14851
|
+
const result = ts$1.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program, true)]);
|
|
14472
14852
|
const printed = ts$1.createPrinter({ removeComments: false }).printFile(result.transformed[0]);
|
|
14473
14853
|
const scriptKind = sourceFile.fileName.endsWith(".tsx") || sourceFile.fileName.endsWith(".ts") ? ts$1.ScriptKind.TSX : ts$1.ScriptKind.JS;
|
|
14474
14854
|
return ts$1.createSourceFile(sourceFile.fileName, printed, sourceFile.languageVersion, true, scriptKind);
|
|
@@ -14493,19 +14873,6 @@ function getExtendsClassNames(node) {
|
|
|
14493
14873
|
if (ts$1.isCallExpression(expr) && expr.expression.getText() === "Mixin") return expr.arguments.filter(ts$1.isIdentifier).map((id) => id.text);
|
|
14494
14874
|
return [];
|
|
14495
14875
|
}
|
|
14496
|
-
function findImportSpecifier(sf, localName) {
|
|
14497
|
-
for (const stmt of sf.statements) {
|
|
14498
|
-
if (!ts$1.isImportDeclaration(stmt) || !ts$1.isStringLiteral(stmt.moduleSpecifier)) continue;
|
|
14499
|
-
const clause = stmt.importClause;
|
|
14500
|
-
if (!clause) continue;
|
|
14501
|
-
if (clause.name?.text === localName) return stmt.moduleSpecifier.text;
|
|
14502
|
-
const bindings = clause.namedBindings;
|
|
14503
|
-
if (bindings && ts$1.isNamedImports(bindings)) {
|
|
14504
|
-
for (const el of bindings.elements) if (el.name.text === localName) return stmt.moduleSpecifier.text;
|
|
14505
|
-
}
|
|
14506
|
-
}
|
|
14507
|
-
return null;
|
|
14508
|
-
}
|
|
14509
14876
|
/**
|
|
14510
14877
|
* A single-file mini-program (see `convertInMemorySourceDecorators`) can
|
|
14511
14878
|
* never load an imported module's own `SourceFile`, so a type that's
|
|
@@ -14529,7 +14896,7 @@ function reclassifyGlobalTypeReferences(members, declaringSf, declaringPath, res
|
|
|
14529
14896
|
if (!references) return;
|
|
14530
14897
|
Object.entries(references).forEach(([typeName, reference]) => {
|
|
14531
14898
|
if (reference.location !== "global") return;
|
|
14532
|
-
const specifier =
|
|
14899
|
+
const specifier = findImportOrigin(declaringSf, typeName)?.moduleSpecifier;
|
|
14533
14900
|
if (!specifier) return;
|
|
14534
14901
|
const resolved = resolveImport(specifier, declaringPath);
|
|
14535
14902
|
reference.location = "import";
|
|
@@ -14541,7 +14908,7 @@ function reclassifyGlobalTypeReferences(members, declaringSf, declaringPath, res
|
|
|
14541
14908
|
}
|
|
14542
14909
|
/**
|
|
14543
14910
|
* Looks for `name` as a direct top-level declaration in `sf`; if not found, follows one level of
|
|
14544
|
-
* re-export (barrel file) via `resolveImport` - matching `compiler-ctx-merge.ts`'s equivalent
|
|
14911
|
+
* re-export (barrel file, named or `export *`) via `resolveImport` - matching `compiler-ctx-merge.ts`'s equivalent
|
|
14545
14912
|
* one-hop fallback (see `findReExport` in `shared.ts` for why it's capped at one hop).
|
|
14546
14913
|
*
|
|
14547
14914
|
* @param sf the source file to search
|
|
@@ -14552,26 +14919,31 @@ function reclassifyGlobalTypeReferences(members, declaringSf, declaringPath, res
|
|
|
14552
14919
|
* differ from `sf`/`path` if resolved through a re-export), or `undefined`
|
|
14553
14920
|
*/
|
|
14554
14921
|
function findDeclarationOrReExport(sf, path, name, resolveImport) {
|
|
14555
|
-
const direct = sf
|
|
14922
|
+
const direct = findStatementByName(sf, name);
|
|
14556
14923
|
if (direct) return {
|
|
14557
14924
|
statement: direct,
|
|
14558
14925
|
sourceFile: sf,
|
|
14559
14926
|
path
|
|
14560
14927
|
};
|
|
14561
|
-
const
|
|
14562
|
-
|
|
14563
|
-
|
|
14564
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
|
|
14569
|
-
|
|
14570
|
-
|
|
14571
|
-
|
|
14572
|
-
|
|
14573
|
-
path: resolvedPath
|
|
14928
|
+
const findIn = (moduleSpecifier, localName) => {
|
|
14929
|
+
const resolved = resolveImport(moduleSpecifier, path);
|
|
14930
|
+
if (!resolved) return void 0;
|
|
14931
|
+
const { code, path: resolvedPath } = resolved;
|
|
14932
|
+
const isTs = resolvedPath.endsWith(".tsx") || resolvedPath.endsWith(".ts");
|
|
14933
|
+
const reExportSf = ts$1.createSourceFile(resolvedPath, code, ts$1.ScriptTarget.ESNext, true, isTs ? ts$1.ScriptKind.TSX : ts$1.ScriptKind.JS);
|
|
14934
|
+
const statement = findStatementByName(reExportSf, localName);
|
|
14935
|
+
return statement && {
|
|
14936
|
+
statement,
|
|
14937
|
+
sourceFile: reExportSf,
|
|
14938
|
+
path: resolvedPath
|
|
14939
|
+
};
|
|
14574
14940
|
};
|
|
14941
|
+
const reExport = findReExport(sf, name);
|
|
14942
|
+
if (reExport) return findIn(reExport.moduleSpecifier, reExport.localName);
|
|
14943
|
+
for (const moduleSpecifier of findStarReExportSpecifiers(sf)) {
|
|
14944
|
+
const found = findIn(moduleSpecifier, name);
|
|
14945
|
+
if (found) return found;
|
|
14946
|
+
}
|
|
14575
14947
|
}
|
|
14576
14948
|
/**
|
|
14577
14949
|
* Recursively resolves a class's `extends` heritage into a flat, deduplicated
|
|
@@ -14602,7 +14974,7 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
|
|
|
14602
14974
|
let foundSf = sf;
|
|
14603
14975
|
let foundPath = path;
|
|
14604
14976
|
let keepLooking = true;
|
|
14605
|
-
const sameFileStatement = sf
|
|
14977
|
+
const sameFileStatement = findStatementByName(sf, parentName);
|
|
14606
14978
|
if (sameFileStatement) {
|
|
14607
14979
|
if (ts$1.isClassDeclaration(sameFileStatement)) foundClass = sameFileStatement;
|
|
14608
14980
|
else {
|
|
@@ -14611,7 +14983,7 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
|
|
|
14611
14983
|
if (!foundClass) warnMixinFactoryClassNotFound(buildCtx, parentName, rootClassDeclaration);
|
|
14612
14984
|
}
|
|
14613
14985
|
} else {
|
|
14614
|
-
const specifier =
|
|
14986
|
+
const specifier = findImportOrigin(sf, parentName)?.moduleSpecifier;
|
|
14615
14987
|
if (!specifier) continue;
|
|
14616
14988
|
const resolved = resolveImport(specifier, path);
|
|
14617
14989
|
if (!resolved) continue;
|
|
@@ -14643,7 +15015,8 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
|
|
|
14643
15015
|
ancestors.push({
|
|
14644
15016
|
classNode: foundClass,
|
|
14645
15017
|
sourceFile: foundSf,
|
|
14646
|
-
path: foundPath
|
|
15018
|
+
path: foundPath,
|
|
15019
|
+
factoryName: parentName
|
|
14647
15020
|
});
|
|
14648
15021
|
if (keepLooking) resolveAncestors(foundClass, foundSf, foundPath, resolveImport, visited, ancestors, rootClassDeclaration, buildCtx);
|
|
14649
15022
|
}
|
|
@@ -14660,8 +15033,8 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
|
|
|
14660
15033
|
* @returns the ancestor's metadata
|
|
14661
15034
|
*/
|
|
14662
15035
|
function extractAncestorMeta(ancestor, cmpSourceFile, resolveImport, config) {
|
|
14663
|
-
const { classNode, sourceFile: parentSf, path: resolvedPath } = ancestor;
|
|
14664
|
-
const className = classNode.name?.text;
|
|
15036
|
+
const { classNode, sourceFile: parentSf, path: resolvedPath, factoryName } = ancestor;
|
|
15037
|
+
const className = classNode.name?.text ?? factoryName;
|
|
14665
15038
|
const parentStaticMembers = classNode.members.filter(isStaticGetter);
|
|
14666
15039
|
let resolvedClassNode = classNode;
|
|
14667
15040
|
let resolvedStaticMembers = parentStaticMembers;
|
|
@@ -14753,7 +15126,6 @@ function mergeExtendedClassMetaWithResolveImport(cmpNode, staticMembers, sourceF
|
|
|
14753
15126
|
//#region src/compiler/transformers/static-to-meta/class-methods.ts
|
|
14754
15127
|
const parseClassMethods = (classMethods, cmpMeta) => {
|
|
14755
15128
|
if (!classMethods?.length) return;
|
|
14756
|
-
const hasHostData = classMethods.includes("hostData");
|
|
14757
15129
|
cmpMeta.hasAttributeChangedCallbackFn = classMethods.includes("attributeChangedCallback");
|
|
14758
15130
|
cmpMeta.hasConnectedCallbackFn = classMethods.includes("connectedCallback");
|
|
14759
15131
|
cmpMeta.hasDisconnectedCallbackFn = classMethods.includes("disconnectedCallback");
|
|
@@ -14765,8 +15137,7 @@ const parseClassMethods = (classMethods, cmpMeta) => {
|
|
|
14765
15137
|
cmpMeta.hasComponentShouldUpdateFn = classMethods.includes("componentShouldUpdate");
|
|
14766
15138
|
cmpMeta.hasComponentDidUpdateFn = classMethods.includes("componentDidUpdate");
|
|
14767
15139
|
cmpMeta.hasLifecycle = cmpMeta.hasComponentWillLoadFn || cmpMeta.hasComponentDidLoadFn || cmpMeta.hasComponentWillUpdateFn || cmpMeta.hasComponentDidUpdateFn;
|
|
14768
|
-
cmpMeta.hasRenderFn = classMethods.includes("render")
|
|
14769
|
-
cmpMeta.hasVdomRender = cmpMeta.hasVdomRender || hasHostData;
|
|
15140
|
+
cmpMeta.hasRenderFn = classMethods.includes("render");
|
|
14770
15141
|
};
|
|
14771
15142
|
//#endregion
|
|
14772
15143
|
//#region src/compiler/transformers/static-to-meta/element-ref.ts
|
|
@@ -15146,13 +15517,13 @@ const parseStaticComponentMeta = (compilerCtx, typeChecker, cmpNode, moduleFile,
|
|
|
15146
15517
|
hasPatchClone: false,
|
|
15147
15518
|
hasPatchInsert: false
|
|
15148
15519
|
};
|
|
15149
|
-
|
|
15150
|
-
|
|
15151
|
-
if (ts$1.isCallExpression(node)) parseCallExpression(cmp, node, typeChecker);
|
|
15520
|
+
if (!isCollectionDependency) validateComponentMembers(cmpNode, buildCtx);
|
|
15521
|
+
const visitComponentChildNode = (node) => {
|
|
15522
|
+
if (ts$1.isCallExpression(node)) parseCallExpression(cmp, node, typeChecker, moduleFile);
|
|
15152
15523
|
else if (ts$1.isStringLiteral(node)) parseStringLiteral(cmp, node);
|
|
15153
|
-
node.forEachChild(
|
|
15524
|
+
node.forEachChild(visitComponentChildNode);
|
|
15154
15525
|
};
|
|
15155
|
-
visitComponentChildNode(cmpNode
|
|
15526
|
+
visitComponentChildNode(cmpNode);
|
|
15156
15527
|
parseClassMethods(classMethods, cmp);
|
|
15157
15528
|
cmp.hasModernPropertyDecls = detectModernPropDeclarations(cmpNode) || doesExtend;
|
|
15158
15529
|
cmp.htmlAttrNames = unique(cmp.htmlAttrNames);
|
|
@@ -15170,31 +15541,32 @@ const parseStaticComponentMeta = (compilerCtx, typeChecker, cmpNode, moduleFile,
|
|
|
15170
15541
|
return cmpNode;
|
|
15171
15542
|
};
|
|
15172
15543
|
/**
|
|
15173
|
-
*
|
|
15174
|
-
*
|
|
15175
|
-
* @param
|
|
15176
|
-
* @returns whether `classNode` is a Stencil component class
|
|
15544
|
+
* Warn about members a Stencil component class should not define.
|
|
15545
|
+
* @param cmpNode the component class declaration
|
|
15546
|
+
* @param buildCtx the current build context, used to surface diagnostics
|
|
15177
15547
|
*/
|
|
15178
|
-
const
|
|
15179
|
-
const
|
|
15180
|
-
|
|
15181
|
-
|
|
15182
|
-
const
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
|
|
15191
|
-
|
|
15192
|
-
|
|
15193
|
-
|
|
15194
|
-
|
|
15195
|
-
|
|
15196
|
-
|
|
15197
|
-
|
|
15548
|
+
const validateComponentMembers = (cmpNode, buildCtx) => {
|
|
15549
|
+
const componentName = cmpNode.name?.text ?? "";
|
|
15550
|
+
for (const member of cmpNode.members) {
|
|
15551
|
+
if (!member.name || !ts$1.isIdentifier(member.name)) continue;
|
|
15552
|
+
const memberName = member.name.text;
|
|
15553
|
+
/**
|
|
15554
|
+
* the component has a getter called "shadowRoot"
|
|
15555
|
+
*/
|
|
15556
|
+
if (ts$1.isGetAccessorDeclaration(member) && BLACKLISTED_COMPONENT_METHODS.includes(memberName)) {
|
|
15557
|
+
const err = buildWarn(buildCtx.diagnostics);
|
|
15558
|
+
err.messageText = `The component "${componentName}" has a getter called "${memberName}". This getter is reserved for use by Stencil components and should not be defined by the user.`;
|
|
15559
|
+
augmentDiagnosticWithNode(err, ts$1.getOriginalNode(member));
|
|
15560
|
+
}
|
|
15561
|
+
/**
|
|
15562
|
+
* the component defines a "componentShouldUpdate" method with more than one parameter,
|
|
15563
|
+
* which was the pre-v5 per-prop signature "(newVal, oldVal, propName)"
|
|
15564
|
+
*/
|
|
15565
|
+
if (ts$1.isMethodDeclaration(member) && memberName === "componentShouldUpdate" && member.parameters.length > 1) {
|
|
15566
|
+
const err = buildWarn(buildCtx.diagnostics);
|
|
15567
|
+
err.messageText = `The component "${componentName}" defines "componentShouldUpdate" with ${member.parameters.length} parameters. As of Stencil v5, "componentShouldUpdate" is called once per render with a single "changes" argument (a map of prop/state names to "{ newVal, oldVal }") instead of once per prop with "(newVal, oldVal, propName)". This method will still compile, but any extra parameters will be "undefined" at runtime.`;
|
|
15568
|
+
augmentDiagnosticWithNode(err, ts$1.getOriginalNode(member));
|
|
15569
|
+
}
|
|
15198
15570
|
}
|
|
15199
15571
|
};
|
|
15200
15572
|
const parseVirtualProps = (docs) => {
|
|
@@ -15368,6 +15740,9 @@ const updateModule = (config, compilerCtx, buildCtx, tsSourceFile, sourceFileTex
|
|
|
15368
15740
|
} else if (ts$1.isImportDeclaration(node)) {
|
|
15369
15741
|
parseModuleImport(config, compilerCtx, buildCtx, moduleFile, srcDirPath, node, true);
|
|
15370
15742
|
return;
|
|
15743
|
+
} else if (ts$1.isExportDeclaration(node)) {
|
|
15744
|
+
parseModuleReExport(moduleFile, srcDirPath, node);
|
|
15745
|
+
return;
|
|
15371
15746
|
} else if (ts$1.isCallExpression(node)) parseCallExpression(moduleFile, node, typeChecker);
|
|
15372
15747
|
else if (ts$1.isStringLiteral(node)) parseStringLiteral(moduleFile, node);
|
|
15373
15748
|
else if (ts$1.isVariableStatement(node)) node.declarationList.declarations.forEach((declaration) => {
|
|
@@ -15538,18 +15913,32 @@ const addExternalImport = (config, compilerCtx, buildCtx, moduleFile, containing
|
|
|
15538
15913
|
//#region src/compiler/transformers/static-to-meta/import.ts
|
|
15539
15914
|
const parseModuleImport = (config, compilerCtx, buildCtx, moduleFile, dirPath, importNode, resolveCollections) => {
|
|
15540
15915
|
if (importNode.moduleSpecifier && ts$1.isStringLiteral(importNode.moduleSpecifier)) {
|
|
15541
|
-
|
|
15916
|
+
const importPath = importNode.moduleSpecifier.text;
|
|
15542
15917
|
if (!moduleFile.originalImports.includes(importPath)) moduleFile.originalImports.push(importPath);
|
|
15543
15918
|
if (importPath === "@stencil/core/signals") moduleFile.hasSignalsImport = true;
|
|
15544
|
-
|
|
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);
|
|
15919
|
+
const localPath = resolveLocalImportPath(dirPath, importPath);
|
|
15920
|
+
if (localPath) moduleFile.localImports.push(localPath);
|
|
15921
|
+
else addExternalImport(config, compilerCtx, buildCtx, moduleFile, moduleFile.sourceFilePath, importPath, resolveCollections, !importNode.importClause);
|
|
15551
15922
|
}
|
|
15552
15923
|
};
|
|
15924
|
+
/**
|
|
15925
|
+
* Record a local `export … from './x'` re-export as a local import, so build conditionals
|
|
15926
|
+
* propagate through barrel files. Bare-specifier re-exports are left alone.
|
|
15927
|
+
*
|
|
15928
|
+
* @param moduleFile the module containing the re-export
|
|
15929
|
+
* @param dirPath the module's (normalized) directory
|
|
15930
|
+
* @param exportNode the export declaration
|
|
15931
|
+
*/
|
|
15932
|
+
const parseModuleReExport = (moduleFile, dirPath, exportNode) => {
|
|
15933
|
+
if (exportNode.moduleSpecifier && ts$1.isStringLiteral(exportNode.moduleSpecifier)) {
|
|
15934
|
+
const localPath = resolveLocalImportPath(dirPath, exportNode.moduleSpecifier.text);
|
|
15935
|
+
if (localPath && !moduleFile.localImports.includes(localPath)) moduleFile.localImports.push(localPath);
|
|
15936
|
+
}
|
|
15937
|
+
};
|
|
15938
|
+
const resolveLocalImportPath = (dirPath, importPath) => {
|
|
15939
|
+
if (isAbsolute(importPath)) return normalizePath(importPath);
|
|
15940
|
+
if (importPath.startsWith(".")) return normalizePath(join$1(dirPath, importPath));
|
|
15941
|
+
};
|
|
15553
15942
|
//#endregion
|
|
15554
15943
|
//#region src/compiler/transformers/static-to-meta/visitor.ts
|
|
15555
15944
|
const convertStaticToMeta = (config, compilerCtx, buildCtx, typeChecker, collection, transformOpts) => {
|
|
@@ -15559,6 +15948,7 @@ const convertStaticToMeta = (config, compilerCtx, buildCtx, typeChecker, collect
|
|
|
15559
15948
|
const visitNode = (node) => {
|
|
15560
15949
|
if (ts$1.isClassDeclaration(node)) return parseStaticComponentMeta(compilerCtx, typeChecker, node, moduleFile, buildCtx, transformOpts);
|
|
15561
15950
|
else if (ts$1.isImportDeclaration(node)) parseModuleImport(config, compilerCtx, buildCtx, moduleFile, dirPath, node, !transformOpts.isolatedModules);
|
|
15951
|
+
else if (ts$1.isExportDeclaration(node)) parseModuleReExport(moduleFile, dirPath, node);
|
|
15562
15952
|
else if (ts$1.isCallExpression(node)) parseCallExpression(moduleFile, node, typeChecker);
|
|
15563
15953
|
else if (ts$1.isStringLiteral(node)) parseStringLiteral(moduleFile, node);
|
|
15564
15954
|
return ts$1.visitEachChild(node, visitNode, transformCtx);
|
|
@@ -15665,6 +16055,7 @@ const transpileModule = (config, input, transformOpts) => {
|
|
|
15665
16055
|
...config,
|
|
15666
16056
|
logger: createNodeLogger()
|
|
15667
16057
|
};
|
|
16058
|
+
resetDeprecatedApiWarning();
|
|
15668
16059
|
const compilerCtx = new CompilerContext();
|
|
15669
16060
|
const buildCtx = new BuildContext(config, compilerCtx);
|
|
15670
16061
|
const tsCompilerOptions = { ...config.tsCompilerOptions };
|
|
@@ -15842,6 +16233,7 @@ const transpileCss = async (transformInput, results) => {
|
|
|
15842
16233
|
results.map = cssResults.map;
|
|
15843
16234
|
results.imports = cssResults.imports.map((p) => ({ path: p.importPath }));
|
|
15844
16235
|
results.diagnostics.push(...cssResults.diagnostics);
|
|
16236
|
+
if (transformInput.docs) results.styleDocs = cssResults.styleDocs;
|
|
15845
16237
|
};
|
|
15846
16238
|
const transpileCssSync = (transformInput, results) => {
|
|
15847
16239
|
const cssResults = transformCssToEsmSync(transformInput);
|
|
@@ -15849,6 +16241,7 @@ const transpileCssSync = (transformInput, results) => {
|
|
|
15849
16241
|
results.map = cssResults.map;
|
|
15850
16242
|
results.imports = cssResults.imports.map((p) => ({ path: p.importPath }));
|
|
15851
16243
|
results.diagnostics.push(...cssResults.diagnostics);
|
|
16244
|
+
if (transformInput.docs) results.styleDocs = cssResults.styleDocs;
|
|
15852
16245
|
};
|
|
15853
16246
|
const transpileJson = (results) => {
|
|
15854
16247
|
results.code = dataToEsm(JSON.parse(results.code), {
|
|
@@ -16279,7 +16672,7 @@ const FORM_ASSOCIATED_ATTRIBUTES = [
|
|
|
16279
16672
|
* @param cmp the metadata for the component that a type definition string is generated for
|
|
16280
16673
|
* @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions
|
|
16281
16674
|
* @param areTypesInternal `true` if types being generated are for a project's internal purposes, `false` otherwise
|
|
16282
|
-
* @param signalBacking `true` if the component is using signal backing for its props; includes the signals map on the element interface
|
|
16675
|
+
* @param signalBacking `true` if the component is using signal backing for its props; includes the signals map on the element interface and unions JSX prop types with `ReadonlySignal<T>`
|
|
16283
16676
|
* @returns the generated types string alongside additional metadata
|
|
16284
16677
|
*/
|
|
16285
16678
|
const generateComponentTypes = (cmp, typeImportData, areTypesInternal, signalBacking = false) => {
|
|
@@ -16296,8 +16689,12 @@ const generateComponentTypes = (cmp, typeImportData, areTypesInternal, signalBac
|
|
|
16296
16689
|
const isDep = cmp.isCollectionDependency;
|
|
16297
16690
|
const propNames = new Set(propAttributes.map((p) => p.name));
|
|
16298
16691
|
const formAssociatedAttrs = cmp.formAssociated ? FORM_ASSOCIATED_ATTRIBUTES.filter((attr) => !propNames.has(attr.name)) : [];
|
|
16692
|
+
const jsxPropAttributes = signalBacking ? propAttributes.map((attr) => ({
|
|
16693
|
+
...attr,
|
|
16694
|
+
type: `${attr.type} | ReadonlySignal<${attr.type}>`
|
|
16695
|
+
})) : propAttributes;
|
|
16299
16696
|
const jsxAttributes = attributesToMultiLineString([
|
|
16300
|
-
...
|
|
16697
|
+
...jsxPropAttributes,
|
|
16301
16698
|
...eventAttributes,
|
|
16302
16699
|
...formAssociatedAttrs
|
|
16303
16700
|
], true, areTypesInternal);
|