Skip to content

Commit 43bc6bc

Browse files
refactor: convert to ESM + update all dependencies (#120)
1 parent 2c5b009 commit 43bc6bc

14 files changed

+1630
-882
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 build
@@ -31,11 +23,8 @@ workflows:
3123
- node/macos
3224
- node/windows
3325
node-version:
34-
- '20.9'
35-
- '18.17'
36-
- '16.20'
37-
# Stay below 14.17.0 or nvm tries to download arm64 artifacts which don't exist
38-
- '14.16'
26+
- '22.9'
27+
- '20.11'
3928
- cfa/release:
4029
requires:
4130
- test

.gitattributes

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

.husky/pre-commit

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
yarn lint-staged

jest.config.js

+12-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
const path = require('path');
1+
import path from 'node:path';
2+
import { createDefaultEsmPreset } from 'ts-jest';
23

3-
module.exports = {
4-
preset: 'ts-jest',
5-
testEnvironment: 'node',
6-
testPathIgnorePatterns: ['node_modules', path.resolve(__dirname, 'dist')],
7-
setupFiles: ['<rootDir>/jest.setup.js'],
8-
};
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-19
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,19 @@
33
"version": "0.0.0-development",
44
"description": "Parse Electron documentation into a machine readable JSON file",
55
"main": "dist/index.js",
6+
"type": "module",
67
"author": "Samuel Attard",
78
"license": "MIT",
89
"engines": {
9-
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
10+
"node": "^20.11.0 || >= 21.2.0"
1011
},
1112
"scripts": {
1213
"build": "tsc",
1314
"prepublishOnly": "npx yarn build",
1415
"prettier:check": "prettier --list-different \"src/**/*.{ts,tsx}\"",
1516
"prettier:write": "prettier --write \"src/**/*.{ts,tsx}\"",
16-
"test": "jest"
17+
"test": "cross-env NODE_OPTIONS=\"--experimental-vm-modules\" jest",
18+
"prepare": "husky"
1719
},
1820
"bin": {
1921
"electron-docs-linter": "./dist/bin.js",
@@ -24,27 +26,30 @@
2426
"!dist/__tests__"
2527
],
2628
"devDependencies": {
27-
"@types/chai": "^4.2.5",
28-
"@types/fs-extra": "^8.0.1",
29-
"@types/jest": "^24.0.23",
30-
"@types/lodash.camelcase": "^4.3.6",
31-
"@types/minimist": "^1.2.0",
29+
"@types/chai": "^4.3.19",
30+
"@types/jest": "^29.5.13",
31+
"@types/lodash.camelcase": "^4.3.9",
32+
"@types/node": "^22.5.5",
3233
"@types/pretty-ms": "^5.0.1",
33-
"jest": "^29.3.1",
34-
"prettier": "^1.19.1",
35-
"ts-jest": "^29.0.3",
36-
"typescript": "^4.9.3"
34+
"cross-env": "^7.0.3",
35+
"husky": "^9.1.6",
36+
"jest": "^30.0.0-alpha.6",
37+
"lint-staged": "^15.2.10",
38+
"prettier": "^3.3.3",
39+
"ts-jest": "^29.2.5",
40+
"typescript": "^5.6.2"
3741
},
3842
"dependencies": {
39-
"@types/markdown-it": "^12.0.0",
40-
"chai": "^4.2.0",
41-
"chalk": "^3.0.0",
42-
"fs-extra": "^8.1.0",
43+
"@types/markdown-it": "^14.1.2",
44+
"chai": "^5.1.1",
45+
"chalk": "^5.3.0",
4346
"lodash.camelcase": "^4.3.0",
44-
"markdown-it": "^12.0.0",
45-
"minimist": "^1.2.0",
46-
"ora": "^4.0.3",
47-
"pretty-ms": "^5.1.0"
47+
"markdown-it": "^14.1.0",
48+
"ora": "^8.1.0",
49+
"pretty-ms": "^9.1.0"
50+
},
51+
"lint-staged": {
52+
"*.ts": "prettier --write"
4853
},
4954
"repository": {
5055
"type": "git",

src/DocsParser.ts

+13-13
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { expect } from 'chai';
2-
import * as fs from 'fs-extra';
2+
import fs from 'node:fs';
33
import MarkdownIt from 'markdown-it';
4-
import Token from 'markdown-it/lib/token';
4+
import { Token } from 'markdown-it';
55
import * as path from 'path';
6-
import toCamelCase = require('lodash.camelcase');
6+
import toCamelCase from 'lodash.camelcase';
77

88
import {
99
ParsedDocumentation,
@@ -13,7 +13,7 @@ import {
1313
ModuleDocumentationContainer,
1414
ClassDocumentationContainer,
1515
ElementDocumentationContainer,
16-
} from './ParsedDocumentation';
16+
} from './ParsedDocumentation.js';
1717
import {
1818
findNextList,
1919
convertListToTypedKeys,
@@ -28,15 +28,15 @@ import {
2828
findContentAfterHeadingClose,
2929
HeadingContent,
3030
getContentBeforeFirstHeadingMatching,
31-
} from './markdown-helpers';
32-
import { WEBSITE_BASE_DOCS_URL, REPO_BASE_DOCS_URL } from './constants';
33-
import { extendError } from './helpers';
31+
} from './markdown-helpers.js';
32+
import { WEBSITE_BASE_DOCS_URL, REPO_BASE_DOCS_URL } from './constants.js';
33+
import { extendError } from './helpers.js';
3434
import {
3535
parseMethodBlocks,
3636
_headingToMethodBlock,
3737
parsePropertyBlocks,
3838
parseEventBlocks,
39-
} from './block-parsers';
39+
} from './block-parsers.js';
4040

4141
export class DocsParser {
4242
constructor(
@@ -108,7 +108,7 @@ export class DocsParser {
108108
groups = getContentBeforeConstructor(tokens);
109109
} else {
110110
// FIXME: Make it so that we don't need this magic FIXME for the electron breaking-changes document
111-
groups = getContentBeforeFirstHeadingMatching(tokens, heading =>
111+
groups = getContentBeforeFirstHeadingMatching(tokens, (heading) =>
112112
['Events', 'Methods', 'Properties', '`FIXME` comments'].includes(heading.trim()),
113113
);
114114
}
@@ -156,7 +156,7 @@ export class DocsParser {
156156
| ClassDocumentationContainer
157157
| ElementDocumentationContainer
158158
)[] = [];
159-
const contents = await fs.readFile(filePath, 'utf8');
159+
const contents = await fs.promises.readFile(filePath, 'utf8');
160160
const md = new MarkdownIt({ html: true });
161161

162162
const allTokens = md.parse(contents, {});
@@ -182,7 +182,7 @@ export class DocsParser {
182182
if (isClass) {
183183
// Instance name will be taken either from an example in a method declaration or the camel
184184
// case version of the class name
185-
const levelFourHeader = headingsAndContent(tokens).find(h => h.level === 4);
185+
const levelFourHeader = headingsAndContent(tokens).find((h) => h.level === 4);
186186
const instanceName = levelFourHeader
187187
? (levelFourHeader.heading.split('`')[1] || '').split('.')[0] ||
188188
toCamelCase(container.name)
@@ -262,7 +262,7 @@ export class DocsParser {
262262
}
263263

264264
private async parseStructure(filePath: string): Promise<StructureDocumentationContainer> {
265-
const contents = await fs.readFile(filePath, 'utf8');
265+
const contents = await fs.promises.readFile(filePath, 'utf8');
266266
const md = new MarkdownIt({ html: true });
267267

268268
const tokens = md.parse(contents, {});
@@ -279,7 +279,7 @@ export class DocsParser {
279279
return {
280280
type: 'Structure',
281281
...baseInfos[0].container,
282-
properties: consumeTypedKeysList(convertListToTypedKeys(list!)).map(typedKey => ({
282+
properties: consumeTypedKeysList(convertListToTypedKeys(list!)).map((typedKey) => ({
283283
name: typedKey.key,
284284
description: typedKey.description,
285285
required: typedKey.required,

src/ParsedDocumentation.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ export class ParsedDocumentation {
172172
}
173173

174174
public getJSON(): ParsedDocumentationResult {
175-
return this.repr.filter(container => {
175+
return this.repr.filter((container) => {
176176
if (container.type !== 'Module') return true;
177177

178178
return container.events.length + container.methods.length + container.properties.length > 0;

src/__tests__/markdown-helpers.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ describe('markdown-helpers', () => {
5757
});
5858

5959
describe('snapshots', () => {
60-
const fixtureDir = path.resolve(__dirname, 'fixtures');
60+
const fixtureDir = path.resolve(import.meta.dirname, 'fixtures');
6161
for (const markdownFixture of fs.readdirSync(fixtureDir)) {
6262
if (!markdownFixture.endsWith('.md')) continue;
6363

src/bin.ts

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

3-
import * as fs from 'fs-extra';
4-
import minimist from 'minimist';
3+
import chalk from 'chalk';
4+
import fs from 'node:fs';
5+
import { parseArgs } from 'node:util';
56
import ora from 'ora';
67
import * as path from 'path';
78
import pretty from 'pretty-ms';
89

9-
import { parseDocs } from '.';
10-
import chalk from 'chalk';
10+
import { parseDocs } from './index.js';
1111

12-
const args = minimist(process.argv, {
13-
default: {
14-
packageMode: 'single',
12+
const {
13+
values: { outDir, dir, useReadme, moduleVersion, help, packageMode },
14+
} = parseArgs({
15+
options: {
16+
packageMode: {
17+
type: 'string',
18+
default: 'single',
19+
},
20+
dir: {
21+
type: 'string',
22+
},
23+
outDir: {
24+
type: 'string',
25+
},
26+
useReadme: {
27+
type: 'boolean',
28+
},
29+
moduleVersion: {
30+
type: 'string',
31+
},
32+
help: {
33+
type: 'boolean',
34+
default: false,
35+
},
1536
},
1637
});
1738

18-
const { dir, outDir, useReadme, packageMode, moduleVersion, help } = args;
19-
if (!['single', 'multi'].includes(packageMode)) {
39+
let safePackageMode = packageMode as 'single' | 'multi' | string;
40+
41+
if (safePackageMode !== 'single' && safePackageMode !== 'multi') {
2042
console.error(chalk.red('packageMode must be one of "single" and "multi"'));
2143
process.exit(1);
2244
}
@@ -41,7 +63,7 @@ if (typeof moduleVersion !== 'string') {
4163
}
4264

4365
const resolvedDir = path.isAbsolute(dir) ? dir : path.resolve(process.cwd(), dir);
44-
if (!fs.pathExistsSync(resolvedDir)) {
66+
if (!fs.existsSync(resolvedDir)) {
4567
runner.fail(`${chalk.red('Resolved directory does not exist:')} ${chalk.cyan(resolvedDir)}`);
4668
process.exit(1);
4769
}
@@ -57,17 +79,18 @@ runner.text = chalk.cyan(`Generating API in directory: ${chalk.yellow(`"${resolv
5779

5880
const start = Date.now();
5981

60-
fs.mkdirp(resolvedOutDir).then(() =>
82+
fs.promises.mkdir(resolvedOutDir, { recursive: true }).then(() =>
6183
parseDocs({
6284
useReadme: useReadme ? true : false,
6385
baseDirectory: resolvedDir,
6486
moduleVersion,
65-
packageMode,
87+
packageMode: safePackageMode,
6688
})
67-
.then(data =>
68-
fs.writeJson(path.resolve(resolvedOutDir, './electron-api.json'), data, {
69-
spaces: 2,
70-
}),
89+
.then((data) =>
90+
fs.promises.writeFile(
91+
path.resolve(resolvedOutDir, './electron-api.json'),
92+
JSON.stringify(data, null, 2),
93+
),
7194
)
7295
.then(() =>
7396
runner.succeed(
@@ -76,7 +99,7 @@ fs.mkdirp(resolvedOutDir).then(() =>
7699
)} took ${chalk.cyan(pretty(Date.now() - start))}`,
77100
),
78101
)
79-
.catch(err => {
102+
.catch((err) => {
80103
runner.fail();
81104
console.error(err);
82105
process.exit(1);

src/block-parsers.ts

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect } from 'chai';
2-
import Token from 'markdown-it/lib/token';
2+
import { Token } from 'markdown-it';
33

44
import {
55
parseHeadingTags,
@@ -14,12 +14,12 @@ import {
1414
StripReturnTypeBehavior,
1515
consumeTypedKeysList,
1616
slugifyHeading,
17-
} from './markdown-helpers';
17+
} from './markdown-helpers.js';
1818
import {
1919
MethodDocumentationBlock,
2020
PropertyDocumentationBlock,
2121
EventDocumentationBlock,
22-
} from './ParsedDocumentation';
22+
} from './ParsedDocumentation.js';
2323

2424
type GuessedParam = {
2525
name: string;
@@ -110,7 +110,7 @@ export const _headingToMethodBlock = (
110110
null,
111111
`Method ${heading.heading} has at least one parameter but no parameter type list`,
112112
);
113-
parameters = consumeTypedKeysList(convertListToTypedKeys(list)).map(typedKey => ({
113+
parameters = consumeTypedKeysList(convertListToTypedKeys(list)).map((typedKey) => ({
114114
name: typedKey.key,
115115
description: typedKey.description,
116116
required: typedKey.required,
@@ -191,13 +191,11 @@ export const _headingToEventBlock = (heading: HeadingContent): EventDocumentatio
191191

192192
let parameters: EventDocumentationBlock['parameters'] = [];
193193
if (
194-
safelyJoinTokens(findContentAfterHeadingClose(heading.content))
195-
.trim()
196-
.startsWith('Returns:')
194+
safelyJoinTokens(findContentAfterHeadingClose(heading.content)).trim().startsWith('Returns:')
197195
) {
198196
const list = findNextList(heading.content);
199197
if (list) {
200-
parameters = consumeTypedKeysList(convertListToTypedKeys(list)).map(typedKey => ({
198+
parameters = consumeTypedKeysList(convertListToTypedKeys(list)).map((typedKey) => ({
201199
name: typedKey.key,
202200
description: typedKey.description,
203201
...typedKey.type,
@@ -219,7 +217,7 @@ export const _headingToEventBlock = (heading: HeadingContent): EventDocumentatio
219217
export const parseMethodBlocks = (tokens: Token[] | null): MethodDocumentationBlock[] => {
220218
if (!tokens) return [];
221219

222-
return headingsAndContent(tokens).map(heading => _headingToMethodBlock(heading)!);
220+
return headingsAndContent(tokens).map((heading) => _headingToMethodBlock(heading)!);
223221
};
224222

225223
export const parsePropertyBlocks = (tokens: Token[] | null): PropertyDocumentationBlock[] => {

0 commit comments

Comments
 (0)