Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: convert to ESM + update all dependencies #277

Merged
merged 4 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 2 additions & 13 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@ workflows:
jobs:
- node/test:
name: test-<< matrix.executor >>-<< matrix.node-version >>
pre-steps:
- when:
condition:
and:
- equal: [ node/macos, << matrix.executor >> ]
- equal: [ '14.16', << matrix.node-version >> ]
steps:
- node/install-rosetta
test-steps:
- run: yarn prettier:check
- run: yarn test
Expand All @@ -30,11 +22,8 @@ workflows:
- node/macos
- node/windows
node-version:
- '20.10'
- '18.18'
- '16.20'
# Stay below 14.17.0 or nvm tries to download arm64 artifacts which don't exist
- '14.16'
- '22.9'
- '20.11'
- cfa/release:
requires:
- test
Expand Down
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
3 changes: 0 additions & 3 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn lint-staged
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ The module exports a function that parses a given API JSON object and returns
an array of lines to create the definition file

```js
const { generateDefinitions } = require('@electron/typescript-definitions')
import { generateDefinitions } from '@electron/typescript-definitions'

const apiPath = './vendor/electron/docs/api.json'

const definitionLines = generateDefinitions({ electronApi: require(apiPath) })
const definitionLines = generateDefinitions({ electronApi: loadJSON(apiPath) })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the loadJSON function just a placeholder? Should we made this code copy/pasteable?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The impl of loadJSON would be as much code as the rest of this doc, so, left as exercise to the reader

// definitionLines will be an strin representation of the definition file
```

Expand Down
13 changes: 13 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import path from 'node:path';
import { createDefaultEsmPreset } from 'ts-jest';

/** @type {import('ts-jest').JestConfigWithTsJest} **/
export default {
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
testPathIgnorePatterns: ['node_modules', path.resolve(import.meta.dirname, 'dist')],
...createDefaultEsmPreset({
tsconfig: 'tsconfig.json',
})
};
50 changes: 24 additions & 26 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,44 @@
"electron-typescript-definitions": "dist/bin.js"
},
"main": "dist/index.js",
"type": "module",
"engines": {
"node": ">=14.0.0"
"node": ">=20.9.0"
},
"scripts": {
"build": "tsc",
"prepare": "husky install",
"prepare": "husky",
"prepublishOnly": "yarn build",
"prettier:check": "prettier --list-different \"src/**/*.{ts,tsx}\"",
"prettier:write": "prettier --write \"src/**/*.{ts,tsx}\"",
"test": "yarn build && mocha"
"prettier:check": "prettier --list-different \"{src,test}/**/*.ts\"",
"prettier:write": "prettier --write \"{src,test}/**/*.ts\"",
"pretest": "tsc",
"test": "cross-env NODE_OPTIONS=\"--experimental-vm-modules\" jest"
},
"author": {
"name": "Samuel Attard",
"homepage": "https://www.samuelattard.com"
},
"license": "MIT",
"devDependencies": {
"@electron/docs-parser": "^1.2.0",
"@types/debug": "^4.1.4",
"@types/fs-extra": "^5.0.5",
"@types/lodash": "^4.14.123",
"@types/minimist": "^1.2.0",
"chai": "^4.2.0",
"husky": "^8.0.2",
"lint-staged": "^13.0.4",
"mocha": "^10.1.0",
"prettier": "^1.17.0",
"typescript": "^3.4.5"
"@electron/docs-parser": "^2.0.0",
"@types/debug": "^4.1.12",
"@types/jest": "^29.5.13",
"@types/lodash": "^4.17.7",
"cross-env": "^7.0.3",
"husky": "^9.1.6",
"jest": "^30.0.0-alpha.6",
"lint-staged": "^15.2.10",
"prettier": "^3.3.3",
"ts-jest": "^29.2.5",
"typescript": "^5.6.2"
},
"dependencies": {
"@types/node": "^11.13.7",
"chalk": "^2.4.2",
"colors": "^1.1.2",
"debug": "^4.1.1",
"fs-extra": "^7.0.1",
"@types/node": "^20.11.25",
"chalk": "^5.3.0",
"debug": "^4.3.7",
"lodash": "^4.17.11",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"ora": "^3.4.0",
"pretty-ms": "^5.0.0"
"ora": "^8.1.0",
"pretty-ms": "^9.1.0"
},
"repository": {
"type": "git",
Expand All @@ -57,6 +55,6 @@
"base"
],
"lint-staged": {
"*.{js,ts}": "prettier --write"
"*.ts": "prettier --write"
}
}
41 changes: 28 additions & 13 deletions src/bin.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
#!/usr/bin/env node

