Skip to content

Commit

Permalink
chore: Rollup & Vitest
Browse files Browse the repository at this point in the history
* Use Rollup instead of Babel to generate CJS and ESM bundles
* Convert implementation to ESM
* Use Vitest instead of Jest for tests
* Use memfs instead of mocking specific node:fs functions
* Update nps calls to use CJS config
  • Loading branch information
duncanbeevers committed Dec 7, 2024
1 parent 39a7744 commit 2f68f10
Show file tree
Hide file tree
Showing 25 changed files with 964 additions and 771 deletions.
12 changes: 6 additions & 6 deletions .eslintrc.js → .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ const config = {
extends: [
'kentcdodds',
'kentcdodds/jest',
'plugin:node-dependencies/recommended'
'plugin:node-dependencies/recommended',
],
parserOptions: {
ecmaVersion: 2021
ecmaVersion: 2021,
},
rules: {
'valid-jsdoc': 'off',
Expand All @@ -15,16 +15,16 @@ const config = {
{
anonymous: 'never',
named: 'never',
asyncArrow: 'always'
}
asyncArrow: 'always',
},
],
'import/no-import-module-exports': 'off',
'arrow-parens': ['error', 'as-needed'],
quotes: ['error', 'single', { avoidEscape: true }],
},
settings: {
'import/ignore': ['node_modules', 'src'] // Using CommonJS in src
}
'import/ignore': ['node_modules', 'src'], // Using CommonJS in src
},
};

module.exports = config;
33 changes: 27 additions & 6 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,41 @@ updates:
- 17.3.9
- 17.4.0
- 17.4.1
- dependency-name: '@rollup/plugin-commonjs'
versions:
- 28.0.1
- dependency-name: '@rollup/plugin-json'
versions:
- 6.1.0
- dependency-name: '@rollup/plugin-node-resolve'
versions:
- 15.3.0
- dependency-name: rollup
versions:
- 4.28.0
- dependency-name: rollup-plugin-auto-external
versions:
- 2.0.0
- dependency-name: memfs
versions:
- 4.14.1
- dependency-name: vue-eslint-parser
versions:
- 7.4.1
- 7.5.0
- 7.6.0
- dependency-name: jest-cli
- dependency-name: vite
versions:
- 6.0.3
- dependency-name: vitest
versions:
- 26.6.3
- dependency-name: babel-jest
- 2.1.8
- dependency-name: '@vitest/coverage-v8'
versions:
- 26.6.3
- dependency-name: jest
- 2.1.8
- dependency-name: '@vitest/ui'
versions:
- 26.6.3
- 2.1.8
- dependency-name: pretty-format
versions:
- 26.6.2
4 changes: 0 additions & 4 deletions .prettierrc.js

This file was deleted.

14 changes: 0 additions & 14 deletions babel.config.js

This file was deleted.

14 changes: 0 additions & 14 deletions jest.config.js

This file was deleted.

