584 lines
19 KiB
JavaScript
584 lines
19 KiB
JavaScript
import path, { dirname, resolve } from 'node:path';
|
|
import { useNuxt, logger, defineNuxtModule, createResolver, resolvePath, addPlugin, addTemplate, addTypeTemplate, addComponent, addImports, addImportsSources } from '@nuxt/kit';
|
|
import { parseNodeModulePath } from 'mlly';
|
|
import MagicString from 'magic-string';
|
|
import os from 'node:os';
|
|
import { readFile } from 'node:fs/promises';
|
|
import pMemoize from 'p-memoize';
|
|
import semver from 'semver';
|
|
|
|
const version = "3.0.0";
|
|
|
|
const directivesRegExp = /(?<=[ (])_?resolveDirective\(\s*["']([^'"]*)["'][^)]*\)/g;
|
|
function transformDirectivesPlugin(context) {
|
|
const { sourcemap } = useNuxt().options;
|
|
return {
|
|
name: "quasar:directive",
|
|
enforce: "post",
|
|
transform(code, id) {
|
|
const [filename] = id.split("?", 2);
|
|
if (!filename || !filename.endsWith(".vue"))
|
|
return null;
|
|
const s = new MagicString(code);
|
|
const directives = [];
|
|
let counter = 0;
|
|
s.replace(directivesRegExp, (full, name) => {
|
|
const directive = context.imports.directives.find((d) => d.kebabCase === name);
|
|
if (directive) {
|
|
const alias = `__q_directive_${counter++}`;
|
|
directives.push({
|
|
name: directive.name,
|
|
alias
|
|
});
|
|
return alias;
|
|
} else {
|
|
return full;
|
|
}
|
|
});
|
|
if (directives.length) {
|
|
s.prepend(
|
|
`${directives.map((d) => `import { ${d.name} as ${d.alias} } from "quasar"`).join("\n")}
|
|
`
|
|
);
|
|
}
|
|
if (s.hasChanged()) {
|
|
return {
|
|
code: s.toString(),
|
|
map: sourcemap[context.mode] ? s.generateMap({ source: id, includeContent: true }) : void 0
|
|
};
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
const isWindows = os.platform() === "win32";
|
|
function slash(p) {
|
|
return p.replace(/\\/g, "/");
|
|
}
|
|
function normalizePath(id) {
|
|
return path.posix.normalize(isWindows ? slash(id) : id);
|
|
}
|
|
const readFileMemoized = pMemoize(async (path2) => {
|
|
return readFile(path2, "utf-8");
|
|
});
|
|
const readJSON = pMemoize(async (path2) => {
|
|
return JSON.parse(await readFile(path2, "utf-8"));
|
|
});
|
|
const PASCAL_CASE = /[a-z][A-Z]|^[A-Z]/g;
|
|
function kebabCase(string) {
|
|
return string.replaceAll(
|
|
PASCAL_CASE,
|
|
(match) => match.length === 1 ? match[0].toLowerCase() : `${match[0]}-${match[1].toLowerCase()}`
|
|
);
|
|
}
|
|
function hasKeys(object) {
|
|
return Object.keys(object || {}).length > 0;
|
|
}
|
|
function parseVueRequest(id) {
|
|
const [filename = "", rawQuery] = id.split("?", 2);
|
|
const query = Object.fromEntries(new URLSearchParams(rawQuery));
|
|
if (query.vue != null) {
|
|
query.vue = true;
|
|
}
|
|
return {
|
|
filename,
|
|
query
|
|
};
|
|
}
|
|
function uniq(arr) {
|
|
return [...new Set(arr)];
|
|
}
|
|
|
|
function transformScssPlugin({ options }) {
|
|
const sassVariables = typeof options.sassVariables === "string" ? normalizePath(options.sassVariables) : options.sassVariables;
|
|
const scssTransform = createScssTransform("scss", sassVariables);
|
|
const sassTransform = createScssTransform("sass", sassVariables);
|
|
return {
|
|
name: "quasar:scss",
|
|
enforce: "pre",
|
|
transform(src, id) {
|
|
const { filename, query } = parseVueRequest(id);
|
|
let code;
|
|
if (query.vue && query.type === "style") {
|
|
const lang = Object.keys(query).find((k) => k.startsWith("lang."));
|
|
if (lang?.endsWith(".scss")) {
|
|
code = scssTransform(src);
|
|
} else if (lang?.endsWith(".sass")) {
|
|
code = sassTransform(src);
|
|
}
|
|
}
|
|
if (!query.vue) {
|
|
if (filename.endsWith(".scss")) {
|
|
code = scssTransform(src);
|
|
} else if (filename.endsWith(".sass")) {
|
|
code = sassTransform(src);
|
|
}
|
|
}
|
|
if (code) {
|
|
return { code, map: null };
|
|
}
|
|
}
|
|
};
|
|
}
|
|
function createScssTransform(fileExtension, sassVariables) {
|
|
return (content) => {
|
|
const hasQuasarVariables = content.includes("quasar/src/css/variables") || content.includes("quasar/dist/") || /@use\s+['"]quasar(?:[/'"]|$)/.test(content);
|
|
const sassUseStatements = [];
|
|
if (hasQuasarVariables) {
|
|
return content;
|
|
} else if (typeof sassVariables === "string") {
|
|
sassUseStatements.push(`@use '${sassVariables}' as *`);
|
|
} else {
|
|
sassUseStatements.push("@use 'quasar/src/css/variables.sass' as *");
|
|
}
|
|
sassUseStatements.push("");
|
|
const prefix = fileExtension === "sass" ? sassUseStatements.join("\n") : sassUseStatements.join(";\n");
|
|
const useIndex = Math.max(content.lastIndexOf("@use "), content.lastIndexOf("@forward "));
|
|
if (useIndex === -1) {
|
|
return prefix + content;
|
|
}
|
|
const newLineIndex = content.indexOf("\n", useIndex);
|
|
if (newLineIndex !== -1) {
|
|
const index = newLineIndex + 1;
|
|
return content.substring(0, index) + prefix + content.substring(index);
|
|
}
|
|
return `${content}
|
|
${prefix}`;
|
|
};
|
|
}
|
|
|
|
const QUASAR_ENTRY = "quasar";
|
|
const QUASAR_VIRTUAL_ENTRY = "/__quasar/entry.mjs";
|
|
function virtualQuasarEntryPlugin(context) {
|
|
const { resolveQuasar, quasarVersion } = context;
|
|
const quasarGte216 = semver.gte(quasarVersion, "2.16.0");
|
|
const clientEntry = quasarGte216 ? resolveQuasar("dist/quasar.client.js") : resolveQuasar("dist/quasar.esm.js");
|
|
const serverEntry = quasarGte216 ? resolveQuasar("dist/quasar.server.prod.js") : resolveQuasar("src/index.ssr.js");
|
|
return {
|
|
name: "quasar:entry",
|
|
enforce: "pre",
|
|
config(config) {
|
|
config.ssr ??= {};
|
|
config.ssr.noExternal ??= [];
|
|
if (config.ssr.noExternal !== true) {
|
|
config.ssr.noExternal = toArray(config.ssr.noExternal);
|
|
config.ssr.noExternal.push(/\/node_modules\/quasar\/src\//);
|
|
}
|
|
},
|
|
resolveId(id) {
|
|
if (id === QUASAR_ENTRY) {
|
|
return {
|
|
id: context.dev ? context.mode === "client" ? clientEntry : serverEntry : QUASAR_VIRTUAL_ENTRY,
|
|
moduleSideEffects: false
|
|
};
|
|
}
|
|
},
|
|
async load(id) {
|
|
if (!context.dev && id === QUASAR_VIRTUAL_ENTRY)
|
|
return Object.entries(context.imports.raw).filter(([, path]) => !path.includes("/__tests__/")).map(([name, path]) => `export { default as ${name} } from "quasar/${path}"`).join("\n");
|
|
}
|
|
};
|
|
}
|
|
function toArray(value) {
|
|
return Array.isArray(value) ? value : [value];
|
|
}
|
|
|
|
const moduleName = "nuxt-quasar-ui";
|
|
const quasarFontsPath = "quasar/fonts";
|
|
const quasarAnimationsPath = "quasar/animations";
|
|
const quasarIconsPath = "quasar/icons";
|
|
const quasarCssPath = "quasar/css";
|
|
const quasarBrandPath = "quasar/brand";
|
|
|
|
const RESOLVED_ID$1 = "/__quasar/animations.css";
|
|
const RESOLVED_ID_WITH_QUERY_RE$1 = /([/\\])__quasar\1animations\.css(\?.*)?$/;
|
|
function virtualAnimationsPlugin({ options, resolveQuasarExtras }) {
|
|
return {
|
|
name: "quasar:animations",
|
|
resolveId(id) {
|
|
if (id.match(RESOLVED_ID_WITH_QUERY_RE$1))
|
|
return id;
|
|
const [path] = id.split("?");
|
|
if (path === quasarAnimationsPath)
|
|
return RESOLVED_ID$1;
|
|
},
|
|
async load(id) {
|
|
if (!RESOLVED_ID_WITH_QUERY_RE$1.test(id))
|
|
return;
|
|
let animations = options.extras?.animations || [];
|
|
if (animations === "all") {
|
|
const { generalAnimations, inAnimations, outAnimations } = await import('@quasar/extras/animate/animate-list.mjs');
|
|
animations = [...generalAnimations, ...inAnimations, ...outAnimations];
|
|
} else {
|
|
animations = uniq(animations);
|
|
}
|
|
const cssArray = await Promise.all(
|
|
animations.map(
|
|
(animation) => readFile(resolveQuasarExtras(`animate/${animation}.css`), "utf8")
|
|
)
|
|
);
|
|
return cssArray.join("\n");
|
|
}
|
|
};
|
|
}
|
|
|
|
const RESOLVED_ID = "/__quasar/brand.css";
|
|
const RESOLVED_ID_WITH_QUERY_RE = /([/\\])__quasar\1brand\.css(\?.*)?$/;
|
|
function virtualBrandPlugin(context) {
|
|
return {
|
|
name: "quasar:brand",
|
|
resolveId(id) {
|
|
if (id.match(RESOLVED_ID_WITH_QUERY_RE))
|
|
return id;
|
|
const [path] = id.split("?");
|
|
if (path === quasarBrandPath)
|
|
return RESOLVED_ID;
|
|
},
|
|
load(id) {
|
|
if (RESOLVED_ID_WITH_QUERY_RE.test(id))
|
|
return [
|
|
":root {",
|
|
...Object.entries(context.options.config?.brand || {}).map(([name, color]) => ` --q-${name}: ${color};`),
|
|
"}"
|
|
].join("\n");
|
|
}
|
|
};
|
|
}
|
|
|
|
function setupCss(css, options) {
|
|
const brand = options.config?.brand || {};
|
|
if (css.includes(quasarBrandPath)) {
|
|
logger.warn('Re-ordering "quasar/brand" is deprecated. In a future version, brand variables will always be defined in body tag.');
|
|
}
|
|
if (!css.includes(quasarBrandPath) && Object.keys(brand).length) {
|
|
css.unshift(quasarBrandPath);
|
|
}
|
|
const quasarCss = [
|
|
typeof options.sassVariables === "string" ? "quasar/dist/quasar.sass" : "quasar/dist/quasar.css"
|
|
];
|
|
if (options.cssAddon) {
|
|
quasarCss.push("quasar/dist/quasar.addon.css");
|
|
}
|
|
const index = css.indexOf(quasarCssPath);
|
|
if (index !== -1) {
|
|
css.splice(index, 1, ...quasarCss);
|
|
} else {
|
|
css.unshift(...quasarCss);
|
|
}
|
|
const animations = options.extras?.animations || [];
|
|
if (!css.includes(quasarAnimationsPath) && animations.length) {
|
|
css.unshift(quasarAnimationsPath);
|
|
}
|
|
if (options.extras?.fontIcons) {
|
|
const i = css.indexOf(quasarIconsPath);
|
|
if (i !== -1) {
|
|
css.splice(i, 1, ...uniq(options.extras.fontIcons).map(resolveFontIcon));
|
|
} else {
|
|
css.unshift(...uniq(options.extras.fontIcons).map(resolveFontIcon));
|
|
}
|
|
}
|
|
if (options.extras?.font) {
|
|
const i = css.indexOf(quasarFontsPath);
|
|
if (i !== -1) {
|
|
css.splice(i, 1, resolveFont(options.extras.font));
|
|
} else {
|
|
css.unshift(resolveFont(options.extras.font));
|
|
}
|
|
}
|
|
return css;
|
|
}
|
|
function resolveFontIcon(icon) {
|
|
return `@quasar/extras/${icon}/${icon}.css`;
|
|
}
|
|
function resolveFont(font) {
|
|
return `@quasar/extras/${font}/${font}.css`;
|
|
}
|
|
|
|
function when(condition, content) {
|
|
return condition ? typeof content === "function" ? content() : content : "";
|
|
}
|
|
function generateTemplateQuasarConfig(context) {
|
|
const plugins = uniq(context.options.plugins || []);
|
|
const { config, lang, iconSet, components } = context.options;
|
|
const componentsWithDefaults = Object.entries(components?.defaults || {}).filter(([_, props]) => hasKeys(props)).map(([name]) => name);
|
|
const ext = semver.gte(context.quasarVersion, "2.16.0") ? ".js" : ".mjs";
|
|
return `${when(lang, () => `import lang from "quasar/lang/${lang}${ext}"`)}
|
|
${when(typeof iconSet === "string", () => `import iconSet from "quasar/icon-set/${iconSet}${ext}"`)}
|
|
${when(plugins.length, () => `import { ${plugins} } from "quasar"`)}
|
|
${when(componentsWithDefaults.length, () => `import { ${componentsWithDefaults} } from "quasar"`)}
|
|
|
|
export const componentsWithDefaults = { ${componentsWithDefaults} }
|
|
|
|
export const appConfigKey = ${JSON.stringify(context.options.appConfigKey)}
|
|
|
|
export const quasarNuxtConfig = {
|
|
${when(lang, "lang,")}
|
|
${typeof iconSet === "string" ? "iconSet" : `iconSet: ${iconSet ? JSON.stringify(iconSet) : '"material-icons"'}`},
|
|
components: ${JSON.stringify(components || {})},
|
|
plugins: {${plugins.join(",") || ""}},
|
|
${when(config, () => `config: ${JSON.stringify(config)}`)}
|
|
}`;
|
|
}
|
|
|
|
async function generateTemplateShims(context) {
|
|
const componentNames = context.imports.components.map((c) => c.name);
|
|
return `type KeysMatching<T, V> = {
|
|
[K in keyof T]-?: T[K] extends V ? K : never
|
|
}[keyof T] & keyof T
|
|
|
|
type OptionalKeys<T extends object> = Exclude<{
|
|
[K in keyof T]: T extends Record<K, T[K]> ? never : K
|
|
}[keyof T], undefined>
|
|
|
|
type OmitMatching<T extends object, V> = Omit<T, KeysMatching<T, V>>
|
|
|
|
type OmitFnProps<T extends object> = OmitMatching<T, ((...args: any[]) => any) | undefined>
|
|
|
|
type PickOptionalProps<T extends object> = Pick<T, OptionalKeys<T>>
|
|
|
|
declare module '${moduleName}' {
|
|
interface QuasarComponentDefaults {
|
|
${componentNames.map(
|
|
(name) => ` ${name}?: PickOptionalProps<OmitFnProps<import("quasar").${name}Props>>`
|
|
).join("\n")}
|
|
}
|
|
}
|
|
|
|
declare module '@nuxt/schema' {
|
|
interface AppConfigInput {
|
|
[${JSON.stringify(context.options.appConfigKey)}]?: import("nuxt-quasar-ui").QuasarUIConfiguration
|
|
}
|
|
interface AppConfig {
|
|
[${JSON.stringify(context.options.appConfigKey)}]?: import("nuxt-quasar-ui").QuasarUIConfiguration
|
|
}
|
|
}
|
|
|
|
export {}
|
|
`;
|
|
}
|
|
|
|
const module$1 = defineNuxtModule({
|
|
meta: {
|
|
name: "quasar",
|
|
version,
|
|
configKey: "quasar",
|
|
compatibility: {
|
|
nuxt: ">=3.0.0"
|
|
}
|
|
},
|
|
defaults: {
|
|
lang: "en-US",
|
|
iconSet: "material-icons",
|
|
autoIncludeIconSet: true,
|
|
cssAddon: false,
|
|
sassVariables: false,
|
|
appConfigKey: "nuxtQuasar",
|
|
components: {
|
|
defaults: {},
|
|
autoImport: true
|
|
},
|
|
plugins: [],
|
|
extras: {}
|
|
},
|
|
async setup(options, nuxt) {
|
|
const { resolve: resolveLocal } = createResolver(import.meta.url);
|
|
const { resolve: resolveQuasar } = createResolver(dirname(await resolvePath("quasar/package.json")));
|
|
const { resolve: resolveQuasarExtras } = createResolver(dirname(await resolvePath("@quasar/extras/package.json")));
|
|
const { version: quasarVersion } = await readJSON(resolveQuasar("package.json"));
|
|
const importMap = await readJSON(resolveQuasar("dist/transforms/import-map.json"));
|
|
const transformAssetUrls = await readJSON(resolveQuasar("dist/transforms/loader-asset-urls.json"));
|
|
const imports = categorizeImports(importMap, resolveQuasar);
|
|
const sassVersion = await getSassVersion();
|
|
const baseContext = {
|
|
ssr: nuxt.options.ssr,
|
|
dev: nuxt.options.dev,
|
|
imports,
|
|
options,
|
|
quasarVersion,
|
|
sassVersion,
|
|
resolveLocal,
|
|
resolveQuasar,
|
|
resolveQuasarExtras
|
|
};
|
|
if (options.autoIncludeIconSet && typeof options.iconSet === "string" && isFontIconSet(options.iconSet) && !options.extras?.fontIcons?.includes(options.iconSet)) {
|
|
options.extras ??= {};
|
|
options.extras.fontIcons ??= [];
|
|
options.extras.fontIcons.push(options.iconSet);
|
|
}
|
|
setupCss(nuxt.options.css, options);
|
|
addPlugin(resolveLocal("./runtime/plugin"));
|
|
addTemplate({
|
|
write: true,
|
|
filename: "quasar.config.mjs",
|
|
getContents: () => generateTemplateQuasarConfig(baseContext)
|
|
});
|
|
addTypeTemplate({
|
|
filename: "quasar.shims.d.ts",
|
|
getContents: () => generateTemplateShims(baseContext)
|
|
});
|
|
if (options.components?.autoImport !== false) {
|
|
for (const component of imports.components) {
|
|
addComponent({
|
|
name: component.name,
|
|
export: component.name,
|
|
filePath: "quasar",
|
|
// TOFIX: Nuxt v3.13.2 tries to resolve full component paths with following PR: https://github.com/nuxt/nuxt/pull/28843
|
|
// Since this module has a custom way of resolving quasar, this breaks things.
|
|
// Adding this property prevents nuxt from resolving components, but since this is an internal property, it might break again in future.
|
|
// @ts-expect-error untyped internal property
|
|
_scanned: true
|
|
});
|
|
}
|
|
}
|
|
if (nuxt.options.imports.autoImport !== false) {
|
|
const ignoredComposables = ["useId", "useHydration"];
|
|
for (const composable of imports.composables.filter((c) => !ignoredComposables.includes(c.name))) {
|
|
addImports({
|
|
name: composable.name,
|
|
from: "quasar"
|
|
});
|
|
}
|
|
if (options.plugins) {
|
|
for (const plugin of uniq(options.plugins)) {
|
|
const pluginPath = imports.plugins.find((p) => p.name === plugin)?.path;
|
|
if (pluginPath) {
|
|
addImports({
|
|
name: plugin,
|
|
from: "quasar"
|
|
});
|
|
}
|
|
}
|
|
}
|
|
if (options.extras?.svgIcons) {
|
|
for (const iconSet of uniq(options.extras.svgIcons)) {
|
|
const icons = await getIconsFromIconset(iconSet, resolveQuasarExtras);
|
|
addImportsSources({
|
|
from: `@quasar/extras/${iconSet}`,
|
|
imports: icons
|
|
});
|
|
}
|
|
}
|
|
}
|
|
nuxt.hook("prepare:types", ({ references }) => {
|
|
references.unshift({ types: "quasar" });
|
|
});
|
|
nuxt.hook("vite:extendConfig", (config, { isClient, isServer }) => {
|
|
const ssr = nuxt.options.ssr;
|
|
const context = {
|
|
...baseContext,
|
|
mode: isServer ? "server" : "client"
|
|
};
|
|
config.optimizeDeps ??= {};
|
|
config.optimizeDeps.exclude ??= [];
|
|
config.optimizeDeps.exclude.push("quasar");
|
|
config.vue ??= {};
|
|
config.vue.template ??= {};
|
|
if (config.vue.template.transformAssetUrls !== false) {
|
|
config.vue.template.transformAssetUrls ??= {};
|
|
config.vue.template.transformAssetUrls = {
|
|
...config.vue.template.transformAssetUrls,
|
|
...transformAssetUrls
|
|
};
|
|
}
|
|
config.define = {
|
|
...config.define,
|
|
__QUASAR_VERSION__: `'${quasarVersion}'`,
|
|
__QUASAR_SSR__: ssr,
|
|
__QUASAR_SSR_SERVER__: ssr && isServer,
|
|
__QUASAR_SSR_CLIENT__: ssr && isClient,
|
|
__QUASAR_SSR_PWA__: false
|
|
};
|
|
config.plugins ??= [];
|
|
config.plugins.push(
|
|
virtualAnimationsPlugin(context),
|
|
virtualBrandPlugin(context),
|
|
transformDirectivesPlugin(context),
|
|
virtualQuasarEntryPlugin(context)
|
|
);
|
|
if (options.sassVariables) {
|
|
config.plugins.push(transformScssPlugin(context));
|
|
}
|
|
});
|
|
nuxt.hook("nitro:config", async (config) => {
|
|
config.replace = {
|
|
...config.replace,
|
|
__QUASAR_VERSION__: `'${quasarVersion}'`,
|
|
__QUASAR_SSR__: nuxt.options.ssr,
|
|
__QUASAR_SSR_SERVER__: true,
|
|
__QUASAR_SSR_CLIENT__: false,
|
|
__QUASAR_SSR_PWA__: false
|
|
};
|
|
config.externals ??= {};
|
|
config.externals.inline ??= [];
|
|
config.externals.inline.push("quasar");
|
|
});
|
|
nuxt.hook("devtools:customTabs", (tabs) => {
|
|
tabs.push({
|
|
name: "quasar",
|
|
title: "Quasar",
|
|
icon: "vscode-icons-file-type-light-quasar",
|
|
view: {
|
|
type: "iframe",
|
|
src: "https://quasar.dev/vue-components"
|
|
}
|
|
});
|
|
});
|
|
}
|
|
});
|
|
function isFontIconSet(iconSet) {
|
|
return !iconSet.startsWith("svg-");
|
|
}
|
|
function categorizeImports(importMap, quasarResolve) {
|
|
const imports = {
|
|
raw: importMap,
|
|
components: [],
|
|
composables: [],
|
|
directives: [],
|
|
plugins: []
|
|
};
|
|
for (const [name, path] of Object.entries(importMap)) {
|
|
const importData = {
|
|
name,
|
|
path: quasarResolve(path)
|
|
};
|
|
if (path.includes("/components/") && !path.includes("/__tests__/")) {
|
|
imports.components.push(importData);
|
|
} else if (path.includes("/composables/")) {
|
|
imports.composables.push(importData);
|
|
} else if (path.includes("/directives/")) {
|
|
imports.directives.push({
|
|
...importData,
|
|
kebabCase: kebabCase(name)
|
|
});
|
|
} else if (path.includes("/plugins/")) {
|
|
imports.plugins.push(importData);
|
|
}
|
|
}
|
|
return imports;
|
|
}
|
|
const iconDeclarationPattern = /^export declare const ([a-zA-Z\d]+): string;?$/gm;
|
|
async function getIconsFromIconset(iconSet, resolveQuasarExtras) {
|
|
try {
|
|
const icons = await readJSON(resolveQuasarExtras(`${iconSet}/icons.json`));
|
|
return icons;
|
|
} catch {
|
|
const path = resolveQuasarExtras(`${iconSet}/index.d.ts`);
|
|
const dts = await readFileMemoized(path);
|
|
const icons = [...dts.matchAll(iconDeclarationPattern)].map((arr) => arr[1]);
|
|
return icons;
|
|
}
|
|
}
|
|
async function getSassVersion() {
|
|
try {
|
|
const sassEntry = await resolvePath("sass");
|
|
const modulePath = parseNodeModulePath(sassEntry);
|
|
if (modulePath.dir) {
|
|
const { version: version2 } = await readJSON(resolve(modulePath.dir, modulePath.name, "./package.json"));
|
|
return version2;
|
|
}
|
|
} catch {
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export { module$1 as default };
|