import * as fs from 'fs-extra';
import minimist from 'minimist';
import ora from 'ora';
import * as path from 'path';
import pretty from 'pretty-ms';
import fs from 'node:fs';
import path from 'node:path';
import { parseArgs } from 'node:util';

import chalk from 'chalk';
import { generateDefinitions } from '.';
import ora from 'ora';
import pretty from 'pretty-ms';

const args = minimist(process.argv);
import { generateDefinitions } from './index.js';

const { api, outDir, help } = args;
const {
values: { api, outDir, help },
} = parseArgs({
options: {
api: {
type: 'string',
},
outDir: {
type: 'string',
default: process.cwd(),
},
help: {
type: 'boolean',
default: false,
},
},
});

if (help) {
console.info(
Expand All @@ -30,7 +45,7 @@ if (typeof api !== 'string') {
}

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

fs.mkdirp(resolvedOutDir).then(() =>
fs.promises.mkdir(resolvedOutDir, { recursive: true }).then(async () =>
generateDefinitions({
electronApi: require(resolvedApi),
electronApi: JSON.parse(await fs.promises.readFile(resolvedApi, 'utf-8')),
})
.then(data => fs.writeFile(resolvedFilePath, data))
.then((data) => fs.promises.writeFile(resolvedFilePath, data))
.then(() =>
runner.succeed(
`${chalk.green('Electron Typescript Definitions generated in')} ${chalk.yellow(
`"${resolvedFilePath}"`,
)} took ${chalk.cyan(pretty(Date.now() - start))}`,
),
)
.catch(err => {
.catch((err) => {
console.error(err);
process.exit(1);
}),
Expand Down
24 changes: 14 additions & 10 deletions src/dynamic-param-interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import _ from 'lodash';
import * as utils from './utils';
import d from 'debug';
import {
EventParameterDocumentation,
DetailedObjectType,
Expand All @@ -9,6 +6,11 @@ import {
DocumentationTag,
} from '@electron/docs-parser';
import chalk from 'chalk';
import d from 'debug';
import _ from 'lodash';

import * as utils from './utils.js';

const debug = d('dynamic-param');

type ParamInterface = EventParameterDocumentation &
Expand Down Expand Up @@ -37,7 +39,7 @@ const polite = (s: string): string => {
const ignoreDescriptions = <T extends EventParameterDocumentation>(
props: T[],
): Pick<T, Exclude<keyof T, 'description'>>[] =>
_.map(props, p => {
_.map(props, (p) => {
const { description, ...toReturn } = p;

return toReturn;
Expand All @@ -48,7 +50,7 @@ const unsetDescriptions = (o: any): any => {
if (noDescriptionCache.has(o)) return noDescriptionCache.get(o);
if (typeof o !== 'object' || !o) return o;
const val = Array.isArray(o)
? o.map(item => unsetDescriptions(item))
? o.map((item) => unsetDescriptions(item))
: Object.keys(o).reduce((accum: any, key: string) => {
if (key === 'description') return accum;
accum[key] = unsetDescriptions(o[key]);
Expand Down Expand Up @@ -149,7 +151,7 @@ const flushParamInterfaces = (
.sort((a, b) =>
paramInterfacesToDeclare[a].tName!.localeCompare(paramInterfacesToDeclare[b].tName!),
)
.forEach(paramKey => {
.forEach((paramKey) => {
if (paramKey === 'Event') {
throw 'Unexpected dynamic Event type, should be routed through the Event handler';
}
Expand Down Expand Up @@ -181,7 +183,7 @@ const flushParamInterfaces = (
);

param.properties = param.properties || [];
param.properties.forEach(paramProperty => {
param.properties.forEach((paramProperty) => {
if (paramProperty.description) {
utils.extendArray(
paramAPI,
Expand All @@ -192,7 +194,7 @@ const flushParamInterfaces = (
if (!Array.isArray(paramProperty.type) && paramProperty.type.toLowerCase() === 'object') {
let argType =
(paramProperty as any).__type || _.upperFirst(_.camelCase(paramProperty.name));
if (API.some(a => a.name === argType)) {
if (API.some((a) => a.name === argType)) {
paramProperty.type = argType;
debug(
chalk.red(
Expand All @@ -210,7 +212,7 @@ const flushParamInterfaces = (
}

if (Array.isArray(paramProperty.type)) {
paramProperty.type = paramProperty.type.map(paramPropertyType => {
paramProperty.type = paramProperty.type.map((paramPropertyType) => {
const functionProp = paramPropertyType as DetailedFunctionType;
if (paramPropertyType.type === 'Function' && functionProp.parameters) {
return {
Expand All @@ -229,7 +231,7 @@ const flushParamInterfaces = (
) {
let argType =
(paramProperty as any).__type || _.upperFirst(_.camelCase(paramProperty.name));
if (API.some(a => a.name === argType)) {
if (API.some((a) => a.name === argType)) {
paramPropertyType.type = argType;
debug(
chalk.red(
Expand Down Expand Up @@ -293,3 +295,5 @@ export class DynamicParamInterfaces {
static createParamInterface = createParamInterface;
static flushParamInterfaces = flushParamInterfaces;
}

utils.setParamInterfaces(DynamicParamInterfaces);
28 changes: 15 additions & 13 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import _ from 'lodash';
import * as fs from 'fs-extra';
import * as path from 'path';
import * as utils from './utils';
import { getModuleDeclarations, generateModuleDeclaration } from './module-declaration';
import { remapOptionals } from './remap-optionals';
import { generatePrimaryInterfaces } from './primary-interfaces';
import fs from 'node:fs';
import path from 'node:path';

import { ParsedDocumentationResult } from '@electron/docs-parser';
import { DynamicParamInterfaces } from './dynamic-param-interfaces';
import _ from 'lodash';

import * as utils from './utils.js';
import { getModuleDeclarations, generateModuleDeclaration } from './module-declaration.js';
import { remapOptionals } from './remap-optionals.js';
import { generatePrimaryInterfaces } from './primary-interfaces.js';
import { DynamicParamInterfaces } from './dynamic-param-interfaces.js';

// takes the predefined header and footer and wraps them around the generated files
const wrapWithHeaderAndFooter = (outputLines: string[], electronVersion: string) => {
const newOutputLines: string[] = [];
utils.extendArray(
newOutputLines,
fs
.readFileSync(path.resolve(__dirname, '../base/base_header.ts'), 'utf8')
.readFileSync(path.resolve(import.meta.dirname, '../base/base_header.ts'), 'utf8')
.replace('<<VERSION>>', electronVersion)
.split(/\r?\n/),
);
Expand All @@ -23,18 +25,18 @@ const wrapWithHeaderAndFooter = (outputLines: string[], electronVersion: string)
utils.extendArray(
newOutputLines,
fs
.readFileSync(path.resolve(__dirname, '../base/base_inner.ts'), 'utf8')
.readFileSync(path.resolve(import.meta.dirname, '../base/base_inner.ts'), 'utf8')
.replace('<<VERSION>>', electronVersion)
.split(/\r?\n/),
);

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

utils.extendArray(
newOutputLines,
fs
.readFileSync(path.resolve(__dirname, '../base/base_footer.ts'), 'utf8')
.readFileSync(path.resolve(import.meta.dirname, '../base/base_footer.ts'), 'utf8')
.replace('<<VERSION>>', electronVersion)
.split(/\r?\n/),
);
Expand Down Expand Up @@ -106,7 +108,7 @@ export async function generateDefinitions({ electronApi: API }: GenerateOptions)
// fetch everything that's been made and pop it into the actual API
Object.keys(getModuleDeclarations())
.sort((m1, m2) => m1.localeCompare(m2))
.forEach(moduleKey => {
.forEach((moduleKey) => {
if (moduleKey === 'Process') return;
const moduleAPI = getModuleDeclarations()[moduleKey];
moduleAPI.push('}');
Expand Down
Loading