From 8d18d87e6175894a1e6fb965a30a2be02db7c24f Mon Sep 17 00:00:00 2001 From: Kostiantyn Popovych Date: Tue, 16 May 2023 13:37:36 -0700 Subject: [PATCH 1/3] Release 0.3.1 (#6) --- CHANGELOG.md | 3 +++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47e1a01..831f9b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # main (unreleased) +# 0.3.1 +- Fix ESLint configuration in example project + # 0.3.0 - Add support for ESLint parser: `@babel/eslint-parser` diff --git a/package-lock.json b/package-lock.json index c21b3c4..898ab9e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "plugin-preloader", - "version": "0.3.0", + "version": "0.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "plugin-preloader", - "version": "0.3.0", + "version": "0.3.1", "license": "MIT", "devDependencies": { "@types/babel__core": "^7.20.0", diff --git a/package.json b/package.json index 9df3df5..efd9997 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plugin-preloader", - "version": "0.3.0", + "version": "0.3.1", "author": "Kostiantyn Popovych (https://github.com/KostiantynPopovych)", "description": "This library dynamically preloads and installs Babel and ESLint plugins and presets based on your configuration, streamlining the build process without the need to include them as dependencies in your project.", "repository": "git@github.com:upgradejs/plugin-preloader", From a454320d789aea63ef5ad50c978feaa9e1479be0 Mon Sep 17 00:00:00 2001 From: Kostiantyn Popovych Date: Tue, 16 May 2023 14:24:13 -0700 Subject: [PATCH 2/3] Remove async preload method to make the result of the execution predictable (#7) --- README.md | 28 ++------ __tests__/getEntitiesMapWithVersions.spec.ts | 73 ++------------------ __tests__/plugin-preloader.spec.ts | 49 ++----------- example/index.js | 4 +- src/getEntitiesMapWithVersions.ts | 37 +--------- src/index.ts | 54 ++------------- 6 files changed, 26 insertions(+), 219 deletions(-) diff --git a/README.md b/README.md index 9fa2433..7ef8015 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ This library offers a method for preloading Babel and ESLint packages according ## Features - Automatically install Babel and ESLint packages based on their configuration files. -- Sync and async preload methods. - Supports both latest and specific package versions. ## Installation @@ -15,7 +14,7 @@ npm install --save-dev plugin-preloader ``` ## Usage -The syncPreload and asyncPreload functions can operate effectively with standard Babel and ESLint configurations, ensuring that each plugin, preset, parser, or extend is processed and installed at the most recent version. +The `preload` function can operate effectively with standard Babel and ESLint configurations, ensuring that each plugin, preset, parser, or extend is processed and installed at the most recent version. To designate a specific version rather than the latest for Babel plugins and presets, you can use the fourth element in the plugin/preset definition array item, bypassing the second and third elements - `["@babel/preset-react", undefined, undefined, "7.0.0"]`. @@ -47,23 +46,12 @@ const sampleEslintConfig: ESLintConfig = { }; ``` -### Async Preload -```typescript -import { asyncPreload } from "plugin-preloader"; - -async function main() { - await asyncPreload({ babel: sampleBabelConfig, eslint: sampleEslintConfig }); -} - -main(); -``` - -### Sync Preload +### Preload ```javascript -const { syncPreload } = require("plugin-preloader"); +const preload = require("plugin-preloader"); -syncPreload({ babel: sampleBabelConfig, eslint: sampleEslintConfig }); +preload({ babel: sampleBabelConfig, eslint: sampleEslintConfig }); ``` In addition, we have provided a sample project in the [example](https://github.com/upgradejs/plugin-preloader/tree/main/example) folder. @@ -77,14 +65,6 @@ In addition, we have provided a sample project in the [example](https://github.c - Returns: `void` - Description: Installs the required packages synchronously based on the Babel and ESLint configurations. -`asyncPreload({ babel, eslint })` -- Parameters: - - Object with the following properties: - - `babel`: [BabelConfig](https://github.com/upgradejs/plugin-preloader/blob/66d1433eae5dc09fdd47ef92f5b2423e2ce8b4f2/src/types/index.ts#L19) object (optional) - - `eslint`: [ESLintConfig](https://github.com/upgradejs/plugin-preloader/blob/66d1433eae5dc09fdd47ef92f5b2423e2ce8b4f2/src/types/index.ts#L23) object (optional) -- Returns: `Promise` -- Description: Installs the required packages asynchronously based on the Babel and ESLint configurations. - ## Known Issues - **Incompatibility with `pnpm` package manager:** This project may not function correctly with the `pnpm` package manager. It is recommended to use `npm` or `yarn` for better compatibility and a smoother experience diff --git a/__tests__/getEntitiesMapWithVersions.spec.ts b/__tests__/getEntitiesMapWithVersions.spec.ts index 7ad2072..82ef2b5 100644 --- a/__tests__/getEntitiesMapWithVersions.spec.ts +++ b/__tests__/getEntitiesMapWithVersions.spec.ts @@ -1,18 +1,15 @@ -import { - getEntitiesMapWithVersionsAsync, - getEntitiesMapWithVersionsSync, -} from "@core/getEntitiesMapWithVersions"; +import getEntitiesMapWithVersions from "@core/getEntitiesMapWithVersions"; import { babelMap, eslintMap } from "@core/maps"; import { Entity } from "@core/types"; -describe("getEntitiesMapWithVersionsSync", () => { +describe("getEntitiesMapWithVersions", () => { it("returns expected map with versions for Babel config", () => { const entities = [ "@babel/plugin-transform-typescript", ["@babel/preset-react", "7.0.0"], ] as Entity[]; - const result = getEntitiesMapWithVersionsSync(entities, { + const result = getEntitiesMapWithVersions(entities, { ...babelMap.presets, ...babelMap.plugins, }); @@ -37,7 +34,8 @@ describe("getEntitiesMapWithVersionsSync", () => { "@typescript-eslint/parser", ] as Entity[]; - const result = getEntitiesMapWithVersionsSync(entities, { + // TODO: Mock the node_modules folder to prevent updating tests every time whn modules are updated + const result = getEntitiesMapWithVersions(entities, { ...eslintMap.plugins, ...eslintMap.extendsMap, ...eslintMap.parser, @@ -51,69 +49,12 @@ describe("getEntitiesMapWithVersionsSync", () => { "plugin:@typescript-eslint/recommended": { nameInRegistry: "@typescript-eslint/eslint-plugin", currentVersion: "5.56.0", - desiredVersion: "5.56.0", + desiredVersion: "5.59.6", }, "@typescript-eslint/parser": { nameInRegistry: "@typescript-eslint/parser", currentVersion: "5.56.0", - desiredVersion: "5.56.0", - }, - }); - }); -}); - -describe("getEntitiesMapWithVersionsAsync", () => { - it("returns expected map with versions for Babel config", async () => { - const entities = [ - "@babel/plugin-transform-typescript", - ["@babel/preset-react", "7.0.0"], - ] as Entity[]; - - const result = await getEntitiesMapWithVersionsAsync(entities, { - ...babelMap.presets, - ...babelMap.plugins, - }); - - expect(result).toEqual({ - "@babel/plugin-transform-typescript": { - nameInRegistry: "@babel/plugin-transform-typescript", - desiredVersion: "latest", - }, - "@babel/preset-react": { - nameInRegistry: "@babel/preset-react", - desiredVersion: "7.0.0", - }, - }); - }); - - it("returns expected map with versions for ESLint config", async () => { - const entities = [ - ["plugin:security-rules/recommended", "7.0.0"], - "@babel/preset-preact", - "plugin:@typescript-eslint/recommended", - "@typescript-eslint/parser", - ] as Entity[]; - - const result = await getEntitiesMapWithVersionsAsync(entities, { - ...eslintMap.plugins, - ...eslintMap.extendsMap, - ...eslintMap.parser, - }); - - expect(result).toEqual({ - "plugin:security-rules/recommended": { - nameInRegistry: "eslint-plugin-security-rules", - desiredVersion: "7.0.0", - }, - "plugin:@typescript-eslint/recommended": { - nameInRegistry: "@typescript-eslint/eslint-plugin", - currentVersion: "5.56.0", - desiredVersion: "5.56.0", - }, - "@typescript-eslint/parser": { - nameInRegistry: "@typescript-eslint/parser", - currentVersion: "5.56.0", - desiredVersion: "5.56.0", + desiredVersion: "5.59.6", }, }); }); diff --git a/__tests__/plugin-preloader.spec.ts b/__tests__/plugin-preloader.spec.ts index a1fe2fe..2f53610 100644 --- a/__tests__/plugin-preloader.spec.ts +++ b/__tests__/plugin-preloader.spec.ts @@ -1,4 +1,4 @@ -import { asyncPreload, syncPreload } from "@core/index"; +import preload from "@core/index"; import * as wrappers from "@core/utils/wrappers"; import { sampleBabelConfig, sampleEslintConfig } from "__mock__/configs"; @@ -8,48 +8,11 @@ const syncExecMock = wrappers.syncExec as jest.Mock; jest.mock("@core/utils/wrappers"); const expectedBabelDependencies = - "@babel/preset-react@7.0.0 @babel/plugin-proposal-decorators@latest @babel/plugin-proposal-private-methods@8.0.0 @babel/preset-env@latest"; + "@babel/preset-react@7.0.0 @babel/plugin-transform-runtime@latest @babel/plugin-proposal-decorators@latest @babel/plugin-proposal-private-methods@8.0.0 @babel/preset-env@latest"; const expectedEslintDependencies = "@typescript-eslint/eslint-plugin@latest eslint-plugin-abcsize@latest @typescript-eslint/parser@latest"; -describe("asyncPreload - checking wrappers.asyncExec calls", () => { - beforeEach(() => { - asyncExecMock.mockClear(); - }); - - afterEach(() => { - asyncExecMock.mockRestore(); - }); - - test("should call asyncExec with the correct command for Babel config", async () => { - asyncExecMock.mockImplementation(async () => { - return { stdout: "Mocked stdout" }; - }); - await asyncPreload({ babel: sampleBabelConfig }); - expect(asyncExecMock).toHaveBeenCalled(); - expect(asyncExecMock.mock.calls[0][0]).toContain( - `npm install ${expectedBabelDependencies} --no-save --no-audit` - ); - }); - - test("should not call asyncExecMock for ESLint config", async () => { - await asyncPreload({ eslint: { extends: ["eslint:recommended"] } }); - expect(asyncExecMock).not.toHaveBeenCalled(); - }); - - test("should call asyncExec with the correct command for ESLint config", async () => { - asyncExecMock.mockImplementation(async () => { - return { stdout: "Mocked stdout" }; - }); - await asyncPreload({ eslint: sampleEslintConfig }); - expect(asyncExecMock).toHaveBeenCalled(); - expect(asyncExecMock.mock.calls[0][0]).toContain( - `npm install ${expectedEslintDependencies} --no-save --no-audit` - ); - }); -}); - -describe("syncPreload - checking wrappers.syncExec calls", () => { +describe("preload", () => { beforeEach(() => { syncExecMock.mockClear(); }); @@ -59,7 +22,7 @@ describe("syncPreload - checking wrappers.syncExec calls", () => { }); test("should not call syncExecMock for ESLint config", async () => { - syncPreload({ eslint: { extends: ["eslint:recommended"] } }); + preload({ eslint: { extends: ["eslint:recommended"] } }); expect(asyncExecMock).not.toHaveBeenCalled(); }); @@ -67,7 +30,7 @@ describe("syncPreload - checking wrappers.syncExec calls", () => { syncExecMock.mockImplementation(() => { return "Mocked stdout"; }); - syncPreload({ babel: sampleBabelConfig }); + preload({ babel: sampleBabelConfig }); expect(syncExecMock).toHaveBeenCalled(); expect(syncExecMock.mock.calls[0][0]).toContain( `npm install ${expectedBabelDependencies} --no-save --no-audit` @@ -78,7 +41,7 @@ describe("syncPreload - checking wrappers.syncExec calls", () => { syncExecMock.mockImplementation(() => { return "Mocked stdout"; }); - syncPreload({ eslint: sampleEslintConfig }); + preload({ eslint: sampleEslintConfig }); expect(syncExecMock).toHaveBeenCalled(); expect(syncExecMock.mock.calls[0][0]).toContain( `npm install ${expectedEslintDependencies} --no-save --no-audit` diff --git a/example/index.js b/example/index.js index 135f14b..41e6a9a 100644 --- a/example/index.js +++ b/example/index.js @@ -3,7 +3,7 @@ const { ESLint } = require("eslint"); const { resolve, join } = require("path"); const { promises: fs } = require("fs"); const { parse } = require("@babel/core"); -const { asyncPreload } = require("plugin-preloader"); +const preload = require("plugin-preloader"); const program = new Command(); @@ -49,7 +49,7 @@ async function analyze(filePath, { babelConfigPath, eslintConfigPath }) { const babelConfig = babelConfigPath ? require(babelConfigPath) : {}; const eslintConfig = eslintConfigPath ? require(eslintConfigPath) : {}; - await asyncPreload({ babel: babelConfig, eslint: eslintConfig }); + preload({ babel: babelConfig, eslint: eslintConfig }); await generateEslintReport(options, eslintConfig, "."); diff --git a/src/getEntitiesMapWithVersions.ts b/src/getEntitiesMapWithVersions.ts index 101803a..d0c874a 100644 --- a/src/getEntitiesMapWithVersions.ts +++ b/src/getEntitiesMapWithVersions.ts @@ -3,7 +3,7 @@ import { resolve } from "path"; import log from "fancy-log"; import { wrappers } from "./utils"; -function getEntitiesMapWithVersionsSync(entities: Entity[], entitiesMap: Map): MapWithVersions { +function getEntitiesMapWithVersions(entities: Entity[], entitiesMap: Map): MapWithVersions { const mapWithVersions: MapWithVersions = {}; for (const entity of entities) { const name: Name = Array.isArray(entity) ? entity[0] : entity; @@ -33,37 +33,4 @@ function getEntitiesMapWithVersionsSync(entities: Entity[], entitiesMap: Map): M return mapWithVersions; } -async function getEntitiesMapWithVersionsAsync( - entities: Entity[], - entitiesMap: Map -): Promise { - const mapWithVersions: MapWithVersions = {}; - for (const entity of entities) { - const name: Name = Array.isArray(entity) ? entity[0] : entity; - try { - const { nameInRegistry } = entitiesMap[name]; - mapWithVersions[name] = { - nameInRegistry, - desiredVersion: Array.isArray(entity) ? entity[1] : "latest", - }; - const currentDir = process.cwd(); - const packagePath = resolve(currentDir, "node_modules", nameInRegistry); - const packageIsInstalled = await wrappers.asyncExists(packagePath); - if (packageIsInstalled) { - const { version } = require(packagePath + "/package.json"); - mapWithVersions[name].currentVersion = version; - if (mapWithVersions[name].desiredVersion === "latest") { - const command = `npm view ${nameInRegistry} version`; - const remoteVersion = (await wrappers.asyncExec(command)).stdout; - mapWithVersions[name].desiredVersion = remoteVersion.trim(); - } - } - } catch (e) { - delete mapWithVersions[name]; - log.error(`Plugin ${name} is not handled yet.`); - } - } - return mapWithVersions; -} - -export { getEntitiesMapWithVersionsSync, getEntitiesMapWithVersionsAsync }; +export default getEntitiesMapWithVersions; diff --git a/src/index.ts b/src/index.ts index 88e5978..57f8207 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,18 +1,15 @@ import { MapEntityWithVersions, Preload } from "./types"; import { babelMap, eslintMap } from "./maps"; -import { - getEntitiesMapWithVersionsSync, - getEntitiesMapWithVersionsAsync, -} from "./getEntitiesMapWithVersions"; +import getEntitiesMapWithVersions from "./getEntitiesMapWithVersions"; import { wrappers, transform } from "@core/utils"; import log from "fancy-log"; -async function asyncPreload({ babel, eslint }: Preload) { +function preload({ babel, eslint }: Preload) { const checkedEntities: MapEntityWithVersions[] = []; if (babel) { const pluginsAndPresets = transform.babelConfig(babel); - const pluginsAndPresetsMap = await getEntitiesMapWithVersionsAsync(pluginsAndPresets, { + const pluginsAndPresetsMap = getEntitiesMapWithVersions(pluginsAndPresets, { ...babelMap.plugins, ...babelMap.presets, }); @@ -21,48 +18,7 @@ async function asyncPreload({ babel, eslint }: Preload) { if (eslint) { const pluginsExtendsAndParser = transform.eslintConfig(eslint); - const pluginsExtendsAndParserMap = await getEntitiesMapWithVersionsAsync( - pluginsExtendsAndParser, - { ...eslintMap.extendsMap, ...eslintMap.parser, ...eslintMap.plugins } - ); - checkedEntities.push(...Object.values(pluginsExtendsAndParserMap)); - } - - if (checkedEntities.length) { - log("Packages to install:"); - } else { - log("No packages need to be installed"); - return; - } - - const packagesToInstall = checkedEntities.reduce((acc, { nameInRegistry, desiredVersion }) => { - const packageWithVersion = `${nameInRegistry}@${desiredVersion}`; - log(`- ${packageWithVersion}`); - return acc + `${packageWithVersion} `; - }, ""); - - const command = `npm install ${packagesToInstall.trim()} --no-save --no-audit`; - - const output = (await wrappers.asyncExec(command)).stdout; - - log(output.trim()); -} - -function syncPreload({ babel, eslint }: Preload) { - const checkedEntities: MapEntityWithVersions[] = []; - - if (babel) { - const pluginsAndPresets = transform.babelConfig(babel); - const pluginsAndPresetsMap = getEntitiesMapWithVersionsSync(pluginsAndPresets, { - ...babelMap.plugins, - ...babelMap.presets, - }); - checkedEntities.push(...Object.values(pluginsAndPresetsMap)); - } - - if (eslint) { - const pluginsExtendsAndParser = transform.eslintConfig(eslint); - const pluginsExtendsAndParserMap = getEntitiesMapWithVersionsSync(pluginsExtendsAndParser, { + const pluginsExtendsAndParserMap = getEntitiesMapWithVersions(pluginsExtendsAndParser, { ...eslintMap.extendsMap, ...eslintMap.parser, ...eslintMap.plugins, @@ -90,4 +46,4 @@ function syncPreload({ babel, eslint }: Preload) { log(output.trim()); } -export { syncPreload, asyncPreload }; +export default preload; From f23fff47ff8490f91a25ab27dbf1dde359e201a1 Mon Sep 17 00:00:00 2001 From: Kostiantyn Popovych Date: Tue, 16 May 2023 14:30:12 -0700 Subject: [PATCH 3/3] release v1.0.0 (#8) --- CHANGELOG.md | 3 +++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 831f9b7..44d9520 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # main (unreleased) +# 1.0.0 +- Breaking change: the `asyncPreload` method was removed to ensure that dependencies will be installed before the program execution. The project now exports only the sync version of the `preload` method, and it is a default export. + # 0.3.1 - Fix ESLint configuration in example project diff --git a/package-lock.json b/package-lock.json index 898ab9e..8d2157b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "plugin-preloader", - "version": "0.3.1", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "plugin-preloader", - "version": "0.3.1", + "version": "1.0.0", "license": "MIT", "devDependencies": { "@types/babel__core": "^7.20.0", diff --git a/package.json b/package.json index efd9997..a36a297 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plugin-preloader", - "version": "0.3.1", + "version": "1.0.0", "author": "Kostiantyn Popovych (https://github.com/KostiantynPopovych)", "description": "This library dynamically preloads and installs Babel and ESLint plugins and presets based on your configuration, streamlining the build process without the need to include them as dependencies in your project.", "repository": "git@github.com:upgradejs/plugin-preloader",