feat: migrate to ESM and update Jest configuration

- Added package.json in dist/setup to specify module type as ESM.
- Updated jest.config.js to support ESM with ts-jest and added moduleNameMapper for .js extensions.
- Created jest.setup.js to ensure Jest globals are available in ESM mode.
- Modified test script in package.json to use node with experimental VM modules for Jest.
- Updated imports in various distribution files to include .js extensions for ESM compatibility.
- Adjusted tsconfig.json to exclude __tests__ directory and maintain ESM settings.
- Updated package-lock.json to include new dependencies and their versions.
This commit is contained in:
Salman Muin Kayser Chishti 2025-10-14 14:21:06 +01:00
parent 100690a6a6
commit 81b484e462
28 changed files with 3641 additions and 5337 deletions

View file

@ -3,17 +3,22 @@ import fs from 'fs';
import * as path from 'path';
import * as core from '@actions/core';
import * as io from '@actions/io';
import * as auth from '../src/authutil';
import * as cacheUtils from '../src/cache-utils';
import * as auth from '../src/authutil.js';
import * as cacheUtils from '../src/cache-utils.js';
import {fileURLToPath} from 'url';
import {jest, describe, beforeEach, afterEach, it, expect} from '@jest/globals';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
let rcFile: string;
describe('authutil tests', () => {
const _runnerDir = path.join(__dirname, 'runner');
let cnSpy: jest.SpyInstance;
let logSpy: jest.SpyInstance;
let dbgSpy: jest.SpyInstance;
let cnSpy: any;
let logSpy: any;
let dbgSpy: any;
beforeAll(async () => {
const randPath = path.join(Math.random().toString(36).substring(7));

View file

@ -3,9 +3,13 @@ import * as cache from '@actions/cache';
import * as path from 'path';
import * as glob from '@actions/glob';
import osm from 'os';
import {fileURLToPath} from 'url';
import * as utils from '../src/cache-utils';
import {restoreCache} from '../src/cache-restore';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
import * as utils from '../src/cache-utils.js';
import {restoreCache} from '../src/cache-restore.js';
describe('cache-restore', () => {
process.env['GITHUB_WORKSPACE'] = path.join(__dirname, 'data');

View file

@ -3,10 +3,14 @@ import * as cache from '@actions/cache';
import * as glob from '@actions/glob';
import fs from 'fs';
import path from 'path';
import {fileURLToPath} from 'url';
import * as utils from '../src/cache-utils';
import {run} from '../src/cache-save';
import {State} from '../src/constants';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
import * as utils from '../src/cache-utils.js';
import {run} from '../src/cache-save.js';
import {State} from '../src/constants.js';
describe('run', () => {
const yarnFileHash =

View file

@ -1,19 +1,23 @@
import * as core from '@actions/core';
import * as cache from '@actions/cache';
import path from 'path';
import * as utils from '../src/cache-utils';
import * as utils from '../src/cache-utils.js';
import {
PackageManagerInfo,
isCacheFeatureAvailable,
supportedPackageManagers,
isGhes,
resetProjectDirectoriesMemoized
} from '../src/cache-utils';
} from '../src/cache-utils.js';
import fs from 'fs';
import * as cacheUtils from '../src/cache-utils';
import * as cacheUtils from '../src/cache-utils.js';
import * as glob from '@actions/glob';
import {Globber} from '@actions/glob';
import {MockGlobber} from './mock/glob-mock';
import {MockGlobber} from './mock/glob-mock.js';
import {fileURLToPath} from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
describe('cache-utils', () => {
const versionYarn1 = '1.2.3';

View file

@ -8,9 +8,9 @@ import fs from 'fs';
import cp from 'child_process';
import osm from 'os';
import path from 'path';
import * as main from '../src/main';
import * as auth from '../src/authutil';
import {INodeVersion} from '../src/distributions/base-models';
import * as main from '../src/main.js';
import * as auth from '../src/authutil.js';
import {INodeVersion} from '../src/distributions/base-models.js';
import nodeTestManifest from './data/versions-manifest.json';
import nodeTestDist from './data/node-dist-index.json';

View file

@ -7,12 +7,16 @@ import * as io from '@actions/io';
import fs from 'fs';
import path from 'path';
import osm from 'os';
import {fileURLToPath} from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
import each from 'jest-each';
import * as main from '../src/main';
import * as util from '../src/util';
import OfficialBuilds from '../src/distributions/official_builds/official_builds';
import * as main from '../src/main.js';
import * as util from '../src/util.js';
import OfficialBuilds from '../src/distributions/official_builds/official_builds.js';
describe('main tests', () => {
let inputs = {} as any;

View file

@ -1,4 +1,4 @@
import {MockGlobber} from './glob-mock';
import {MockGlobber} from './glob-mock.js';
describe('mocked globber tests', () => {
it('globber should return generator', async () => {

View file

@ -8,9 +8,9 @@ import fs from 'fs';
import cp from 'child_process';
import osm from 'os';
import path from 'path';
import * as main from '../src/main';
import * as auth from '../src/authutil';
import {INodeVersion} from '../src/distributions/base-models';
import * as main from '../src/main.js';
import * as auth from '../src/authutil.js';
import {INodeVersion} from '../src/distributions/base-models.js';
import nodeTestManifest from './data/versions-manifest.json';
import nodeTestDist from './data/node-dist-index.json';

View file

@ -8,9 +8,9 @@ import fs from 'fs';
import cp from 'child_process';
import osm from 'os';
import path from 'path';
import * as main from '../src/main';
import * as auth from '../src/authutil';
import {INodeVersion} from '../src/distributions/base-models';
import * as main from '../src/main.js';
import * as auth from '../src/authutil.js';
import {INodeVersion} from '../src/distributions/base-models.js';
import nodeTestDist from './data/node-dist-index.json';
import nodeTestDistNightly from './data/node-nightly-index.json';

View file

@ -1,7 +1,6 @@
"use strict";
exports.id = 101;
exports.ids = [101];
exports.modules = {
export const id = 101;
export const ids = [101];
export const modules = {
/***/ 9101:
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
@ -448,4 +447,3 @@ async function toFormData(Body, ct) {
/***/ })
};
;

1620
dist/cache-save/index.js vendored

File diff suppressed because one or more lines are too long

3
dist/cache-save/package.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"type": "module"
}

View file

@ -1,16 +1,15 @@
"use strict";
exports.id = 101;
exports.ids = [101];
exports.modules = {
export const id = 101;
export const ids = [101];
export const modules = {
/***/ 29101:
/***/ 9101:
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ toFormData: () => (/* binding */ toFormData)
/* harmony export */ });
/* harmony import */ var fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9802);
/* harmony import */ var formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(83018);
/* harmony import */ var formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3018);
@ -448,4 +447,3 @@ async function toFormData(Body, ct) {
/***/ })
};
;

BIN
dist/setup/7zr.exe vendored Normal file

Binary file not shown.

7167
dist/setup/index.js vendored

File diff suppressed because one or more lines are too long

3
dist/setup/package.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"type": "module"
}

View file

@ -5,14 +5,21 @@ export default {
testMatch: ['**/*.test.ts'],
testRunner: 'jest-circus/runner',
extensionsToTreatAsEsm: ['.ts'],
globals: {
'ts-jest': {
useESM: true
}
},
transform: {
'^.+\\.ts$': 'ts-jest'
'^.+\\.ts$': ['ts-jest', {
useESM: true,
tsconfig: {
module: 'es2022',
target: 'es2022'
}
}]
},
preset: 'ts-jest/presets/default-esm',
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1'
},
transformIgnorePatterns: [
'node_modules/(?!(node-fetch|fetch-blob|formdata-polyfill|data-uri-to-buffer)/)'
],
verbose: true
}

5
jest.setup.js Normal file
View file

@ -0,0 +1,5 @@
// Jest setup file to ensure globals are available in ESM mode
import { jest } from '@jest/globals';
// Make jest available globally
globalThis.jest = jest;

27
package-lock.json generated
View file

@ -4695,6 +4695,33 @@
"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
"dev": true
},
"node_modules/neo-async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true,
"license": "MIT"
},
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"deprecated": "Use your platform's native DOMException instead",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"license": "MIT",
"engines": {
"node": ">=10.5.0"
}
},
"node_modules/node-fetch": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",

View file

@ -14,7 +14,7 @@
"format-check": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --check \"**/*.{ts,yml,yaml}\"",
"lint": "eslint --config ./.eslintrc.js \"**/*.ts\"",
"lint:fix": "eslint --config ./.eslintrc.js \"**/*.ts\" --fix",
"test": "jest --coverage",
"test": "node --experimental-vm-modules node_modules/.bin/jest --coverage",
"pre-checkin": "npm run format && npm run lint:fix && npm run build && npm test"
},
"repository": {

View file

@ -2,8 +2,8 @@ import * as tc from '@actions/tool-cache';
import semver from 'semver';
import BaseDistribution from './base-distribution';
import {NodeInputs} from './base-models';
import BaseDistribution from './base-distribution.js';
import {NodeInputs} from './base-models.js';
export default abstract class BasePrereleaseNodejs extends BaseDistribution {
protected abstract distribution: string;

View file

@ -11,7 +11,7 @@ import * as path from 'path';
import os from 'os';
import fs from 'fs';
import {NodeInputs, INodeVersion, INodeVersionInfo} from './base-models';
import {NodeInputs, INodeVersion, INodeVersionInfo} from './base-models.js';
export default abstract class BaseDistribution {
protected httpClient: hc.HttpClient;

View file

@ -1,9 +1,9 @@
import BaseDistribution from './base-distribution';
import {NodeInputs} from './base-models';
import NightlyNodejs from './nightly/nightly_builds';
import OfficialBuilds from './official_builds/official_builds';
import RcBuild from './rc/rc_builds';
import CanaryBuild from './v8-canary/canary_builds';
import BaseDistribution from './base-distribution.js';
import {NodeInputs} from './base-models.js';
import NightlyNodejs from './nightly/nightly_builds.js';
import OfficialBuilds from './official_builds/official_builds.js';
import RcBuild from './rc/rc_builds.js';
import CanaryBuild from './v8-canary/canary_builds.js';
enum Distributions {
DEFAULT = '',

View file

@ -1,5 +1,5 @@
import BasePrereleaseNodejs from '../base-distribution-prerelease';
import {NodeInputs} from '../base-models';
import BasePrereleaseNodejs from '../base-distribution-prerelease.js';
import {NodeInputs} from '../base-models.js';
export default class NightlyNodejs extends BasePrereleaseNodejs {
protected distribution = 'nightly';

View file

@ -2,8 +2,8 @@ import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
import path from 'path';
import BaseDistribution from '../base-distribution';
import {NodeInputs, INodeVersion, INodeVersionInfo} from '../base-models';
import BaseDistribution from '../base-distribution.js';
import {NodeInputs, INodeVersion, INodeVersionInfo} from '../base-models.js';
interface INodeRelease extends tc.IToolRelease {
lts?: string;

View file

@ -1,5 +1,5 @@
import BaseDistribution from '../base-distribution';
import {NodeInputs} from '../base-models';
import BaseDistribution from '../base-distribution.js';
import {NodeInputs} from '../base-models.js';
export default class RcBuild extends BaseDistribution {
constructor(nodeInfo: NodeInputs) {

View file

@ -1,5 +1,5 @@
import BasePrereleaseNodejs from '../base-distribution-prerelease';
import {NodeInputs} from '../base-models';
import BasePrereleaseNodejs from '../base-distribution-prerelease.js';
import {NodeInputs} from '../base-models.js';
export default class CanaryBuild extends BasePrereleaseNodejs {
protected distribution = 'v8-canary';

View file

@ -4,12 +4,11 @@
"module": "es2022", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"moduleResolution": "node", /* Specify module resolution strategy: 'node' or 'classic'. */
"outDir": "./lib", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
"sourceMap": true,
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"resolveJsonModule": true, /* Allows importing modules with a '.json' extension, which is a common practice in node projects. */
},
"exclude": ["__tests__", "lib", "node_modules"]
"exclude": ["lib", "node_modules"]
}