From a73281d46dd07014fa54414d52afcf17b0fd29ef Mon Sep 17 00:00:00 2001 From: Joseph Garrone Date: Sat, 9 Nov 2024 14:02:19 +0100 Subject: [PATCH] Checkpoint --- scripts/build/main.ts | 2 +- src/bin/add-story.ts | 21 ++-- src/bin/eject-page.ts | 19 ++-- src/bin/main.ts | 28 +++--- ...tUiModuleFileSourceCodeReadyToBeCopied.ts} | 38 ++++--- src/bin/postinstall/index.ts | 1 + .../installUiModulesPeerDependencies.ts | 0 .../managedGitignoreFile.ts | 0 src/bin/postinstall/postinstall.ts | 79 +++++++++++++++ .../uiModuleMeta.ts | 99 ++++++++++++------- src/bin/shared/buildContext.ts | 10 +- src/bin/shared/constants.ts | 2 + src/bin/sync-ui-modules/index.ts | 1 - src/bin/sync-ui-modules/sync-ui-modules.ts | 13 --- src/bin/tools/getInstalledModuleDirPath.ts | 8 +- src/bin/tools/listInstalledModules.ts | 7 +- 16 files changed, 224 insertions(+), 104 deletions(-) rename src/bin/{sync-ui-modules/getSourceCodeToCopyInUserCodebase.ts => postinstall/getUiModuleFileSourceCodeReadyToBeCopied.ts} (57%) create mode 100644 src/bin/postinstall/index.ts rename src/bin/{sync-ui-modules => postinstall}/installUiModulesPeerDependencies.ts (100%) rename src/bin/{sync-ui-modules => postinstall}/managedGitignoreFile.ts (100%) create mode 100644 src/bin/postinstall/postinstall.ts rename src/bin/{sync-ui-modules => postinstall}/uiModuleMeta.ts (71%) delete mode 100644 src/bin/sync-ui-modules/index.ts delete mode 100644 src/bin/sync-ui-modules/sync-ui-modules.ts diff --git a/scripts/build/main.ts b/scripts/build/main.ts index 097c886a..2fdcdbc6 100644 --- a/scripts/build/main.ts +++ b/scripts/build/main.ts @@ -115,7 +115,7 @@ import { vendorFrontendDependencies } from "./vendorFrontendDependencies"; } run( - `npx ncc build ${join("dist", "vite-plugin", "index.js")} -o ${join( + `npx ncc build ${join("dist", "vite-plugin", "index.js")} --external prettier -o ${join( "dist", "ncc_out" )}` diff --git a/src/bin/add-story.ts b/src/bin/add-story.ts index dc528a5e..8b82e80e 100644 --- a/src/bin/add-story.ts +++ b/src/bin/add-story.ts @@ -14,7 +14,7 @@ import { kebabCaseToCamelCase } from "./tools/kebabCaseToSnakeCase"; import { assert, Equals } from "tsafe/assert"; import type { BuildContext } from "./shared/buildContext"; import chalk from "chalk"; -import { runFormat } from "./tools/runFormat"; +import { runPrettier, getIsPrettierAvailable } from "./tools/runPrettier"; import { maybeDelegateCommandToCustomHandler } from "./shared/customHandler_delegate"; export async function command(params: { buildContext: BuildContext }) { @@ -119,7 +119,7 @@ export async function command(params: { buildContext: BuildContext }) { process.exit(-1); } - const componentCode = fs + let sourceCode = fs .readFileSync( pathJoin( getThisCodebaseRootDirPath(), @@ -133,6 +133,17 @@ export async function command(params: { buildContext: BuildContext }) { .replace('import React from "react";\n', "") .replace(/from "[./]+dist\//, 'from "keycloakify/'); + run_prettier: { + if (!(await getIsPrettierAvailable())) { + break run_prettier; + } + + sourceCode = await runPrettier({ + filePath: targetFilePath, + sourceCode: sourceCode + }); + } + { const targetDirPath = pathDirname(targetFilePath); @@ -141,11 +152,7 @@ export async function command(params: { buildContext: BuildContext }) { } } - fs.writeFileSync(targetFilePath, Buffer.from(componentCode, "utf8")); - - runFormat({ - packageJsonFilePath: buildContext.packageJsonFilePath - }); + fs.writeFileSync(targetFilePath, Buffer.from(sourceCode, "utf8")); console.log( [ diff --git a/src/bin/eject-page.ts b/src/bin/eject-page.ts index a138cdc8..da9c16d2 100644 --- a/src/bin/eject-page.ts +++ b/src/bin/eject-page.ts @@ -22,7 +22,7 @@ import { assert, Equals } from "tsafe/assert"; import type { BuildContext } from "./shared/buildContext"; import chalk from "chalk"; import { maybeDelegateCommandToCustomHandler } from "./shared/customHandler_delegate"; -import { runFormat } from "./tools/runFormat"; +import { runPrettier, getIsPrettierAvailable } from "./tools/runPrettier"; export async function command(params: { buildContext: BuildContext }) { const { buildContext } = params; @@ -217,7 +217,7 @@ export async function command(params: { buildContext: BuildContext }) { process.exit(-1); } - const componentCode = fs + let componentCode = fs .readFileSync( pathJoin( getThisCodebaseRootDirPath(), @@ -229,6 +229,17 @@ export async function command(params: { buildContext: BuildContext }) { ) .toString("utf8"); + run_prettier: { + if (!(await getIsPrettierAvailable())) { + break run_prettier; + } + + componentCode = await runPrettier({ + filePath: targetFilePath, + sourceCode: componentCode + }); + } + { const targetDirPath = pathDirname(targetFilePath); @@ -239,10 +250,6 @@ export async function command(params: { buildContext: BuildContext }) { fs.writeFileSync(targetFilePath, Buffer.from(componentCode, "utf8")); - runFormat({ - packageJsonFilePath: buildContext.packageJsonFilePath - }); - console.log( `${chalk.green("✓")} ${chalk.bold( pathJoin(".", pathRelative(process.cwd(), targetFilePath)) diff --git a/src/bin/main.ts b/src/bin/main.ts index 0047b715..15c73167 100644 --- a/src/bin/main.ts +++ b/src/bin/main.ts @@ -197,20 +197,6 @@ program } }); -program - .command({ - name: "initialize-admin-theme", - description: "Initialize the admin theme." - }) - .task({ - skip, - handler: async ({ projectDirPath }) => { - const { command } = await import("./initialize-admin-theme"); - - await command({ buildContext: getBuildContext({ projectDirPath }) }); - } - }); - program .command({ name: "copy-keycloak-resources-to-public", @@ -241,6 +227,20 @@ program } }); +program + .command({ + name: "postinstall", + description: "Initialize all the Keycloakify UI modules installed in the project." + }) + .task({ + skip, + handler: async ({ projectDirPath }) => { + const { command } = await import("./postinstall"); + + await command({ buildContext: getBuildContext({ projectDirPath }) }); + } + }); + // Fallback to build command if no command is provided { const [, , ...rest] = process.argv; diff --git a/src/bin/sync-ui-modules/getSourceCodeToCopyInUserCodebase.ts b/src/bin/postinstall/getUiModuleFileSourceCodeReadyToBeCopied.ts similarity index 57% rename from src/bin/sync-ui-modules/getSourceCodeToCopyInUserCodebase.ts rename to src/bin/postinstall/getUiModuleFileSourceCodeReadyToBeCopied.ts index 8306e67d..6855c0b1 100644 --- a/src/bin/sync-ui-modules/getSourceCodeToCopyInUserCodebase.ts +++ b/src/bin/postinstall/getUiModuleFileSourceCodeReadyToBeCopied.ts @@ -3,6 +3,7 @@ import * as fsPr from "fs/promises"; import { join as pathJoin, sep as pathSep } from "path"; import { assert } from "tsafe/assert"; import type { BuildContext } from "../shared/buildContext"; +import { KEYCLOAK_THEME } from "../shared/constants"; export type BuildContextLike = { themeSrcDirPath: string; @@ -10,27 +11,32 @@ export type BuildContextLike = { assert(); -export async function getSourceCodeToCopyInUserCodebase(params: { +export async function getUiModuleFileSourceCodeReadyToBeCopied(params: { buildContext: BuildContextLike; - relativeFromDirPath: string; fileRelativePath: string; - commentData: { - isForEjection: boolean; - uiModuleName: string; - uiModuleVersion: string; - }; -}): Promise { - const { buildContext, relativeFromDirPath, fileRelativePath, commentData } = params; + isForEjection: boolean; + uiModuleDirPath: string; + uiModuleName: string; + uiModuleVersion: string; +}): Promise { + const { + buildContext, + uiModuleDirPath, + fileRelativePath, + isForEjection, + uiModuleName, + uiModuleVersion + } = params; let sourceCode = ( - await fsPr.readFile(pathJoin(relativeFromDirPath, fileRelativePath)) + await fsPr.readFile(pathJoin(uiModuleDirPath, KEYCLOAK_THEME, fileRelativePath)) ).toString("utf8"); const comment = (() => { - if (commentData.isForEjection) { + if (isForEjection) { return [ `/*`, - ` This file was ejected from ${commentData.uiModuleName} version ${commentData.uiModuleVersion}.`, + ` This file was ejected from ${uiModuleName} version ${uiModuleVersion}.`, `*/` ].join("\n"); } else { @@ -39,7 +45,7 @@ export async function getSourceCodeToCopyInUserCodebase(params: { ` WARNING: Before modifying this file run the following command:`, ` \`npx keycloakify eject-file ${fileRelativePath.split(pathSep).join("/")}\``, ` `, - ` This file comes from ${commentData.uiModuleName} version ${commentData.uiModuleVersion}.`, + ` This file comes from ${uiModuleName} version ${uiModuleVersion}.`, `*/` ]; } @@ -47,16 +53,18 @@ export async function getSourceCodeToCopyInUserCodebase(params: { sourceCode = [comment, ``, sourceCode].join("\n"); + const destFilePath = pathJoin(buildContext.themeSrcDirPath, fileRelativePath); + format: { if (!(await getIsPrettierAvailable())) { break format; } sourceCode = await runPrettier({ - filePath: pathJoin(buildContext.themeSrcDirPath, fileRelativePath), + filePath: destFilePath, sourceCode }); } - return sourceCode; + return Buffer.from(sourceCode, "utf8"); } diff --git a/src/bin/postinstall/index.ts b/src/bin/postinstall/index.ts new file mode 100644 index 00000000..7f1cc290 --- /dev/null +++ b/src/bin/postinstall/index.ts @@ -0,0 +1 @@ +export * from "./postinstall"; diff --git a/src/bin/sync-ui-modules/installUiModulesPeerDependencies.ts b/src/bin/postinstall/installUiModulesPeerDependencies.ts similarity index 100% rename from src/bin/sync-ui-modules/installUiModulesPeerDependencies.ts rename to src/bin/postinstall/installUiModulesPeerDependencies.ts diff --git a/src/bin/sync-ui-modules/managedGitignoreFile.ts b/src/bin/postinstall/managedGitignoreFile.ts similarity index 100% rename from src/bin/sync-ui-modules/managedGitignoreFile.ts rename to src/bin/postinstall/managedGitignoreFile.ts diff --git a/src/bin/postinstall/postinstall.ts b/src/bin/postinstall/postinstall.ts new file mode 100644 index 00000000..6b06f8e4 --- /dev/null +++ b/src/bin/postinstall/postinstall.ts @@ -0,0 +1,79 @@ +import type { BuildContext } from "../shared/buildContext"; +import { getUiModuleMetas, computeHash } from "./uiModuleMeta"; +import { installUiModulesPeerDependencies } from "./installUiModulesPeerDependencies"; +import { + readManagedGitignoreFile, + writeManagedGitignoreFile +} from "./managedGitignoreFile"; +import { dirname as pathDirname } from "path"; +import { join as pathJoin } from "path"; +import { existsAsync } from "../tools/fs.existsAsync"; +import * as fsPr from "fs/promises"; + +export async function command(params: { buildContext: BuildContext }) { + const { buildContext } = params; + + const uiModuleMetas = await getUiModuleMetas({ buildContext }); + + await installUiModulesPeerDependencies({ + buildContext, + uiModuleMetas + }); + + const { ejectedFilesRelativePaths } = await readManagedGitignoreFile({ + buildContext + }); + + await writeManagedGitignoreFile({ + buildContext, + ejectedFilesRelativePaths, + uiModuleMetas + }); + + await Promise.all( + uiModuleMetas + .map(uiModuleMeta => + Promise.all( + uiModuleMeta.files.map( + async ({ fileRelativePath, copyableFilePath, hash }) => { + if (ejectedFilesRelativePaths.includes(fileRelativePath)) { + return; + } + + const destFilePath = pathJoin( + buildContext.themeSrcDirPath, + fileRelativePath + ); + + skip_condition: { + if (!(await existsAsync(destFilePath))) { + break skip_condition; + } + + const destFileHash = computeHash( + await fsPr.readFile(destFilePath) + ); + + if (destFileHash !== hash) { + break skip_condition; + } + + return; + } + + { + const dirName = pathDirname(copyableFilePath); + + if (!(await existsAsync(dirName))) { + await fsPr.mkdir(dirName, { recursive: true }); + } + } + + await fsPr.copyFile(copyableFilePath, destFilePath); + } + ) + ) + ) + .flat() + ); +} diff --git a/src/bin/sync-ui-modules/uiModuleMeta.ts b/src/bin/postinstall/uiModuleMeta.ts similarity index 71% rename from src/bin/sync-ui-modules/uiModuleMeta.ts rename to src/bin/postinstall/uiModuleMeta.ts index 9347e326..24cdcd33 100644 --- a/src/bin/sync-ui-modules/uiModuleMeta.ts +++ b/src/bin/postinstall/uiModuleMeta.ts @@ -1,7 +1,7 @@ import { assert, type Equals } from "tsafe/assert"; import { id } from "tsafe/id"; import { z } from "zod"; -import { join as pathJoin, sep as pathSep, dirname as pathDirname } from "path"; +import { join as pathJoin, dirname as pathDirname } from "path"; import * as fsPr from "fs/promises"; import type { BuildContext } from "../shared/buildContext"; import { is } from "tsafe/is"; @@ -11,10 +11,11 @@ import { crawlAsync } from "../tools/crawlAsync"; import { getIsPrettierAvailable, getPrettierAndConfig } from "../tools/runPrettier"; import { readThisNpmPackageVersion } from "../tools/readThisNpmPackageVersion"; import { - getSourceCodeToCopyInUserCodebase, - type BuildContextLike as BuildContextLike_getSourceCodeToCopyInUserCodebase -} from "./getSourceCodeToCopyInUserCodebase"; + getUiModuleFileSourceCodeReadyToBeCopied, + type BuildContextLike as BuildContextLike_getUiModuleFileSourceCodeReadyToBeCopied +} from "./getUiModuleFileSourceCodeReadyToBeCopied"; import * as crypto from "crypto"; +import { KEYCLOAK_THEME } from "../shared/constants"; export type UiModuleMeta = { moduleName: string; @@ -22,6 +23,7 @@ export type UiModuleMeta = { files: { fileRelativePath: string; hash: string; + copyableFilePath: string; }[]; peerDependencies: Record; }; @@ -35,7 +37,8 @@ const zUiModuleMeta = (() => { files: z.array( z.object({ fileRelativePath: z.string(), - hash: z.string() + hash: z.string(), + copyableFilePath: z.string() }) ), peerDependencies: z.record(z.string()) @@ -51,7 +54,7 @@ const zUiModuleMeta = (() => { type ParsedCacheFile = { keycloakifyVersion: string; prettierConfigHash: string | null; - pathSep: string; + thisFilePath: string; uiModuleMetas: UiModuleMeta[]; }; @@ -61,7 +64,7 @@ const zParsedCacheFile = (() => { const zTargetType = z.object({ keycloakifyVersion: z.string(), prettierConfigHash: z.union([z.string(), z.null()]), - pathSep: z.string(), + thisFilePath: z.string(), uiModuleMetas: z.array(zUiModuleMeta) }); @@ -72,13 +75,14 @@ const zParsedCacheFile = (() => { return id>(zTargetType); })(); -const CACHE_FILE_BASENAME = "uiModulesMeta.json"; +const CACHE_FILE_RELATIVE_PATH = pathJoin("ui-modules", "cache.json"); -export type BuildContextLike = BuildContextLike_getSourceCodeToCopyInUserCodebase & { - cacheDirPath: string; - packageJsonFilePath: string; - projectDirPath: string; -}; +export type BuildContextLike = + BuildContextLike_getUiModuleFileSourceCodeReadyToBeCopied & { + cacheDirPath: string; + packageJsonFilePath: string; + projectDirPath: string; + }; assert(); @@ -87,7 +91,7 @@ export async function getUiModuleMetas(params: { }): Promise { const { buildContext } = params; - const cacheFilePath = pathJoin(buildContext.cacheDirPath, CACHE_FILE_BASENAME); + const cacheFilePath = pathJoin(buildContext.cacheDirPath, CACHE_FILE_RELATIVE_PATH); const keycloakifyVersion = readThisNpmPackageVersion(); @@ -101,12 +105,20 @@ export async function getUiModuleMetas(params: { return crypto.createHash("sha256").update(JSON.stringify(config)).digest("hex"); })(); - const installedUiModules = await listInstalledModules({ - packageJsonFilePath: buildContext.packageJsonFilePath, - projectDirPath: buildContext.packageJsonFilePath, - filter: ({ moduleName }) => - moduleName.includes("keycloakify") && moduleName.endsWith("-ui") - }); + const installedUiModules = await (async () => { + const installedModulesWithKeycloakifyInTheName = await listInstalledModules({ + packageJsonFilePath: buildContext.packageJsonFilePath, + projectDirPath: buildContext.packageJsonFilePath, + filter: ({ moduleName }) => + moduleName.includes("keycloakify") && moduleName !== "keycloakify" + }); + + return Promise.all( + installedModulesWithKeycloakifyInTheName.filter(async ({ dirPath }) => + existsAsync(pathJoin(dirPath, KEYCLOAK_THEME)) + ) + ); + })(); const cacheContent = await (async () => { if (!(await existsAsync(cacheFilePath))) { @@ -155,7 +167,7 @@ export async function getUiModuleMetas(params: { return []; } - if (parsedCacheFile.pathSep !== pathSep) { + if (parsedCacheFile.thisFilePath !== cacheFilePath) { return []; } @@ -200,31 +212,44 @@ export async function getUiModuleMetas(params: { const files: UiModuleMeta["files"] = []; { - const srcDirPath = pathJoin(dirPath, "src"); + const srcDirPath = pathJoin(dirPath, KEYCLOAK_THEME); await crawlAsync({ dirPath: srcDirPath, returnedPathsType: "relative to dirPath", onFileFound: async fileRelativePath => { - const sourceCode = await getSourceCodeToCopyInUserCodebase({ - buildContext, - relativeFromDirPath: srcDirPath, - fileRelativePath, - commentData: { + const sourceCode = + await getUiModuleFileSourceCodeReadyToBeCopied({ + buildContext, + fileRelativePath, isForEjection: false, + uiModuleDirPath: dirPath, uiModuleName: moduleName, uiModuleVersion: version - } - }); + }); - const hash = crypto - .createHash("sha256") - .update(sourceCode) - .digest("hex"); + const hash = computeHash(sourceCode); + + const copyableFilePath = pathJoin( + pathDirname(cacheFilePath), + KEYCLOAK_THEME, + fileRelativePath + ); + + { + const dirPath = pathDirname(copyableFilePath); + + if (!(await existsAsync(dirPath))) { + await fsPr.mkdir(dirPath, { recursive: true }); + } + } + + fsPr.writeFile(copyableFilePath, sourceCode); files.push({ fileRelativePath, - hash + hash, + copyableFilePath }); } }); @@ -244,7 +269,7 @@ export async function getUiModuleMetas(params: { const parsedCacheFile = id({ keycloakifyVersion, prettierConfigHash, - pathSep, + thisFilePath: cacheFilePath, uiModuleMetas }); @@ -272,3 +297,7 @@ export async function getUiModuleMetas(params: { return uiModuleMetas; } + +export function computeHash(data: Buffer) { + return crypto.createHash("sha256").update(data).digest("hex"); +} diff --git a/src/bin/shared/buildContext.ts b/src/bin/shared/buildContext.ts index 4cb8a552..5ae3f925 100644 --- a/src/bin/shared/buildContext.ts +++ b/src/bin/shared/buildContext.ts @@ -18,9 +18,8 @@ import { import type { KeycloakVersionRange } from "./KeycloakVersionRange"; import { exclude } from "tsafe"; import { crawl } from "../tools/crawl"; -import { THEME_TYPES } from "./constants"; +import { THEME_TYPES, KEYCLOAK_THEME, type ThemeType } from "./constants"; import { objectEntries } from "tsafe/objectEntries"; -import { type ThemeType } from "./constants"; import { id } from "tsafe/id"; import chalk from "chalk"; import { getProxyFetchOptions, type FetchOptionsLike } from "../tools/fetchProxyOptions"; @@ -147,7 +146,10 @@ export function getBuildContext(params: { returnedPathsType: "relative to dirPath" }) .map(fileRelativePath => { - for (const themeSrcDirBasename of ["keycloak-theme", "keycloak_theme"]) { + for (const themeSrcDirBasename of [ + KEYCLOAK_THEME, + KEYCLOAK_THEME.replace(/-/g, "_") + ]) { const split = fileRelativePath.split(themeSrcDirBasename); if (split.length === 2) { return pathJoin(srcDirPath, split[0] + themeSrcDirBasename); @@ -173,7 +175,7 @@ export function getBuildContext(params: { [ `Can't locate your Keycloak theme source directory in .${pathSep}${pathRelative(process.cwd(), srcDirPath)}`, `Make sure to either use the Keycloakify CLI in the root of your Keycloakify project or use the --project CLI option`, - `If you are collocating your Keycloak theme with your app you must have a directory named 'keycloak-theme' or 'keycloak_theme' in your 'src' directory` + `If you are collocating your Keycloak theme with your app you must have a directory named '${KEYCLOAK_THEME}' or '${KEYCLOAK_THEME.replace(/-/g, "_")}' in your 'src' directory` ].join("\n") ) ); diff --git a/src/bin/shared/constants.ts b/src/bin/shared/constants.ts index cfddb472..6514115f 100644 --- a/src/bin/shared/constants.ts +++ b/src/bin/shared/constants.ts @@ -76,3 +76,5 @@ export const CUSTOM_HANDLER_ENV_NAMES = { COMMAND_NAME: "KEYCLOAKIFY_COMMAND_NAME", BUILD_CONTEXT: "KEYCLOAKIFY_BUILD_CONTEXT" }; + +export const KEYCLOAK_THEME = "keycloak-theme"; diff --git a/src/bin/sync-ui-modules/index.ts b/src/bin/sync-ui-modules/index.ts deleted file mode 100644 index 45d420bd..00000000 --- a/src/bin/sync-ui-modules/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./sync-ui-modules"; diff --git a/src/bin/sync-ui-modules/sync-ui-modules.ts b/src/bin/sync-ui-modules/sync-ui-modules.ts deleted file mode 100644 index abd1c4c8..00000000 --- a/src/bin/sync-ui-modules/sync-ui-modules.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { BuildContext } from "./shared/buildContext"; -import { assert, type Equals } from "tsafe/assert"; -import { id } from "tsafe/id"; -import { is } from "tsafe/is"; -import { z } from "zod"; -import { join as pathJoin } from "path"; -import { existsAsync } from "./tools/fs.existsAsync"; - -import * as fsPr from "fs/promises"; - -export async function command(params: { buildContext: BuildContext }) { - const { buildContext } = params; -} diff --git a/src/bin/tools/getInstalledModuleDirPath.ts b/src/bin/tools/getInstalledModuleDirPath.ts index 260c3c5e..7915e6e9 100644 --- a/src/bin/tools/getInstalledModuleDirPath.ts +++ b/src/bin/tools/getInstalledModuleDirPath.ts @@ -1,16 +1,14 @@ -import { dirname as pathDirname, join as pathJoin } from "path"; +import { join as pathJoin } from "path"; import { existsAsync } from "./fs.existsAsync"; import * as child_process from "child_process"; import { assert } from "tsafe/assert"; export async function getInstalledModuleDirPath(params: { moduleName: string; - packageJsonFilePath: string; + packageJsonDirPath: string; projectDirPath: string; }) { - const { moduleName, packageJsonFilePath, projectDirPath } = params; - - const packageJsonDirPath = pathDirname(packageJsonFilePath); + const { moduleName, packageJsonDirPath, projectDirPath } = params; common_case: { const dirPath = pathJoin( diff --git a/src/bin/tools/listInstalledModules.ts b/src/bin/tools/listInstalledModules.ts index ea78956e..ef2f9116 100644 --- a/src/bin/tools/listInstalledModules.ts +++ b/src/bin/tools/listInstalledModules.ts @@ -1,10 +1,11 @@ import { assert, type Equals } from "tsafe/assert"; import { id } from "tsafe/id"; import { z } from "zod"; -import { join as pathJoin } from "path"; +import { join as pathJoin, dirname as pathDirname } from "path"; import * as fsPr from "fs/promises"; import { is } from "tsafe/is"; import { getInstalledModuleDirPath } from "../tools/getInstalledModuleDirPath"; +import { exclude } from "tsafe/exclude"; export async function listInstalledModules(params: { packageJsonFilePath: string; @@ -27,7 +28,7 @@ export async function listInstalledModules(params: { const uiModuleNames = ( [parsedPackageJson.dependencies, parsedPackageJson.devDependencies] as const ) - .filter(obj => obj !== undefined) + .filter(exclude(undefined)) .map(obj => Object.keys(obj)) .flat() .filter(moduleName => filter({ moduleName })); @@ -36,7 +37,7 @@ export async function listInstalledModules(params: { uiModuleNames.map(async moduleName => { const dirPath = await getInstalledModuleDirPath({ moduleName, - packageJsonFilePath, + packageJsonDirPath: pathDirname(packageJsonFilePath), projectDirPath });