Skip to content

Commit

Permalink
Merge pull request #362 from lo1tuma/esm
Browse files Browse the repository at this point in the history
Switch to ESM
  • Loading branch information
lo1tuma authored Aug 23, 2024
2 parents d634be5 + b3c5d3b commit 4168eca
Show file tree
Hide file tree
Showing 62 changed files with 373 additions and 291 deletions.
4 changes: 2 additions & 2 deletions .c8rc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
"functions": 100,
"branches": 100,
"check-coverage": true,
"extension": [".js", ".mjs"],
"extension": [".js"],
"instrument": false,
"src": ".",
"reporter": ["lcov", "text-summary"],
"reportDir": "./target/coverage",
"tempDirectory": "./target/c8-temporary-output",
"exclude": ["target", "test", "benchmarks/", "eslint.config.mjs"]
"exclude": ["target", "test", "benchmarks/", "eslint.config.js"]
}
57 changes: 41 additions & 16 deletions benchmarks/measure.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,63 @@
const os = require('node:os');
const { performance: performanceHooks } = require('node:perf_hooks');
const { times, median, map, prop } = require('rambda');
import os from 'node:os';
import { performance as performanceHooks } from 'node:perf_hooks';
import { filter, lte as isLowerThanOrEquals, map, median, prop, times } from 'rambda';

const [{ speed: cpuSpeed }] = os.cpus();

