From 73b71033b3dfd82d03627df9ff9e3b0d934cea71 Mon Sep 17 00:00:00 2001 From: Guz013 <43732358+Guz013@users.noreply.github.com> Date: Thu, 3 Aug 2023 14:19:00 -0300 Subject: [PATCH] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20simplify/"norm?= =?UTF-8?q?alize"=20packages=20detection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactored how the cli gets the workspace structure, making it more "agnostic" for single- and multi- packages workspaces. Also the paths listed on the package object were simplified to be relative to the package's path. --- packages/cli/src/cli.js | 22 ++----- packages/cli/src/index.js | 0 packages/cli/src/types.d.ts | 5 +- packages/cli/src/workspace.js | 116 ++++++++++++++++------------------ 4 files changed, 61 insertions(+), 82 deletions(-) mode change 100644 => 100755 packages/cli/src/index.js diff --git a/packages/cli/src/cli.js b/packages/cli/src/cli.js index 6dba65a..051996b 100755 --- a/packages/cli/src/cli.js +++ b/packages/cli/src/cli.js @@ -1,5 +1,5 @@ #!node -import path, { join } from 'node:path'; +import path from 'node:path'; import { createSpinner } from 'nanospinner'; import glob from 'picomatch'; import c from 'picocolors'; @@ -9,28 +9,20 @@ export default class Cli { /** @type {string} */ dir = process.cwd(); - /** @type {boolean} */ - debug = false; - /** @type {import('./types').Config[]} */ configs; - /** @type {import('./types').Workspace | undefined} */ - #workspace; - /** * @param {{ * configs: import('./types').Config[] * packages?: string[], - * workspace?: import('./types').Workspace, + * workspace?: import('./types').Package[], * directory?: string, * debug?: boolean, * }} options - Cli options */ constructor(options) { this.configs = options?.configs; - this.packages = options.packages; - this.#workspace = options.workspace; this.dir = path.normalize(options.directory ?? this.dir); this.debug = options.debug ?? this.debug; } @@ -62,7 +54,7 @@ export default class Cli { } else if (!option.detect) continue; - const match = glob(option.detect.map(p => join(pkg.path, p))); + const match = glob(option.detect); const files = pkg.files.filter(f => match ? match(f) : false); const directories = pkg.directories.filter(f => match ? match(f) : false); @@ -106,20 +98,20 @@ export default class Cli { spinner.update({ text: `Configuring ${c.bold(c.blue(pkg.name))}${c.dim(`: config ${config.name}`)}` }); } - spinner.success({ text: `Configuring ${c.bold(c.blue(pkg.name))}` }); + spinner.success({ text: `Configuring ${c.bold(c.blue(pkg.name))}\n${c.dim(JSON.stringify(pkgConfig))}\n` }); return pkgConfig; } async run() { - const workspace = this.#workspace ?? await new Workspace(this.dir).get(); + let packages = await new Workspace(this.dir).getPackages(); - workspace.packages = workspace.packages.map( + packages = packages.map( pkg => { pkg.config = this.detectConfig(pkg); return pkg; }, ); - console.log(JSON.stringify(workspace.packages, null, 2)); + console.log(packages); } } diff --git a/packages/cli/src/index.js b/packages/cli/src/index.js old mode 100644 new mode 100755 diff --git a/packages/cli/src/types.d.ts b/packages/cli/src/types.d.ts index 579ddc1..ed5821b 100644 --- a/packages/cli/src/types.d.ts +++ b/packages/cli/src/types.d.ts @@ -11,11 +11,8 @@ export interface Config { }[] } -export interface Workspace { - packages: Package[] -} - export interface Package { + root?: boolean name: string path: string files: string[] diff --git a/packages/cli/src/workspace.js b/packages/cli/src/workspace.js index 9c18341..a3b1f08 100644 --- a/packages/cli/src/workspace.js +++ b/packages/cli/src/workspace.js @@ -3,6 +3,7 @@ import { existsSync } from 'node:fs'; import YAML from 'yaml'; import path, { join } from 'node:path'; import glob from 'picomatch'; +import picomatch from 'picomatch'; /** @@ -54,30 +55,6 @@ async function getPackageName(directory) { return path.normalize(directory).split('/').at(-1) ?? directory; } -/** - * @param {string} directory - The directory path to work on - * @param {{files: string[], directories: string[]}} paths - The file list to be filtered - * @param {string[]} [packages] - The packages to be filtered - * @returns {Promise} - The package object - */ -async function getRootPackage(directory, paths, packages = []) { - - const ignorePatterns = [ - ...packages.map(p => - `${join(directory, p, '**/*')}`, - )]; - - return { - name: `${await getPackageName(directory)} [ROOT]`, - files: paths.files.filter(f => - !glob.isMatch(f, ignorePatterns), - ) ?? [], - directories: paths.directories.filter(d => - !glob.isMatch(d, ignorePatterns), - ) ?? [], - path: directory, - }; -} export default class Workspace { /** @type {{files: string[], directories: string[]} | undefined} */ paths; @@ -126,7 +103,10 @@ export default class Workspace { } } - return { files, directories }; + return { + files: files.map(p => path.normalize(p.replace(this.dir, './'))), + directories: directories.map(p => path.normalize(p.replace(this.dir, './'))), + }; } /** @type {string[] | undefined} */ @@ -135,10 +115,10 @@ export default class Workspace { /** * @returns {Promise} - List of packages on a directory; */ - async getPackages() { + async getPackagePatterns() { /** @type {string[]} */ - let packages = []; + let packagePatterns = []; const pnpmWorkspace = existsSync(join(this.dir, 'pnpm-workspace.yaml')) @@ -148,67 +128,77 @@ export default class Workspace { : null; if (pnpmWorkspace) { - const fileYaml = await fs.readFile(join(this.dir, pnpmWorkspace), 'utf8'); + const pnpmWorkspaceYaml = await fs.readFile(join(this.dir, pnpmWorkspace), 'utf8'); /** @type {{packages?: string[]}} */ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const fileObj = YAML.parse(fileYaml); + const pnpmWorkspaceObj = YAML.parse(pnpmWorkspaceYaml); - packages.push(...(fileObj?.packages ?? [])); + packagePatterns.push(...(pnpmWorkspaceObj?.packages ?? [])); } else if (existsSync(join(this.dir, 'package.json'))) { const packageJson = await fs.readFile(join(this.dir, 'package.json'), 'utf8'); /** @type {{workspaces?: string[]}} */ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const packageObj = JSON.parse(packageJson); + const packageJsonObj = JSON.parse(packageJson); - packages.push(...(packageObj?.workspaces ?? [])); + packagePatterns.push(...(packageJsonObj?.workspaces ?? [])); } - return packages; + + return packagePatterns.map(p => { + p = path.normalize(p); + p = p.startsWith('/') ? p.replace('/', '') : p; + p = p.endsWith('/') ? p.slice(0, p.length - 1) : p; + return p; + }); } - /** @type {import('./types').Workspace | undefined} */ - workspace; - /** - * @returns {Promise} - * The workspace structure and packages founded + * @returns {Promise} - The list of packages that exist in the workspace */ - async getWorkspace() { - console.log(this.packages); - const rootPackage = await getRootPackage(this.dir, this.paths ?? { files: [], directories: [] }, this.packages); + async getPackages() { - /** @type {string[]} */ - const packagesPaths = this.paths?.directories.filter(d => - glob.isMatch(d, this.packages?.map(p => join(this.dir, p)) ?? ''), - ) ?? []; + const paths = await this.getPaths(); + const packagePatterns = await this.getPackagePatterns(); + const packagePaths = paths.directories.filter(d => picomatch.isMatch(d, packagePatterns)); + + console.log(packagePatterns); + + /** @type {import('./types').Package} */ + const rootPackage = { + root: true, + name: await getPackageName(this.dir), + path: this.dir, + files: paths.files, + directories: paths.directories, + }; /** @type {import('./types').Package[]} */ const packages = []; - for (const pkgPath of packagesPaths) { + for (const packagePath of packagePaths) { packages.push({ - name: await getPackageName(pkgPath), - files: this.paths?.files.filter(f => glob.isMatch(f, join(pkgPath, '**/*'))) ?? [], - directories: this.paths?.directories.filter(f => glob.isMatch(f, join(pkgPath, '**/*'))) ?? [], - path: pkgPath, + root: false, + path: join(this.dir, packagePath), + name: await getPackageName(join(this.dir, packagePath)), + files: paths.files + .filter(f => picomatch.isMatch(f, `${packagePath}/**/*`)) + .map(f => f.replace(`${packagePath}/`, '')), + directories: paths.directories + .filter(d => picomatch.isMatch(d, `${packagePath}/**/*`)) + .map(d => d.replace(`${packagePath}/`, '')), }); + + rootPackage.files = rootPackage.files + .filter(f => picomatch.isMatch(f, `!${packagePath}/**/*`)); + + rootPackage.directories = rootPackage.directories + .filter(d => picomatch.isMatch(d, `!${packagePath}/**/*`)); } - return { - packages: [ - rootPackage, - ...packages, - ], - }; + return [rootPackage, ...packages]; + } - async get() { - this.packages ||= await this.getPackages(); - this.paths = await this.getPaths(); - this.workspace = await this.getWorkspace(); - - return this.workspace; - } }