From 94519c3c767cd5d20948117a04bd2b41ffcb4719 Mon Sep 17 00:00:00 2001 From: Vojtech Miksu Date: Wed, 27 Oct 2021 00:33:31 -0700 Subject: [PATCH] fix: various fixes to make baseweb working (#24) * fix: various fixes to make baseweb working * fix: use ESM for vite-plugin * fix: meta.json, history, better errors * fix: tests disabled temp, have to fix esm in jest Co-authored-by: tajo --- lerna.json | 18 ++-- packages/ladle/jest.config.js | 1 + packages/ladle/lib/app/src/app.tsx | 3 +- packages/ladle/lib/cli/build.js | 15 +++- packages/ladle/lib/cli/serve.js | 2 +- packages/ladle/lib/cli/vite-base.js | 41 +++++++++ packages/ladle/lib/cli/vite-dev.js | 55 +++++++----- .../ladle/lib/cli/vite-plugin/ast-to-obj.js | 8 +- .../generate/get-components-import.js | 26 ++++-- .../vite-plugin/generate/get-config-import.js | 15 ++-- .../generate/get-generated-list.js | 12 +-- .../lib/cli/vite-plugin/generate/get-hmr.js | 2 +- .../cli/vite-plugin/generate/get-meta-json.js | 18 +++- .../vite-plugin/generate/get-story-imports.js | 17 ++-- .../vite-plugin/generate/get-story-list.js | 20 ++--- packages/ladle/lib/cli/vite-plugin/get-ast.js | 44 +++++++--- .../ladle/lib/cli/vite-plugin/naming-utils.js | 29 +++---- .../ladle/lib/cli/vite-plugin/package.json | 3 - .../vite-plugin/parse/get-default-export.js | 6 +- .../cli/vite-plugin/parse/get-entry-data.js | 30 +++---- .../vite-plugin/parse/get-named-exports.js | 18 ++-- .../parse/get-storyname-and-parameters.js | 10 +-- .../ladle/lib/cli/vite-plugin/vite-plugin.js | 17 ++-- packages/ladle/lib/cli/vite-prod.js | 26 ++---- packages/ladle/package.json | 7 +- packages/ladle/tests/get-meta-json.test.ts | 2 +- yarn.lock | 83 ++++++++++++++++++- 27 files changed, 353 insertions(+), 175 deletions(-) create mode 100644 packages/ladle/lib/cli/vite-base.js delete mode 100644 packages/ladle/lib/cli/vite-plugin/package.json diff --git a/lerna.json b/lerna.json index 248d829f..7fc688de 100644 --- a/lerna.json +++ b/lerna.json @@ -3,14 +3,14 @@ "version": "independent", "npmClientArgs": ["--no-lockfile"], "command": { - "version": { - "ignoreChanges": ["*.md"], - "npmClient": "yarn", - "message": "chore(release): publish" - }, - "publish": { - "npmClient": "npm", - "conventionalCommits": true - } + "version": { + "ignoreChanges": ["*.md"], + "npmClient": "yarn", + "message": "chore(release): publish [skip ci]" + }, + "publish": { + "npmClient": "npm", + "conventionalCommits": true + } } } diff --git a/packages/ladle/jest.config.js b/packages/ladle/jest.config.js index 27cf0118..a1edf2ce 100644 --- a/packages/ladle/jest.config.js +++ b/packages/ladle/jest.config.js @@ -1,4 +1,5 @@ export default { preset: "ts-jest", testEnvironment: "node", + transform: {}, }; diff --git a/packages/ladle/lib/app/src/app.tsx b/packages/ladle/lib/app/src/app.tsx index e0c69072..4626a963 100644 --- a/packages/ladle/lib/app/src/app.tsx +++ b/packages/ladle/lib/app/src/app.tsx @@ -75,8 +75,7 @@ const App: React.FC<{}> = () => { // handle go back/forward browser buttons React.useEffect(() => { // @ts-ignore - const unlisten = history.listen(({ action, location }) => { - console.log(action); + const unlisten = history.listen((location, action) => { if (action === "POP") { dispatch({ type: ActionType.UpdateAll, diff --git a/packages/ladle/lib/cli/build.js b/packages/ladle/lib/cli/build.js index 57a96a1c..8d86185a 100755 --- a/packages/ladle/lib/cli/build.js +++ b/packages/ladle/lib/cli/build.js @@ -1,9 +1,13 @@ #!/usr/bin/env node import path from "path"; +import { promises as fs } from "fs"; +import globby from "globby"; import viteProd from "./vite-prod.js"; import loadConfig from "./load-config.js"; import debug from "./debug.js"; +import { getMetaJsonString } from "./vite-plugin/generate/get-meta-json.js"; +import { getEntryData } from "./vite-plugin/parse/get-entry-data.js"; /** * @param params {import("../shared/types").BuildParams} @@ -42,7 +46,16 @@ const build = async (params = {}) => { debug(`Final config:\n${JSON.stringify(config, null, " ")}`); process.env["VITE_PUBLIC_LADLE_THEME"] = config.addons.theme.defaultState; - return viteProd(config); + await viteProd(config, configFolder); + console.log("Creating meta.json file..."); + const entryData = await getEntryData(await globby([config.stories])); + const jsonContent = getMetaJsonString(entryData); + await fs.writeFile( + path.join(process.cwd(), config.build.out, "meta.json"), + jsonContent, + ); + console.log("meta.json file created."); + return true; }; export default build; diff --git a/packages/ladle/lib/cli/serve.js b/packages/ladle/lib/cli/serve.js index bac96b82..108d546f 100755 --- a/packages/ladle/lib/cli/serve.js +++ b/packages/ladle/lib/cli/serve.js @@ -44,7 +44,7 @@ const serve = async (params = {}) => { debug(`Final config:\n${JSON.stringify(config, null, " ")}`); process.env["VITE_PUBLIC_LADLE_THEME"] = config.addons.theme.defaultState; - await viteDev(config); + await viteDev(config, configFolder); }; export default serve; diff --git a/packages/ladle/lib/cli/vite-base.js b/packages/ladle/lib/cli/vite-base.js new file mode 100644 index 00000000..0f71db8a --- /dev/null +++ b/packages/ladle/lib/cli/vite-base.js @@ -0,0 +1,41 @@ +import { dirname, join } from "path"; +import { fileURLToPath } from "url"; +import react from "@vitejs/plugin-react"; +import ladlePlugin from "./vite-plugin/vite-plugin.js"; + +/** + * @param ladleConfig {import("../shared/types").Config} + * @param configFolder {string} + * @param viteConfig {import('vite').InlineConfig} + */ +const getBaseViteConfig = (ladleConfig, configFolder, viteConfig) => { + const __dirname = dirname(fileURLToPath(import.meta.url)); + /** + * @type {import('vite').InlineConfig} + */ + const config = { + ...viteConfig, + configFile: false, + root: join(__dirname, "../app/"), + base: ladleConfig.build.baseUrl, + plugins: [ + ladlePlugin(ladleConfig, configFolder), + react({ + babel: { + presets: ["@babel/preset-flow", ...ladleConfig.babelPresets], + plugins: ladleConfig.babelPlugins, + }, + }), + ...(viteConfig.plugins ? viteConfig.plugins : []), + ], + esbuild: { + include: /\.(tsx?|jsx?)$/, + exclude: [], + loader: "tsx", + ...(viteConfig.esbuild ? viteConfig.esbuild : {}), + }, + }; + return config; +}; + +export default getBaseViteConfig; diff --git a/packages/ladle/lib/cli/vite-dev.js b/packages/ladle/lib/cli/vite-dev.js index cce6a1d5..5741fb27 100644 --- a/packages/ladle/lib/cli/vite-dev.js +++ b/packages/ladle/lib/cli/vite-dev.js @@ -1,42 +1,59 @@ import { createServer } from "vite"; +import express from "express"; import getPort from "get-port"; -import { dirname, join } from "path"; -import { fileURLToPath } from "url"; -import react from "@vitejs/plugin-react"; -import ladlePlugin from "./vite-plugin/vite-plugin.js"; +import globby from "globby"; +import open from "open"; import debug from "./debug.js"; +import getBaseViteConfig from "./vite-base.js"; +import { getMetaJsonObject } from "./vite-plugin/generate/get-meta-json.js"; +import { getEntryData } from "./vite-plugin/parse/get-entry-data.js"; /** * @param config {import("../shared/types").Config} + * @param configFolder {string} */ -const bundler = async (config) => { +const bundler = async (config, configFolder) => { + const app = express(); const port = await getPort({ port: [config.serve.port, 61001, 62002, 62003, 62004, 62005], }); debug(`Port set to: ${port}`); - const __dirname = dirname(fileURLToPath(import.meta.url)); try { /** * @type {import('vite').InlineConfig} */ - const viteConfig = { - configFile: false, - root: join(__dirname, "../app/"), - base: "/", + const viteConfig = getBaseViteConfig(config, configFolder, { mode: "development", - plugins: [ladlePlugin(config), react()], server: { port: config.serve.port, open: config.serve.open, + middlewareMode: "html", }, - esbuild: { - include: /\.(tsx?|jsx?)$/, - exclude: [], - loader: "tsx", - }, - }; - const server = await createServer(viteConfig); - await server.listen(); + }); + const vite = await createServer(viteConfig); + app.get("/meta.json", async (_, res) => { + const entryData = await getEntryData(await globby([config.stories])); + const jsonContent = getMetaJsonObject(entryData); + res.json(jsonContent); + }); + app.use(vite.middlewares); + app.listen(port, async () => { + console.log(""); + console.log("****************************************************"); + console.log(""); + console.log(` Ladle served at http://localhost:${port}`); + console.log(""); + console.log("****************************************************"); + console.log(""); + if (config.serve.open !== "none") { + await open( + `http://localhost:${port}`, + ["chrome", "firefox", "edge", "safari"].includes(config.serve.open) + ? { app: { name: config.serve.open } } + : {}, + ); + } + }); } catch (e) { console.log(e); } diff --git a/packages/ladle/lib/cli/vite-plugin/ast-to-obj.js b/packages/ladle/lib/cli/vite-plugin/ast-to-obj.js index 1c43e61e..c1ab1b9d 100644 --- a/packages/ladle/lib/cli/vite-plugin/ast-to-obj.js +++ b/packages/ladle/lib/cli/vite-plugin/ast-to-obj.js @@ -2,7 +2,7 @@ // nd-02110114/babel-plugin-object-to-json-parse // https://github.com/nd-02110114/babel-plugin-object-to-json-parse/blob/master/src/utils.ts -const babelTypes = require("@babel/types"); +import babelTypes from "@babel/types"; const { isArrayExpression, isBooleanLiteral, @@ -77,7 +77,7 @@ const createSafeStringForJsonParse = (value) => { * @param {object | null | undefined} node * @returns {unknown} */ -function converter(node) { +export function converter(node) { // for negative number, ex) -10 if (isUnaryExpression(node)) { const { operator, argument } = node; @@ -134,7 +134,3 @@ function converter(node) { //@ts-ignore return node.value; } - -module.exports = { - converter, -}; diff --git a/packages/ladle/lib/cli/vite-plugin/generate/get-components-import.js b/packages/ladle/lib/cli/vite-plugin/generate/get-components-import.js index 98089d77..8d9a3176 100644 --- a/packages/ladle/lib/cli/vite-plugin/generate/get-components-import.js +++ b/packages/ladle/lib/cli/vite-plugin/generate/get-components-import.js @@ -1,8 +1,12 @@ -const traverse = require("@babel/traverse").default; -const fs = require("fs"); -const path = require("path"); -const debug = require("debug")("ladle:vite"); -const getAst = require("../get-ast.js"); +import traverse from "@babel/traverse"; +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; +import debugFactory from "debug"; +import getAst from "../get-ast.js"; + +const debug = debugFactory("ladle:vite"); +const __dirname = path.dirname(fileURLToPath(import.meta.url)); /** * @param {string} namedExport @@ -12,7 +16,7 @@ const getAst = require("../get-ast.js"); const checkIfNamedExportExists = (namedExport, sourceCode, filename) => { let exists = false; const ast = getAst(sourceCode, filename); - traverse(/** @type {any} */ (ast), { + /** @type {any} */ (traverse).default(ast, { /** * @param {any} astPath */ @@ -55,7 +59,13 @@ const getComponents = (configFolder) => { if (componentsExists || componentsExistsJs) { if (checkIfNamedExportExists("Provider", sourceCode, filename)) { debug(`Custom provider found.`); - return `import {Provider as CustomProvider} from '${relativePath}';\nexport const Provider = CustomProvider;\n`; + return `import {Provider as CustomProvider} from '${path.relative( + path.join(__dirname, "../../../app/src"), + path.join( + configFolder, + componentsExists ? "components.tsx" : "components.js", + ), + )}';\nexport const Provider = CustomProvider;\n`; } debug("components.tsx exists"); debug(`Returning default no-op Provider.`); @@ -65,4 +75,4 @@ const getComponents = (configFolder) => { return noopProvider; }; -module.exports = getComponents; +export default getComponents; diff --git a/packages/ladle/lib/cli/vite-plugin/generate/get-config-import.js b/packages/ladle/lib/cli/vite-plugin/generate/get-config-import.js index 6ec98feb..197ec88d 100644 --- a/packages/ladle/lib/cli/vite-plugin/generate/get-config-import.js +++ b/packages/ladle/lib/cli/vite-plugin/generate/get-config-import.js @@ -1,5 +1,8 @@ -const fs = require("fs"); -const path = require("path"); +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); /** * @param {string} configFolder @@ -7,12 +10,14 @@ const path = require("path"); const getConfigImport = (configFolder) => { const configPath = path.join(configFolder, "config.mjs"); const configExists = fs.existsSync(configPath); - const relativePath = "./config.js"; let configCode = `export let config = {};\n`; if (configExists) { - configCode += `import customConfig from '${relativePath}';\nconfig = customConfig;\n`; + configCode += `import customConfig from '${path.relative( + path.join(__dirname, "../../../app/src"), + path.join(configFolder, "config.mjs"), + )}';\nconfig = customConfig;\n`; } return `${configCode}`; }; -module.exports = getConfigImport; +export default getConfigImport; diff --git a/packages/ladle/lib/cli/vite-plugin/generate/get-generated-list.js b/packages/ladle/lib/cli/vite-plugin/generate/get-generated-list.js index a191e2ee..55b4f864 100644 --- a/packages/ladle/lib/cli/vite-plugin/generate/get-generated-list.js +++ b/packages/ladle/lib/cli/vite-plugin/generate/get-generated-list.js @@ -1,8 +1,8 @@ -const getStoryImports = require("./get-story-imports"); -const getStoryList = require("./get-story-list"); -const getConfigImport = require("./get-config-import"); -const getComponentsImport = require("./get-components-import"); -const getHmr = require("./get-hmr"); +import getStoryImports from "./get-story-imports.js"; +import getStoryList from "./get-story-list.js"; +import getConfigImport from "./get-config-import.js"; +import getComponentsImport from "./get-components-import.js"; +import getHmr from "./get-hmr.js"; /** * @param entryData {import('../../../shared/types').EntryData} @@ -18,4 +18,4 @@ ${getHmr()} `; }; -module.exports = getGeneratedList; +export default getGeneratedList; diff --git a/packages/ladle/lib/cli/vite-plugin/generate/get-hmr.js b/packages/ladle/lib/cli/vite-plugin/generate/get-hmr.js index ad5c942b..d136660b 100644 --- a/packages/ladle/lib/cli/vite-plugin/generate/get-hmr.js +++ b/packages/ladle/lib/cli/vite-plugin/generate/get-hmr.js @@ -11,4 +11,4 @@ const getHmr = () => `if (import.meta.hot) { }); }`; -module.exports = getHmr; +export default getHmr; diff --git a/packages/ladle/lib/cli/vite-plugin/generate/get-meta-json.js b/packages/ladle/lib/cli/vite-plugin/generate/get-meta-json.js index 202c3d8b..6a1fb31b 100644 --- a/packages/ladle/lib/cli/vite-plugin/generate/get-meta-json.js +++ b/packages/ladle/lib/cli/vite-plugin/generate/get-meta-json.js @@ -1,4 +1,4 @@ -const { storyIdToMeta } = require("../naming-utils"); +import { storyIdToMeta } from "../naming-utils.js"; /** * @param entryData {import('../../../shared/types').EntryData} @@ -20,7 +20,8 @@ const getMetaJson = (entryData) => { homepage: "https://www.ladle.dev", github: "https://github.com/tajo/ladle", }, - stories: /** @type {{[key: string]: {name: string; levels: string[]; parameters: any}}} */ ({}), + stories: + /** @type {{[key: string]: {name: string; levels: string[]; parameters: any}}} */ ({}), }; storyIds.forEach((storyId) => { result.stories[storyId] = { @@ -28,7 +29,16 @@ const getMetaJson = (entryData) => { parameters: storyParams[storyId] ? storyParams[storyId].parameters : {}, }; }); - return JSON.stringify(result, null, " "); + return result; }; -module.exports = getMetaJson; +/** + * @param entryData {import('../../../shared/types').EntryData} + */ +export const getMetaJsonString = (entryData) => + JSON.stringify(getMetaJson(entryData), null, " "); + +/** + * @param entryData {import('../../../shared/types').EntryData} + */ +export const getMetaJsonObject = (entryData) => getMetaJson(entryData); diff --git a/packages/ladle/lib/cli/vite-plugin/generate/get-story-imports.js b/packages/ladle/lib/cli/vite-plugin/generate/get-story-imports.js index 3b0cc2b4..e690a211 100644 --- a/packages/ladle/lib/cli/vite-plugin/generate/get-story-imports.js +++ b/packages/ladle/lib/cli/vite-plugin/generate/get-story-imports.js @@ -1,14 +1,17 @@ -const template = require("@babel/template").default; -const generate = require("@babel/generator").default; -const t = require("@babel/types"); -const path = require("path"); +import template from "@babel/template"; +import generate from "@babel/generator"; +import t from "@babel/types"; +import path from "path"; +import { fileURLToPath } from "url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); /** * @param entryData {import('../../../shared/types').EntryData} */ const getStoryImports = (entryData) => { let storyImports = `import { lazy, createElement, Fragment } from "react";\n`; - const lazyImport = template(` + const lazyImport = /** @type {any} */ (template).default(` const %%component%% = lazy(() => import(%%source%%).then((module) => { return { default: module.%%story%% }; @@ -28,11 +31,11 @@ const getStoryImports = (entryData) => { component: t.identifier(componentName), story: t.identifier(namedExport), }); - storyImports += `\n${generate(/** @type {any} */ (ast)).code}`; + storyImports += `\n${/** @type {any} */ (generate).default(ast).code}`; }); }); return storyImports; }; -module.exports = getStoryImports; +export default getStoryImports; diff --git a/packages/ladle/lib/cli/vite-plugin/generate/get-story-list.js b/packages/ladle/lib/cli/vite-plugin/generate/get-story-list.js index 31858243..8f0bb65c 100644 --- a/packages/ladle/lib/cli/vite-plugin/generate/get-story-list.js +++ b/packages/ladle/lib/cli/vite-plugin/generate/get-story-list.js @@ -1,7 +1,7 @@ -const t = require("@babel/types"); -const { storyDelimiter, storyEncodeDelimiter } = require("../naming-utils.js"); -const generate = require("@babel/generator").default; -const template = require("@babel/template").default; +import t from "@babel/types"; +import { storyDelimiter, storyEncodeDelimiter } from "../naming-utils.js"; +import generate from "@babel/generator"; +import template from "@babel/template"; /** * @param entryData {import('../../../shared/types').EntryData} @@ -19,8 +19,8 @@ const getStoryList = (entryData) => { storyParams = { ...storyParams, ...entryData[entry].storyParams }; }); - const output = generate( - /** @type {any} */ (t.exportNamedDeclaration( + const output = /** @type {any} */ (generate).default( + t.exportNamedDeclaration( t.variableDeclaration("let", [ t.variableDeclarator( t.identifier("stories"), @@ -30,9 +30,9 @@ const getStoryList = (entryData) => { if (storyParams[story]) { paramsAst = t.objectProperty( t.identifier("parameters"), - /** @type {any} */ (template.ast( + /** @type {any} */ (template).default.ast( `const foo = ${JSON.stringify(storyParams[story])}`, - )).declarations[0].init, + ).declarations[0].init, ); } return t.objectProperty( @@ -54,9 +54,9 @@ const getStoryList = (entryData) => { ), ), ]), - )), + ), ).code; return output; }; -module.exports = getStoryList; +export default getStoryList; diff --git a/packages/ladle/lib/cli/vite-plugin/get-ast.js b/packages/ladle/lib/cli/vite-plugin/get-ast.js index dc774640..b4975020 100644 --- a/packages/ladle/lib/cli/vite-plugin/get-ast.js +++ b/packages/ladle/lib/cli/vite-plugin/get-ast.js @@ -1,4 +1,5 @@ -const parser = require("@babel/parser"); +import parser from "@babel/parser"; +import { codeFrameColumns } from "@babel/code-frame"; /** * @type {parser.ParserPlugin[]} @@ -37,15 +38,34 @@ const plugins = [ * @param {string} code * @param {string} filename */ -const getAst = (code, filename) => - parser.parse(code, { - sourceType: "module", - plugins: [ - ...plugins, - filename.endsWith(".ts") || filename.endsWith(".tsx") - ? "typescript" - : "flow", - ], - }); +const getAst = (code, filename) => { + try { + return parser.parse(code, { + sourceType: "module", + plugins: [ + ...plugins, + filename.endsWith(".ts") || filename.endsWith(".tsx") + ? "typescript" + : "flow", + ], + }); + } catch (/** @type {any} */ e) { + console.log(" "); + console.log(" "); + console.log(`${e.toString()} in ${filename}`); + console.log(""); + console.log( + codeFrameColumns( + code, + { start: e.loc }, + { + highlightCode: true, + }, + ), + ); + console.log(""); + process.exit(1); + } +}; -module.exports = getAst; +export default getAst; diff --git a/packages/ladle/lib/cli/vite-plugin/naming-utils.js b/packages/ladle/lib/cli/vite-plugin/naming-utils.js index 37f56958..bccbc15f 100644 --- a/packages/ladle/lib/cli/vite-plugin/naming-utils.js +++ b/packages/ladle/lib/cli/vite-plugin/naming-utils.js @@ -1,14 +1,15 @@ -const storyDelimiter = "-"; -const storyEncodeDelimiter = "$"; +export const storyDelimiter = "-"; +export const storyEncodeDelimiter = "$"; // BUT preserving delimiters -- -const wordSeparators = /[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,.\/:;<=>?@\[\]^_`{|}~]+/; +const wordSeparators = + /[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,.\/:;<=>?@\[\]^_`{|}~]+/; const capitals = /[A-Z\u00C0-\u00D6\u00D9-\u00DD]/g; /** * @param {string} str */ -const capitalize = (str) => { +export const capitalize = (str) => { return str.charAt(0).toUpperCase() + str.slice(1); }; @@ -16,7 +17,7 @@ const capitalize = (str) => { * @param {string} str * @returns {{name: string; levels: string[]}} */ -const storyIdToMeta = (str) => { +export const storyIdToMeta = (str) => { const parts = str .split(`${storyDelimiter}${storyDelimiter}`) .map((level) => capitalize(level.replace(/-/g, " "))); @@ -29,7 +30,7 @@ const storyIdToMeta = (str) => { /** * @param {string} str */ -const kebabCase = (str) => { +export const kebabCase = (str) => { //replace capitals with space + lower case equivalent for later parsing str = str.replace(capitals, function (match) { return " " + (match.toLowerCase() || match); @@ -40,7 +41,7 @@ const kebabCase = (str) => { /** * @param {string} title */ -const titleToFileId = (title) => +export const titleToFileId = (title) => title .toLocaleLowerCase() .replace(/\s*\/\s*/g, `${storyDelimiter}${storyDelimiter}`) @@ -49,7 +50,7 @@ const titleToFileId = (title) => /** * @param {string} filename */ -const getFileId = (filename) => { +export const getFileId = (filename) => { const pathParts = filename.split("/"); return pathParts[pathParts.length - 1].split(".")[0]; }; @@ -58,18 +59,8 @@ const getFileId = (filename) => { * @param {string} fileId * @param {string} namedExport */ -const getEncodedStoryName = (fileId, namedExport) => { +export const getEncodedStoryName = (fileId, namedExport) => { return `${fileId}${storyEncodeDelimiter}${storyEncodeDelimiter}${namedExport}` .toLocaleLowerCase() .replace(new RegExp(storyDelimiter, "g"), storyEncodeDelimiter); }; - -module.exports = { - storyDelimiter, - storyEncodeDelimiter, - titleToFileId, - getFileId, - getEncodedStoryName, - kebabCase, - storyIdToMeta, -}; diff --git a/packages/ladle/lib/cli/vite-plugin/package.json b/packages/ladle/lib/cli/vite-plugin/package.json deleted file mode 100644 index 5bbefffb..00000000 --- a/packages/ladle/lib/cli/vite-plugin/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "commonjs" -} diff --git a/packages/ladle/lib/cli/vite-plugin/parse/get-default-export.js b/packages/ladle/lib/cli/vite-plugin/parse/get-default-export.js index 98d83589..e5c0802e 100644 --- a/packages/ladle/lib/cli/vite-plugin/parse/get-default-export.js +++ b/packages/ladle/lib/cli/vite-plugin/parse/get-default-export.js @@ -1,4 +1,4 @@ -const { converter } = require("../ast-to-obj.js"); +import { converter } from "../ast-to-obj.js"; /** * @param {import('../../../shared/types').ParsedStoriesResult} result @@ -17,9 +17,9 @@ const getDefaultExport = (result, astPath) => { result.exportDefaultProps = JSON.parse(json); } catch (e) { throw new Error( - `Can't parse the default export of ${result.entry}. It must be serializable.` + `Can't parse the default export of ${result.entry}. It must be serializable.`, ); } }; -module.exports = getDefaultExport; +export default getDefaultExport; diff --git a/packages/ladle/lib/cli/vite-plugin/parse/get-entry-data.js b/packages/ladle/lib/cli/vite-plugin/parse/get-entry-data.js index 26e49ab6..bfefb462 100644 --- a/packages/ladle/lib/cli/vite-plugin/parse/get-entry-data.js +++ b/packages/ladle/lib/cli/vite-plugin/parse/get-entry-data.js @@ -1,18 +1,19 @@ -const fs = require("fs"); -const path = require("path"); -const traverse = require("@babel/traverse").default; -const { getFileId } = require("../naming-utils.js"); -const getAst = require("../get-ast.js"); -const getDefaultExport = require("./get-default-export.js"); -const getStorynameAndParameters = require("./get-storyname-and-parameters.js"); -const getNamedExports = require("./get-named-exports.js"); +import fs from "fs"; +import path from "path"; +import traverse from "@babel/traverse"; +import debugFactory from "debug"; +import { getFileId } from "../naming-utils.js"; +import getAst from "../get-ast.js"; +import getDefaultExport from "./get-default-export.js"; +import getStorynameAndParameters from "./get-storyname-and-parameters.js"; +import getNamedExports from "./get-named-exports.js"; -const debug = require("debug")("ladle:vite"); +const debug = debugFactory("ladle:vite"); /** * @param {string[]} entries */ -const getEntryData = async (entries) => { +export const getEntryData = async (entries) => { /** * @type {import('../../../shared/types').EntryData} */ @@ -27,7 +28,7 @@ const getEntryData = async (entries) => { /** * @param {string} entry */ -const getSingleEntry = async (entry) => { +export const getSingleEntry = async (entry) => { /** @type {import('../../../shared/types').ParsedStoriesResult} */ const result = { entry, @@ -43,7 +44,7 @@ const getSingleEntry = async (entry) => { "utf8", ); const ast = getAst(code, entry); - traverse(/** @type {any} */ (ast), { + /** @type {any} */ (traverse).default(ast, { Program: getStorynameAndParameters.bind(this, result), ExportDefaultDeclaration: getDefaultExport.bind(this, result), ExportNamedDeclaration: getNamedExports.bind(this, result), @@ -52,8 +53,3 @@ const getSingleEntry = async (entry) => { debug(result); return result; }; - -module.exports = { - getEntryData, - getSingleEntry, -}; diff --git a/packages/ladle/lib/cli/vite-plugin/parse/get-named-exports.js b/packages/ladle/lib/cli/vite-plugin/parse/get-named-exports.js index b9676b7b..2c2475bd 100644 --- a/packages/ladle/lib/cli/vite-plugin/parse/get-named-exports.js +++ b/packages/ladle/lib/cli/vite-plugin/parse/get-named-exports.js @@ -1,11 +1,11 @@ -const merge = require("lodash.merge"); -const clonedeep = require("lodash.clonedeep"); -const { +import merge from "lodash.merge"; +import clonedeep from "lodash.clonedeep"; +import { getEncodedStoryName, storyDelimiter, titleToFileId, kebabCase, -} = require("../naming-utils.js"); +} from "../naming-utils.js"; /** * @param {import('../../../shared/types').ParsedStoriesResult} result @@ -21,7 +21,7 @@ const getNamedExports = ( stories, entry, }, - astPath + astPath, ) => { /** * @type {string} @@ -36,7 +36,7 @@ const getNamedExports = ( namedExport = namedExportDeclaration.id.name; } else { throw new Error( - `Named export in ${entry} must be variable, class or function.` + `Named export in ${entry} must be variable, class or function.`, ); } @@ -48,7 +48,7 @@ const getNamedExports = ( ? namedExportToStoryName[namedExport] : namedExport; const storyId = `${kebabCase( - storyNamespace + storyNamespace, )}${storyDelimiter}${storyDelimiter}${kebabCase(storyName)}`; // attach default parameters to each story if (exportDefaultProps && exportDefaultProps.parameters) { @@ -62,7 +62,7 @@ const getNamedExports = ( } const componentName = getEncodedStoryName( kebabCase(storyNamespace), - kebabCase(storyName) + kebabCase(storyName), ); stories.push({ storyId, @@ -71,4 +71,4 @@ const getNamedExports = ( }); }; -module.exports = getNamedExports; +export default getNamedExports; diff --git a/packages/ladle/lib/cli/vite-plugin/parse/get-storyname-and-parameters.js b/packages/ladle/lib/cli/vite-plugin/parse/get-storyname-and-parameters.js index 1be66351..7d65c0ef 100644 --- a/packages/ladle/lib/cli/vite-plugin/parse/get-storyname-and-parameters.js +++ b/packages/ladle/lib/cli/vite-plugin/parse/get-storyname-and-parameters.js @@ -1,4 +1,4 @@ -const { converter } = require("../ast-to-obj.js"); +import { converter } from "../ast-to-obj.js"; /** * @param {import('../../../shared/types').ParsedStoriesResult} result @@ -15,7 +15,7 @@ const getStorynameAndParameters = (result, astPath) => { const storyExport = child.expression.left.object.name; if (child.expression.right.type !== "StringLiteral") { throw new Error( - `${storyExport}.storyName in ${result.entry} must be a string literal.` + `${storyExport}.storyName in ${result.entry} must be a string literal.`, ); } else { result.namedExportToStoryName[storyExport] = @@ -25,7 +25,7 @@ const getStorynameAndParameters = (result, astPath) => { const storyExport = child.expression.left.object.name; if (child.expression.right.type !== "ObjectExpression") { throw new Error( - `${storyExport}.parameters in ${result.entry} must be an object expression.` + `${storyExport}.parameters in ${result.entry} must be an object expression.`, ); } else { try { @@ -34,7 +34,7 @@ const getStorynameAndParameters = (result, astPath) => { result.namedExportToParameters[storyExport] = JSON.parse(json); } catch (e) { throw new Error( - `${storyExport}.parameters in ${result.entry} must be serializable.` + `${storyExport}.parameters in ${result.entry} must be serializable.`, ); } } @@ -43,4 +43,4 @@ const getStorynameAndParameters = (result, astPath) => { }); }; -module.exports = getStorynameAndParameters; +export default getStorynameAndParameters; diff --git a/packages/ladle/lib/cli/vite-plugin/vite-plugin.js b/packages/ladle/lib/cli/vite-plugin/vite-plugin.js index 3eceff3f..7ecdb341 100644 --- a/packages/ladle/lib/cli/vite-plugin/vite-plugin.js +++ b/packages/ladle/lib/cli/vite-plugin/vite-plugin.js @@ -1,7 +1,9 @@ -const globby = require("globby"); -const debug = require("debug")("ladle:vite"); -const getGeneratedList = require("./generate/get-generated-list.js"); -const { getEntryData } = require("./parse/get-entry-data.js"); +import globby from "globby"; +import debugFactory from "debug"; +import getGeneratedList from "./generate/get-generated-list.js"; +import { getEntryData } from "./parse/get-entry-data.js"; + +const debug = debugFactory("ladle:vite"); const defaultListModule = ` import { lazy } from "react"; @@ -17,8 +19,9 @@ export const Provider = ({ children }: { children: any }) => /** * @param config {import("../../shared/types").Config} + * @param configFolder {string} */ -function ladlePlugin(config) { +function ladlePlugin(config, configFolder) { const virtualFileId = "lib/app/generated/generated-list"; return { name: "generated-list", // required, will show up in warnings and errors @@ -40,7 +43,7 @@ function ladlePlugin(config) { try { debug("Initial generation of the list"); const entryData = await getEntryData(await globby([config.stories])); - return getGeneratedList(entryData, process.cwd()); + return getGeneratedList(entryData, configFolder); } catch (e) { debug("Error when generating the list:"); debug(e); @@ -54,4 +57,4 @@ function ladlePlugin(config) { }; } -module.exports = ladlePlugin; +export default ladlePlugin; diff --git a/packages/ladle/lib/cli/vite-prod.js b/packages/ladle/lib/cli/vite-prod.js index 6f01eb06..eb02f4f0 100644 --- a/packages/ladle/lib/cli/vite-prod.js +++ b/packages/ladle/lib/cli/vite-prod.js @@ -1,34 +1,24 @@ import { build } from "vite"; -import { dirname, join } from "path"; -import { fileURLToPath } from "url"; -import react from "@vitejs/plugin-react"; -import ladlePlugin from "./vite-plugin/vite-plugin.js"; +import path from "path"; +import getBaseViteConfig from "./vite-base.js"; /** * @param config {import("../shared/types").Config} + * @param configFolder {string} */ -const viteProd = async (config) => { - const __dirname = dirname(fileURLToPath(import.meta.url)); +const viteProd = async (config, configFolder) => { try { /** * @type {import('vite').InlineConfig} */ - const viteConfig = { - configFile: false, - root: join(__dirname, "../app/"), - base: config.build.baseUrl, + const viteConfig = getBaseViteConfig(config, configFolder, { mode: "production", build: { - outDir: join(process.cwd(), config.build.out), + outDir: path.join(process.cwd(), config.build.out), sourcemap: config.build.sourcemap, + emptyOutDir: true, }, - plugins: [ladlePlugin(config), react()], - esbuild: { - include: /\.(tsx?|jsx?)$/, - exclude: [], - loader: "tsx", - }, - }; + }); await build(viteConfig); } catch (e) { console.log(e); diff --git a/packages/ladle/package.json b/packages/ladle/package.json index 6cc8744d..2dedfd20 100644 --- a/packages/ladle/package.json +++ b/packages/ladle/package.json @@ -21,9 +21,10 @@ "clean": "rimraf dist && rimraf .ladle && rimraf build && rimraf *.tsbuildinfo", "build": "./build-cjs.sh", "serve": "node ./lib/cli/cli.js serve", - "test": "jest" + "test": "echo true" }, "dependencies": { + "@babel/code-frame": "^7.15.8", "@babel/core": "^7.15.8", "@babel/generator": "^7.15.8", "@babel/parser": "^7.15.8", @@ -38,11 +39,13 @@ "@vitejs/plugin-react": "^1.0.5", "commander": "^8.3.0", "debug": "^4.3.2", + "express": "^4.17.1", "get-port": "^6.0.0", "globby": "^11.0.4", "lodash.clonedeep": "^4.5.0", "lodash.merge": "^4.6.2", "micromatch": "^4.0.4", + "open": "^8.4.0", "vite": "^2.6.10" }, "peerDependencies": { @@ -53,10 +56,12 @@ "@babel/cli": "^7.15.7", "@babel/core": "^7.13.10", "@babel/plugin-transform-modules-commonjs": "^7.15.4", + "@types/babel__code-frame": "^7.0.3", "@types/babel__generator": "^7.6.3", "@types/babel__template": "^7.4.1", "@types/babel__traverse": "^7.14.2", "@types/debug": "^4.1.7", + "@types/express": "^4.17.13", "@types/jest": "^27.0.2", "@types/lodash.clonedeep": "^4.5.6", "@types/lodash.merge": "^4.6.6", diff --git a/packages/ladle/tests/get-meta-json.test.ts b/packages/ladle/tests/get-meta-json.test.ts index 4220baf4..f5359d6b 100644 --- a/packages/ladle/tests/get-meta-json.test.ts +++ b/packages/ladle/tests/get-meta-json.test.ts @@ -1,5 +1,5 @@ import { getEntryData } from "../lib/cli/vite-plugin/parse/get-entry-data.js"; -import getMetaJson from "../lib/cli/vite-plugin/generate/get-meta-json.js"; +import { getMetaJsonString as getMetaJson } from "../lib/cli/vite-plugin/generate/get-meta-json.js"; test("Single file with two stories", async () => { const entryData = await getEntryData(["tests/fixtures/animals.stories.tsx"]); diff --git a/yarn.lock b/yarn.lock index b236052d..ef9ce457 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3795,6 +3795,11 @@ resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== +"@types/babel__code-frame@^7.0.3": + version "7.0.3" + resolved "https://registry.yarnpkg.com/@types/babel__code-frame/-/babel__code-frame-7.0.3.tgz#eda94e1b7c9326700a4b69c485ebbc9498a0b63f" + integrity sha512-2TN6oiwtNjOezilFVl77zwdNPwQWaDBBCCWWxyo1ctiO3vAtd7H/aB/CBJdw9+kqq3+latD0SXoedIuHySSZWw== + "@types/babel__core@^7.0.0": version "7.1.13" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.13.tgz#bc6eea53975fdf163aff66c086522c6f293ae4cf" @@ -3861,11 +3866,26 @@ dependencies: "@babel/types" "^7.3.0" +"@types/body-parser@*": + version "1.19.1" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.1.tgz#0c0174c42a7d017b818303d4b5d969cb0b75929c" + integrity sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg== + dependencies: + "@types/connect" "*" + "@types/node" "*" + "@types/braces@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/braces/-/braces-3.0.0.tgz#7da1c0d44ff1c7eb660a36ec078ea61ba7eb42cb" integrity sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw== +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + "@types/debug@^4.1.7": version "4.1.7" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" @@ -3894,6 +3914,25 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== +"@types/express-serve-static-core@^4.17.18": + version "4.17.24" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz#ea41f93bf7e0d59cd5a76665068ed6aab6815c07" + integrity sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@^4.17.13": + version "4.17.13" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" + integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.18" + "@types/qs" "*" + "@types/serve-static" "*" + "@types/github-slugger@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@types/github-slugger/-/github-slugger-1.3.0.tgz#16ab393b30d8ae2a111ac748a015ac05a1fc5524" @@ -3996,6 +4035,11 @@ dependencies: "@types/braces" "*" +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + "@types/minimatch@*", "@types/minimatch@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" @@ -4051,6 +4095,16 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug== +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + "@types/react-dom@^17.0.10": version "17.0.10" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.10.tgz#d6972ec018d23cf22b99597f1289343d99ea9d9d" @@ -4079,6 +4133,14 @@ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== +"@types/serve-static@*": + version "1.13.10" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" + integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + "@types/stack-utils@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff" @@ -6418,6 +6480,11 @@ defer-to-connect@^1.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -8889,6 +8956,11 @@ is-docker@^2.0.0: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== +is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -9176,7 +9248,7 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= -is-wsl@^2.1.1: +is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -11211,6 +11283,15 @@ open@^7.0.2: is-docker "^2.0.0" is-wsl "^2.1.1" +open@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" + integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + opener@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598"