function clearRequireCache() {
Object.keys(require.cache).forEach((key) => {
delete require.cache[key];
});
export { cpuSpeed };

export async function importFresh(modulePath) {
const cacheBuster = `${performanceHooks.now()}_${Math.random()}`;
const cacheBustingModulePath = `${modulePath}?buster=${cacheBuster}`;

await import(cacheBustingModulePath);
}

function runBenchmark(fn, count) {
const isPositiveNumber = isLowerThanOrEquals(0);

export function runSyncBenchmark(fn, count) {
const results = [];

times(() => {
const startTime = performanceHooks.now();
const startMemory = process.memoryUsage().rss;
const startMemory = process.memoryUsage.rss();
fn();
const endTime = performanceHooks.now();
const endMemory = process.memoryUsage().rss;
const endMemory = process.memoryUsage.rss();
const duration = endTime - startTime;
const memory = endMemory - startMemory;

results.push({ duration, memory });
}, count);

const medianDuration = median(map(prop('duration'), results));
const medianMemory = median(map(prop('memory'), results));
const medianMemory = median(filter(isPositiveNumber, map(prop('memory'), results)));

return { medianDuration, medianMemory };
}

module.exports = {
runBenchmark,
clearRequireCache,
cpuSpeed
};
async function measureSingleAsyncTask(fn) {
const startTime = performanceHooks.now();
const startMemory = process.memoryUsage().rss;
await fn();
const endTime = performanceHooks.now();
const endMemory = process.memoryUsage().rss;
const duration = endTime - startTime;
const memory = endMemory - startMemory;

return { duration, memory };
}

export async function runAsyncBenchmark(fn, count) {
const results = [];

for (let iteration = 0; iteration < count; iteration += 1) {
const result = await measureSingleAsyncTask(fn);
results.push(result);
}

const medianDuration = median(map(prop('duration'), results));
const medianMemory = median(filter(isPositiveNumber, map(prop('memory'), results)));

return { medianDuration, medianMemory };
}
34 changes: 20 additions & 14 deletions benchmarks/runtime.bench.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
const assert = require('node:assert');
const { Linter } = require('eslint');
const { times } = require('rambda');
const {
runBenchmark,
cpuSpeed
} = require('./measure');
const mochaPlugin = require('../');
import { Linter } from 'eslint';
import assert from 'node:assert';
import { times } from 'rambda';
import mochaPlugin from '../index.js';
import { cpuSpeed, runSyncBenchmark } from './measure.js';

const allRules = mochaPlugin.configs.all.rules;

Expand All @@ -17,6 +14,7 @@ function lintManyFilesWithAllRecommendedRules(options) {
plugins: { mocha: mochaPlugin },
rules: allRules,
languageOptions: {
sourceType: 'script',
ecmaVersion: 2018
}
};
Expand Down Expand Up @@ -82,23 +80,31 @@ const iterations = 50;

describe('runtime', function () {
it('should not take longer as the defined budget to lint many files with the recommended config', function () {
const cpuAgnosticBudget = 3_750_000;
const cpuAgnosticBudget = 3_250_000;
const budget = cpuAgnosticBudget / cpuSpeed;

const { medianDuration } = runBenchmark(() => {
const { medianDuration } = runSyncBenchmark(() => {
lintManyFilesWithAllRecommendedRules({ numberOfFiles: 350 });
}, iterations);

assert.strictEqual(medianDuration < budget, true);
assert.strictEqual(
medianDuration < budget,
true,
`Expected duration ${medianDuration} to be lower than budget ${budget}`
);
});

it('should not consume more memory as the defined budget to lint many files with the recommended config', function () {
const budget = 2_750_000;
const budget = 2_250_000;

const { medianMemory } = runBenchmark(() => {
const { medianMemory } = runSyncBenchmark(() => {
lintManyFilesWithAllRecommendedRules({ numberOfFiles: 350 });
}, iterations);

assert.strictEqual(medianMemory < budget, true);
assert.strictEqual(
medianMemory < budget,
true,
`Expected memory ${medianMemory} to be lower than budget ${budget}`
);
});
});
34 changes: 20 additions & 14 deletions benchmarks/startup.bench.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
const assert = require('node:assert');
const { runBenchmark, cpuSpeed, clearRequireCache } = require('./measure');
import assert from 'node:assert';
import { cpuSpeed, importFresh, runAsyncBenchmark } from './measure.js';

const iterations = 50;

describe('startup / require time', function () {
it('should not take longer as the defined budget to require the plugin', function () {
const cpuAgnosticBudget = 85_000;
it('should not take longer as the defined budget to require the plugin', async function () {
const cpuAgnosticBudget = 20_000;
const budget = cpuAgnosticBudget / cpuSpeed;

const { medianDuration } = runBenchmark(() => {
clearRequireCache();
require('../index');
const { medianDuration } = await runAsyncBenchmark(async () => {
await importFresh('../index.js');
}, iterations);

assert.strictEqual(medianDuration < budget, true);
assert.strictEqual(
medianDuration < budget,
true,
`Expected duration ${medianDuration} to be lower than budget ${budget}`
);
});

it('should not consume more memory as the defined budget', function () {
const budget = 600_000;
it('should not consume more memory as the defined budget', async function () {
const budget = 225_000;

const { medianMemory } = runBenchmark(() => {
clearRequireCache();
require('../index');
const { medianMemory } = await runAsyncBenchmark(async () => {
await importFresh('../index.js');
}, iterations);

assert.strictEqual(medianMemory < budget, true);
assert.strictEqual(
medianMemory < budget,
true,
`Expected memory ${medianMemory} to be lower than budget ${budget}`
);
});
});
17 changes: 9 additions & 8 deletions eslint.config.mjs → eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,11 @@ import { baseConfig } from '@enormora/eslint-config-base';
import { mochaConfig } from '@enormora/eslint-config-mocha';
import { nodeConfig, nodeConfigFileConfig, nodeEntryPointFileConfig } from '@enormora/eslint-config-node';
import eslintPluginEslintPlugin from 'eslint-plugin-eslint-plugin';
import globals from 'globals';

export default [
{
ignores: ['target/**/*']
},
{
files: ['**/*.js', '**/*.mjs'],
languageOptions: {
globals: globals.node
}
},
baseConfig,
nodeConfig,
{
Expand All @@ -33,14 +26,16 @@ export default [
'import/newline-after-import': 'off',
'import/no-amd': 'off',
'import/no-commonjs': 'off',
'import/no-useless-path-segments': 'off',
'import/first': 'off',

// incompatible with dprint
'@stylistic/indent-binary-ops': 'off'
}
},
{
...nodeConfigFileConfig,
files: ['eslint.config.mjs']
files: ['eslint.config.js']
},
{
...mochaConfig,
Expand Down Expand Up @@ -75,6 +70,12 @@ export default [
...nodeEntryPointFileConfig,
files: ['index.js']
},
{
files: ['index.js'],
rules: {
'import/no-default-export': 'off'
}
},
{
files: ['lib/rules/**/*.js', 'test/rules/**/*.js'],
plugins: { 'eslint-plugin': eslintPluginEslintPlugin },
Expand Down
84 changes: 54 additions & 30 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@
const globals = require('globals');
import globals from 'globals';
import { consistentSpacingBetweenBlocksRule } from './lib/rules/consistent-spacing-between-blocks.js';
import { handleDoneCallbackRule } from './lib/rules/handle-done-callback.js';
import { maxTopLevelSuitesRule } from './lib/rules/max-top-level-suites.js';
import { noAsyncDescribeRule } from './lib/rules/no-async-describe.js';
import { noEmptyDescriptionRule } from './lib/rules/no-empty-description.js';
import { noExclusiveTestsRule } from './lib/rules/no-exclusive-tests.js';
import { noExportsRule } from './lib/rules/no-exports.js';
import { noGlobalTestsRule } from './lib/rules/no-global-tests.js';
import { noHooksForSingleCaseRule } from './lib/rules/no-hooks-for-single-case.js';
import { noHooksRule } from './lib/rules/no-hooks.js';
import { noIdenticalTitleRule } from './lib/rules/no-identical-title.js';
import { noMochaArrowsRule } from './lib/rules/no-mocha-arrows.js';
import { noNestedTestsRule } from './lib/rules/no-nested-tests.js';
import { noPendingTestsRule } from './lib/rules/no-pending-tests.js';
import { noReturnAndCallbackRule } from './lib/rules/no-return-and-callback.js';
import { noReturnFromAsyncRule } from './lib/rules/no-return-from-async.js';
import { noSetupInDescribeRule } from './lib/rules/no-setup-in-describe.js';
import { noSiblingHooksRule } from './lib/rules/no-sibling-hooks.js';
import { noSkippedTestsRule } from './lib/rules/no-skipped-tests.js';
import { noSynchronousTestsRule } from './lib/rules/no-synchronous-tests.js';
import { noTopLevelHooksRule } from './lib/rules/no-top-level-hooks.js';
import { preferArrowCallbackRule } from './lib/rules/prefer-arrow-callback.js';
import { validSuiteDescriptionRule } from './lib/rules/valid-suite-description.js';
import { validTestDescriptionRule } from './lib/rules/valid-test-description.js';

const allRules = {
'mocha/handle-done-callback': 'error',
Expand Down Expand Up @@ -54,32 +78,32 @@ const recommendedRules = {
'mocha/consistent-spacing-between-blocks': 'error'
};

const mod = {
const mochaPlugin = {
rules: {
'handle-done-callback': require('./lib/rules/handle-done-callback'),
'max-top-level-suites': require('./lib/rules/max-top-level-suites'),
'no-async-describe': require('./lib/rules/no-async-describe'),
'no-exclusive-tests': require('./lib/rules/no-exclusive-tests'),
'no-exports': require('./lib/rules/no-exports'),
'no-global-tests': require('./lib/rules/no-global-tests'),
'no-hooks': require('./lib/rules/no-hooks'),
'no-hooks-for-single-case': require('./lib/rules/no-hooks-for-single-case'),
'no-identical-title': require('./lib/rules/no-identical-title'),
'no-mocha-arrows': require('./lib/rules/no-mocha-arrows'),
'no-nested-tests': require('./lib/rules/no-nested-tests'),
'no-pending-tests': require('./lib/rules/no-pending-tests'),
'no-return-and-callback': require('./lib/rules/no-return-and-callback'),
'no-return-from-async': require('./lib/rules/no-return-from-async'),
'no-setup-in-describe': require('./lib/rules/no-setup-in-describe'),
'no-sibling-hooks': require('./lib/rules/no-sibling-hooks'),
'no-skipped-tests': require('./lib/rules/no-skipped-tests'),
'no-synchronous-tests': require('./lib/rules/no-synchronous-tests'),
'no-top-level-hooks': require('./lib/rules/no-top-level-hooks'),
'prefer-arrow-callback': require('./lib/rules/prefer-arrow-callback'),
'valid-suite-description': require('./lib/rules/valid-suite-description'),
'valid-test-description': require('./lib/rules/valid-test-description'),
'no-empty-description': require('./lib/rules/no-empty-description.js'),
'consistent-spacing-between-blocks': require('./lib/rules/consistent-spacing-between-blocks.js')
'handle-done-callback': handleDoneCallbackRule,
'max-top-level-suites': maxTopLevelSuitesRule,
'no-async-describe': noAsyncDescribeRule,
'no-exclusive-tests': noExclusiveTestsRule,
'no-exports': noExportsRule,
'no-global-tests': noGlobalTestsRule,
'no-hooks': noHooksRule,
'no-hooks-for-single-case': noHooksForSingleCaseRule,
'no-identical-title': noIdenticalTitleRule,
'no-mocha-arrows': noMochaArrowsRule,
'no-nested-tests': noNestedTestsRule,
'no-pending-tests': noPendingTestsRule,
'no-return-and-callback': noReturnAndCallbackRule,
'no-return-from-async': noReturnFromAsyncRule,
'no-setup-in-describe': noSetupInDescribeRule,
'no-sibling-hooks': noSiblingHooksRule,
'no-skipped-tests': noSkippedTestsRule,
'no-synchronous-tests': noSynchronousTestsRule,
'no-top-level-hooks': noTopLevelHooksRule,
'prefer-arrow-callback': preferArrowCallbackRule,
'valid-suite-description': validSuiteDescriptionRule,
'valid-test-description': validTestDescriptionRule,
'no-empty-description': noEmptyDescriptionRule,
'consistent-spacing-between-blocks': consistentSpacingBetweenBlocksRule
},
configs: {
all: {
Expand All @@ -95,19 +119,19 @@ const mod = {
}
};

mod.configs.flat = {
mochaPlugin.configs.flat = {
all: {
name: 'mocha/all',
plugins: { mocha: mod },
plugins: { mocha: mochaPlugin },
languageOptions: { globals: globals.mocha },
rules: allRules
},
recommended: {
name: 'mocha/recommended',
plugins: { mocha: mod },
plugins: { mocha: mochaPlugin },
languageOptions: { globals: globals.mocha },
rules: recommendedRules
}
};

module.exports = mod;
export default mochaPlugin;
Loading

0 comments on commit 4168eca

Please sign in to comment.