Skip to content

Commit 576cb5e

Browse files
feat: convert to ESM + update all dependencies (#277)
BREAKING CHANGE: We now require node 20 or higher
1 parent 28f88c9 commit 576cb5e

21 files changed

+50317
-1071
lines changed

.circleci/config.yml

+2-13
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,6 @@ workflows:
1010
jobs:
1111
- node/test:
1212
name: test-<< matrix.executor >>-<< matrix.node-version >>
13-
pre-steps:
14-
- when:
15-
condition:
16-
and:
17-
- equal: [ node/macos, << matrix.executor >> ]
18-
- equal: [ '14.16', << matrix.node-version >> ]
19-
steps:
20-
- node/install-rosetta
2113
test-steps:
2214
- run: yarn prettier:check
2315
- run: yarn test
@@ -30,11 +22,8 @@ workflows:
3022
- node/macos
3123
- node/windows
3224
node-version:
33-
- '20.10'
34-
- '18.18'
35-
- '16.20'
36-
# Stay below 14.17.0 or nvm tries to download arm64 artifacts which don't exist
37-
- '14.16'
25+
- '22.9'
26+
- '20.11'
3827
- cfa/release:
3928
requires:
4029
- test

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf

.husky/pre-commit

-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1 @@
1-
#!/usr/bin/env sh
2-
. "$(dirname -- "$0")/_/husky.sh"
3-
41
yarn lint-staged

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ The module exports a function that parses a given API JSON object and returns
2828
an array of lines to create the definition file
2929

3030
```js
31-
const { generateDefinitions } = require('@electron/typescript-definitions')
31+
import { generateDefinitions } from '@electron/typescript-definitions'
32+
3233
const apiPath = './vendor/electron/docs/api.json'
3334

34-
const definitionLines = generateDefinitions({ electronApi: require(apiPath) })
35+
const definitionLines = generateDefinitions({ electronApi: loadJSON(apiPath) })
3536
// definitionLines will be an strin representation of the definition file
3637
```
3738

jest.config.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import path from 'node:path';
2+
import { createDefaultEsmPreset } from 'ts-jest';
3+
4+
/** @type {import('ts-jest').JestConfigWithTsJest} **/
5+
export default {
6+
moduleNameMapper: {
7+
'^(\\.{1,2}/.*)\\.js$': '$1',
8+
},
9+
testPathIgnorePatterns: ['node_modules', path.resolve(import.meta.dirname, 'dist')],
10+
...createDefaultEsmPreset({
11+
tsconfig: 'tsconfig.json',
12+
})
13+
};

package.json

+24-26
Original file line numberDiff line numberDiff line change
@@ -6,46 +6,44 @@
66
"electron-typescript-definitions": "dist/bin.js"
77
},
88
"main": "dist/index.js",
9+
"type": "module",
910
"engines": {
10-
"node": ">=14.0.0"
11+
"node": ">=20.9.0"
1112
},
1213
"scripts": {
1314
"build": "tsc",
14-
"prepare": "husky install",
15+
"prepare": "husky",
1516
"prepublishOnly": "yarn build",
16-
"prettier:check": "prettier --list-different \"src/**/*.{ts,tsx}\"",
17-
"prettier:write": "prettier --write \"src/**/*.{ts,tsx}\"",
18-
"test": "yarn build && mocha"
17+
"prettier:check": "prettier --list-different \"{src,test}/**/*.ts\"",
18+
"prettier:write": "prettier --write \"{src,test}/**/*.ts\"",
19+
"pretest": "tsc",
20+
"test": "cross-env NODE_OPTIONS=\"--experimental-vm-modules\" jest"
1921
},
2022
"author": {
2123
"name": "Samuel Attard",
2224
"homepage": "https://www.samuelattard.com"
2325
},
2426
"license": "MIT",
2527
"devDependencies": {
26-
"@electron/docs-parser": "^1.2.0",
27-
"@types/debug": "^4.1.4",
28-
"@types/fs-extra": "^5.0.5",
29-
"@types/lodash": "^4.14.123",
30-
"@types/minimist": "^1.2.0",
31-
"chai": "^4.2.0",
32-
"husky": "^8.0.2",
33-
"lint-staged": "^13.0.4",
34-
"mocha": "^10.1.0",
35-
"prettier": "^1.17.0",
36-
"typescript": "^3.4.5"
28+
"@electron/docs-parser": "^2.0.0",
29+
"@types/debug": "^4.1.12",
30+
"@types/jest": "^29.5.13",
31+
"@types/lodash": "^4.17.7",
32+
"cross-env": "^7.0.3",
33+
"husky": "^9.1.6",
34+
"jest": "^30.0.0-alpha.6",
35+
"lint-staged": "^15.2.10",
36+
"prettier": "^3.3.3",
37+
"ts-jest": "^29.2.5",
38+
"typescript": "^5.6.2"
3739
},
3840
"dependencies": {
39-
"@types/node": "^11.13.7",
40-
"chalk": "^2.4.2",
41-
"colors": "^1.1.2",
42-
"debug": "^4.1.1",
43-
"fs-extra": "^7.0.1",
41+
"@types/node": "^20.11.25",
42+
"chalk": "^5.3.0",
43+
"debug": "^4.3.7",
4444
"lodash": "^4.17.11",
45-
"minimist": "^1.2.0",
46-
"mkdirp": "^0.5.1",
47-
"ora": "^3.4.0",
48-
"pretty-ms": "^5.0.0"
45+
"ora": "^8.1.0",
46+
"pretty-ms": "^9.1.0"
4947
},
5048
"repository": {
5149
"type": "git",
@@ -57,6 +55,6 @@
5755
"base"
5856
],
5957
"lint-staged": {
60-
"*.{js,ts}": "prettier --write"
58+
"*.ts": "prettier --write"
6159
}
6260
}