26 changes: 11 additions & 15 deletions package-scripts.js → package-scripts.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,15 @@ module.exports = {
// with ESM. ESM support is needed due to prettier v3’s use of a dynamic
// `import()` in its `.cjs` file. The flag can be removed when node
// supports modules in the VM API or the import is removed from prettier.
default: crossEnv(
'NODE_ENV=test NODE_OPTIONS=--experimental-vm-modules jest --coverage'
),
update: crossEnv(
'NODE_ENV=test NODE_OPTIONS=--experimental-vm-modules jest --coverage --updateSnapshot'
),
watch: crossEnv(
'NODE_ENV=test NODE_OPTIONS=--experimental-vm-modules jest --watch'
),
default: crossEnv('vitest --coverage run'),
update: crossEnv('vitest --coverage --updateSnapshot'),
watch: crossEnv('vitest'),
openCoverage: 'open coverage/lcov-report/index.html',
},
build: {
description: 'delete the dist directory and run babel to build the files',
script: series(
rimraf('dist'),
'babel --out-dir dist --ignore "src/__tests__/**/*","src/__mocks__/**/*" src'
),
description:
'delete the dist directory and run Rollup to build the files',
script: series(rimraf('dist'), 'rollup -c'),
},
lint: {
description: 'lint the entire project',
Expand All @@ -57,7 +49,11 @@ module.exports = {
validate: {
description:
'This runs several scripts to make sure things look good before committing or on clean install',
script: concurrent.nps('lint', 'build', 'test'),
script: concurrent([
'nps -c ./package-scripts.cjs lint',
'nps -c ./package-scripts.cjs build',
'nps -c ./package-scripts.cjs test',
]),
},
format: {
description: 'Formats everything with prettier-eslint',
Expand Down
19 changes: 15 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
"name": "prettier-eslint",
"version": "16.3.0",
"description": "Formats your JavaScript using prettier followed by eslint --fix",
"main": "dist/index.js",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"types": "types/index.d.ts",
"type": "module",
"scripts": {
"prepare": "husky install",
"start": "nps",
"test": "nps test"
"start": "nps -c ./package-scripts.cjs",
"test": "nps -c ./package-scripts.cjs test"
},
"files": [
"dist",
Expand Down Expand Up @@ -52,20 +54,29 @@
"@babel/preset-env": "^7.22.9",
"@changesets/changelog-github": "^0.4.8",
"@changesets/cli": "^2.26.2",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@types/eslint": "^8.4.2",
"@vitest/coverage-v8": "^2.1.8",
"@vitest/ui": "^2.1.8",
"all-contributors-cli": "^6.7.0",
"eslint-config-kentcdodds": "^20.5.0",
"eslint-plugin-node-dependencies": "^0.11.0",
"husky": "^8.0.1",
"jest": "^29.6.2",
"memfs": "^4.14.1",
"nps": "^5.7.1",
"nps-utils": "^1.3.0",
"prettier-eslint-cli": "^8.0.0",
"prettier-plugin-svelte": "^3.1.2",
"rimraf": "^5.0.5",
"rollup": "^4.28.0",
"rollup-plugin-auto-external": "^2.0.0",
"strip-indent": "^3.0.0",
"svelte": "^4.2.9",
"svelte-eslint-parser": "^0.33.1"
"svelte-eslint-parser": "^0.33.1",
"vitest": "^2.1.8"
},
"engines": {
"node": ">=16.10.0"
Expand Down
4 changes: 4 additions & 0 deletions prettier.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default {
arrowParens: 'avoid',
singleQuote: true,
};
31 changes: 31 additions & 0 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import autoExternal from 'rollup-plugin-auto-external';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import { nodeResolve } from '@rollup/plugin-node-resolve';

export default {
input: 'src/index.mjs',
output: [
{
file: 'dist/cjs/index.js',
format: 'cjs',
name: 'cjs-bundle',
},
{
file: 'dist/esm/index.js',
format: 'esm',
name: 'esm-bundle',
},
],
external: ['fs', 'node:path'],
plugins: [
autoExternal(),
commonjs({
include: /node_modules/,
requireReturnsDefault: 'auto',
strictRequires: 'debug',
}),
nodeResolve({ preferBuiltins: true }),
json(),
],
};
66 changes: 30 additions & 36 deletions src/__mocks__/eslint.js → src/__mocks__/eslint.mjs
Original file line number Diff line number Diff line change
@@ -1,40 +1,16 @@
import { vi } from 'vitest';

// this mock file is so eslint doesn't attempt to actually
// search around the file system for stuff

const eslint = jest.requireActual('eslint');
const { ESLint } = eslint;

const mockCalculateConfigForFileSpy = jest.fn(mockCalculateConfigForFile);
mockCalculateConfigForFileSpy.overrides = {};
const mockLintTextSpy = jest.fn(mockLintText);

module.exports = Object.assign(eslint, {
ESLint: jest.fn(MockESLint),
mock: {
calculateConfigForFile: mockCalculateConfigForFileSpy,
lintText: mockLintTextSpy
}
});

function MockESLint(...args) {
global.__PRETTIER_ESLINT_TEST_STATE__.eslintPath = __filename;
const eslintInstance = new ESLint(...args);
eslintInstance.calculateConfigForFile = mockCalculateConfigForFileSpy;
eslintInstance._originalLintText = eslintInstance.lintText;
eslintInstance.lintText = mockLintTextSpy;
return eslintInstance;
}

MockESLint.prototype = Object.create(ESLint.prototype);
const eslintActual = await vi.importActual('eslint');
const { ESLint } = eslintActual;

// eslint-disable-next-line complexity
function mockCalculateConfigForFile(filePath) {
if (mockCalculateConfigForFileSpy.throwError) {
throw mockCalculateConfigForFileSpy.throwError;
}
if (!filePath) {
return {
rules: {}
rules: {},
};
}
if (filePath.includes('default-config')) {
Expand All @@ -46,7 +22,7 @@ function mockCalculateConfigForFile(filePath) {
quotes: [
2,
'single',
{ avoidEscape: true, allowTemplateLiterals: true }
{ avoidEscape: true, allowTemplateLiterals: true },
],
'comma-dangle': [
2,
Expand All @@ -55,26 +31,44 @@ function mockCalculateConfigForFile(filePath) {
objects: 'always-multiline',
imports: 'always-multiline',
exports: 'always-multiline',
functions: 'always-multiline'
}
functions: 'always-multiline',
},
],
'arrow-parens': [2, 'as-needed']
}
'arrow-parens': [2, 'as-needed'],
},
};
} else if (filePath.includes('fixtures/paths')) {
return { rules: {} };
} else {
throw new Error(
`Your mock filePath (${filePath})` +
' does not have a handler for finding the config'
' does not have a handler for finding the config',
);
}
}

function mockLintText(...args) {
const mockLintTextSpy = vi.fn(function mockLintText(...args) {
/* eslint no-invalid-this:0 */
if (mockLintTextSpy.throwError) {
throw mockLintTextSpy.throwError;
}
return this._originalLintText(...args);
});

const calculateConfigForFileSpy = vi.spyOn(ESLint.prototype, 'calculateConfigForFile').mockImplementation(mockCalculateConfigForFile);
const lintTextSpy = vi.spyOn(ESLint.prototype, 'lintText');

function MockESLint(...args) {
global.__PRETTIER_ESLINT_TEST_STATE__.eslintPath = __filename;
return new ESLint(...args);
}

export default {
...eslintActual.default,
ESLint: vi.fn(MockESLint),
};

export const helpers = {
getCalculateConfigForFileSpy: () => calculateConfigForFileSpy,
getLintTextSpy: () => lintTextSpy,
};
13 changes: 0 additions & 13 deletions src/__mocks__/fs.js

This file was deleted.

25 changes: 25 additions & 0 deletions src/__mocks__/fs.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// This follows the advice of the Vitest Mocking guide, and mocks the full
// filesystem with an in-memory replacement.
// https://vitest.dev/guide/mocking#file-system
const { createFsFromVolume, memfs, Volume } = require('memfs');
import path from 'node:path';

const files = [
'foo.js',
'package.json',
'node_modules/eslint/index.js',
'node_modules/prettier/index.js',
];

const volume = new Volume();

volume.fromJSON(
Object.fromEntries(
files.map(file => {
return [`./${file}`, `.tests/fixtures/paths/${file}`];
}),
),
`${path.dirname(__filename)}/../../tests/fixtures/paths`,
);

export default createFsFromVolume(volume);
Loading

0 comments on commit 2f68f10

Please sign in to comment.