src/bin.ts

+28-13
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,32 @@
11
#!/usr/bin/env node
22

3-
import * as fs from 'fs-extra';
4-
import minimist from 'minimist';
5-
import ora from 'ora';
6-
import * as path from 'path';
7-
import pretty from 'pretty-ms';
3+
import fs from 'node:fs';
4+
import path from 'node:path';
5+
import { parseArgs } from 'node:util';
86

97
import chalk from 'chalk';
10-
import { generateDefinitions } from '.';
8+
import ora from 'ora';
9+
import pretty from 'pretty-ms';
1110

12-
const args = minimist(process.argv);
11+
import { generateDefinitions } from './index.js';
1312

14-
const { api, outDir, help } = args;
13+
const {
14+
values: { api, outDir, help },
15+
} = parseArgs({
16+
options: {
17+
api: {
18+
type: 'string',
19+
},
20+
outDir: {
21+
type: 'string',
22+
default: process.cwd(),
23+
},
24+
help: {
25+
type: 'boolean',
26+
default: false,
27+
},
28+
},
29+
});
1530

1631
if (help) {
1732
console.info(
@@ -30,7 +45,7 @@ if (typeof api !== 'string') {
3045
}
3146

3247
const resolvedApi = path.isAbsolute(api) ? api : path.resolve(process.cwd(), api);
33-
if (!fs.pathExistsSync(resolvedApi)) {
48+
if (!fs.existsSync(resolvedApi)) {
3449
runner.fail(`${chalk.red('Resolved directory does not exist:')} ${chalk.cyan(resolvedApi)}`);
3550
process.exit(1);
3651
}
@@ -47,19 +62,19 @@ runner.text = chalk.cyan(`Generating API in directory: ${chalk.yellow(`"${resolv
4762
const start = Date.now();
4863
const resolvedFilePath = path.resolve(resolvedOutDir, './electron.d.ts');
4964

50-
fs.mkdirp(resolvedOutDir).then(() =>
65+
fs.promises.mkdir(resolvedOutDir, { recursive: true }).then(async () =>
5166
generateDefinitions({
52-
electronApi: require(resolvedApi),
67+
electronApi: JSON.parse(await fs.promises.readFile(resolvedApi, 'utf-8')),
5368
})
54-
.then(data => fs.writeFile(resolvedFilePath, data))
69+
.then((data) => fs.promises.writeFile(resolvedFilePath, data))
5570
.then(() =>
5671
runner.succeed(
5772
`${chalk.green('Electron Typescript Definitions generated in')} ${chalk.yellow(
5873
`"${resolvedFilePath}"`,
5974
)} took ${chalk.cyan(pretty(Date.now() - start))}`,
6075
),
6176
)
62-
.catch(err => {
77+
.catch((err) => {
6378
console.error(err);
6479
process.exit(1);
6580
}),

src/dynamic-param-interfaces.ts

+14-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
import _ from 'lodash';
2-
import * as utils from './utils';
3-
import d from 'debug';
41
import {
52
EventParameterDocumentation,
63
DetailedObjectType,
@@ -9,6 +6,11 @@ import {
96
DocumentationTag,
107
} from '@electron/docs-parser';
118
import chalk from 'chalk';
9+
import d from 'debug';
10+
import _ from 'lodash';
11+
12+
import * as utils from './utils.js';
13+
1214
const debug = d('dynamic-param');
1315

1416
type ParamInterface = EventParameterDocumentation &
@@ -37,7 +39,7 @@ const polite = (s: string): string => {
3739
const ignoreDescriptions = <T extends EventParameterDocumentation>(
3840
props: T[],
3941
): Pick<T, Exclude<keyof T, 'description'>>[] =>
40-
_.map(props, p => {
42+
_.map(props, (p) => {
4143
const { description, ...toReturn } = p;
4244

4345
return toReturn;
@@ -48,7 +50,7 @@ const unsetDescriptions = (o: any): any => {
4850
if (noDescriptionCache.has(o)) return noDescriptionCache.get(o);
4951
if (typeof o !== 'object' || !o) return o;
5052
const val = Array.isArray(o)
51-
? o.map(item => unsetDescriptions(item))
53+
? o.map((item) => unsetDescriptions(item))
5254
: Object.keys(o).reduce((accum: any, key: string) => {
5355
if (key === 'description') return accum;
5456
accum[key] = unsetDescriptions(o[key]);
@@ -149,7 +151,7 @@ const flushParamInterfaces = (
149151
.sort((a, b) =>
150152
paramInterfacesToDeclare[a].tName!.localeCompare(paramInterfacesToDeclare[b].tName!),
151153
)
152-
.forEach(paramKey => {
154+
.forEach((paramKey) => {
153155
if (paramKey === 'Event') {
154156
throw 'Unexpected dynamic Event type, should be routed through the Event handler';
155157
}
@@ -181,7 +183,7 @@ const flushParamInterfaces = (
181183
);
182184

183185
param.properties = param.properties || [];
184-
param.properties.forEach(paramProperty => {
186+
param.properties.forEach((paramProperty) => {
185187
if (paramProperty.description) {
186188
utils.extendArray(
187189
paramAPI,
@@ -192,7 +194,7 @@ const flushParamInterfaces = (
192194
if (!Array.isArray(paramProperty.type) && paramProperty.type.toLowerCase() === 'object') {
193195
let argType =
194196
(paramProperty as any).__type || _.upperFirst(_.camelCase(paramProperty.name));
195-
if (API.some(a => a.name === argType)) {
197+
if (API.some((a) => a.name === argType)) {
196198
paramProperty.type = argType;
197199
debug(
198200
chalk.red(
@@ -210,7 +212,7 @@ const flushParamInterfaces = (
210212
}
211213

212214
if (Array.isArray(paramProperty.type)) {
213-
paramProperty.type = paramProperty.type.map(paramPropertyType => {
215+
paramProperty.type = paramProperty.type.map((paramPropertyType) => {
214216
const functionProp = paramPropertyType as DetailedFunctionType;
215217
if (paramPropertyType.type === 'Function' && functionProp.parameters) {
216218
return {
@@ -229,7 +231,7 @@ const flushParamInterfaces = (
229231
) {
230232
let argType =
231233
(paramProperty as any).__type || _.upperFirst(_.camelCase(paramProperty.name));
232-
if (API.some(a => a.name === argType)) {
234+
if (API.some((a) => a.name === argType)) {
233235
paramPropertyType.type = argType;
234236
debug(
235237
chalk.red(
@@ -293,3 +295,5 @@ export class DynamicParamInterfaces {
293295
static createParamInterface = createParamInterface;
294296
static flushParamInterfaces = flushParamInterfaces;
295297
}
298+
299+
utils.setParamInterfaces(DynamicParamInterfaces);

src/index.ts

+15-13
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
1-
import _ from 'lodash';
2-
import * as fs from 'fs-extra';
3-
import * as path from 'path';
4-
import * as utils from './utils';
5-
import { getModuleDeclarations, generateModuleDeclaration } from './module-declaration';
6-
import { remapOptionals } from './remap-optionals';
7-
import { generatePrimaryInterfaces } from './primary-interfaces';
1+
import fs from 'node:fs';
2+
import path from 'node:path';
3+
84
import { ParsedDocumentationResult } from '@electron/docs-parser';
9-
import { DynamicParamInterfaces } from './dynamic-param-interfaces';
5+
import _ from 'lodash';
6+
7+
import * as utils from './utils.js';
8+
import { getModuleDeclarations, generateModuleDeclaration } from './module-declaration.js';
9+
import { remapOptionals } from './remap-optionals.js';
10+
import { generatePrimaryInterfaces } from './primary-interfaces.js';
11+
import { DynamicParamInterfaces } from './dynamic-param-interfaces.js';
1012

1113
// takes the predefined header and footer and wraps them around the generated files
1214
const wrapWithHeaderAndFooter = (outputLines: string[], electronVersion: string) => {
1315
const newOutputLines: string[] = [];
1416
utils.extendArray(
1517
newOutputLines,
1618
fs
17-
.readFileSync(path.resolve(__dirname, '../base/base_header.ts'), 'utf8')
19+
.readFileSync(path.resolve(import.meta.dirname, '../base/base_header.ts'), 'utf8')
1820
.replace('<<VERSION>>', electronVersion)
1921
.split(/\r?\n/),
2022
);
@@ -23,18 +25,18 @@ const wrapWithHeaderAndFooter = (outputLines: string[], electronVersion: string)
2325
utils.extendArray(
2426
newOutputLines,
2527
fs
26-
.readFileSync(path.resolve(__dirname, '../base/base_inner.ts'), 'utf8')
28+
.readFileSync(path.resolve(import.meta.dirname, '../base/base_inner.ts'), 'utf8')
2729
.replace('<<VERSION>>', electronVersion)
2830
.split(/\r?\n/),
2931
);
3032

31-
outputLines.slice(0).forEach(l => newOutputLines.push(`${_.trimEnd(` ${l}`)}`));
33+
outputLines.slice(0).forEach((l) => newOutputLines.push(`${_.trimEnd(` ${l}`)}`));
3234
utils.extendArray(newOutputLines, ['}', '']);
3335

3436
utils.extendArray(
3537
newOutputLines,
3638
fs
37-
.readFileSync(path.resolve(__dirname, '../base/base_footer.ts'), 'utf8')
39+
.readFileSync(path.resolve(import.meta.dirname, '../base/base_footer.ts'), 'utf8')
3840
.replace('<<VERSION>>', electronVersion)
3941
.split(/\r?\n/),
4042
);
@@ -106,7 +108,7 @@ export async function generateDefinitions({ electronApi: API }: GenerateOptions)
106108
// fetch everything that's been made and pop it into the actual API
107109
Object.keys(getModuleDeclarations())
108110
.sort((m1, m2) => m1.localeCompare(m2))
109-
.forEach(moduleKey => {
111+
.forEach((moduleKey) => {
110112
if (moduleKey === 'Process') return;
111113
const moduleAPI = getModuleDeclarations()[moduleKey];
112114
moduleAPI.push('}');

0 commit comments

Comments
 (0)