Skip to content

Commit

Permalink
fix: infer EventEmitter extensions from API (#259)
Browse files Browse the repository at this point in the history
* fix: infer EventEmitter extensions from API

* chore: update tests
  • Loading branch information
MarshallOfSound authored Mar 19, 2024
1 parent a54887c commit 478d24b
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 40 deletions.
31 changes: 21 additions & 10 deletions src/module-declaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,11 @@ export const generateModuleDeclaration = (
) => {
const moduleAPI = modules[_.upperFirst(module.name)] || [];
const newModule = !modules[_.upperFirst(module.name)];
const isStaticVersion =
module.type === 'Module' &&
API.some(
(tModule, tIndex) =>
index !== tIndex && tModule.name.toLowerCase() === module.name.toLowerCase(),
);
const instanceModuleForStaticVersion = API.find(
(tModule, tIndex) =>
index !== tIndex && tModule.name.toLowerCase() === module.name.toLowerCase(),
);
const isStaticVersion = module.type === 'Module' && !!instanceModuleForStaticVersion;
const isClass = module.type === 'Class' || isStaticVersion;
const parentModules: ParsedDocumentationResult = [];
let parentModule:
Expand All @@ -53,11 +52,23 @@ export const generateModuleDeclaration = (
// Interface Declaration
if (newModule) {
if (module.type !== 'Structure') {
if (utils.isEmitter(module)) {
let extendsInfo = '';
if (module.extends) {
extendsInfo = ` extends ${module.extends}`;
} else if (
utils.isEmitter(module) ||
(isStaticVersion &&
instanceModuleForStaticVersion &&
utils.isEmitter(instanceModuleForStaticVersion))
) {
extendsInfo = ` extends ${isClass ? 'NodeEventEmitter' : 'NodeJS.EventEmitter'}`;
}
if (module.name.toLowerCase() === 'session' && isStaticVersion) {
console.log({ isStaticVersion, instanceModuleForStaticVersion, extendsInfo });
}
if (extendsInfo) {
moduleAPI.push(
`${isClass ? 'class' : 'interface'} ${_.upperFirst(
module.name,
)} extends ${module.extends || (isClass ? 'NodeEventEmitter' : 'NodeJS.EventEmitter')} {`,
`${isClass ? 'class' : 'interface'} ${_.upperFirst(module.name)}${extendsInfo} {`,
);
moduleAPI.push('', `// Docs: ${module.websiteUrl}`, '');
} else {
Expand Down
53 changes: 25 additions & 28 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
DocumentationBlock,
DetailedFunctionType,
DocumentationTag,
ParsedDocumentationResult,
} from '@electron/docs-parser';
import _ from 'lodash';
import d from 'debug';
Expand Down Expand Up @@ -257,34 +258,30 @@ export const paramify = (paramName: string) => {
}
return paramName;
};
// TODO: Infer through electron-docs-linter/parser
export const isEmitter = (module: Pick<ModuleDocumentationContainer, 'name'>) => {
const nonEventEmitters = [
'menuitem',
'nativeimage',
'shell',
'browserview',
'webrequest',
'crashreporter',
'dock',
'commandline',
'browserwindowproxy',
'clipboard',
'contenttracing',
'desktopcapturer',
'dialog',
'globalshortcut',
'powersaveblocker',
'touchbar',
'touchbarbutton',
'net',
'netlog',
'protocol',
'contextbridge',
'webframe',
'messagechannelmain',
];
return !nonEventEmitters.includes(module.name.toLowerCase());
export const isEmitter = (doc: ParsedDocumentationResult[0]) => {
// Is a module, has events, is an eventemitter
if (doc.type === 'Module' && doc.events.length) {
return true;
}

// Is a class, has instance events, is an eventemitter
if (doc.type === 'Class' && doc.instanceEvents.length) {
return true;
}

// Implements the on and removeListener methods normally means
// it's an EventEmitter wrapper like ipcMain or ipcRenderer
const relevantMethods =
doc.type === 'Class' ? doc.instanceMethods : doc.type === 'Module' ? doc.methods : [];
if (
relevantMethods.find(m => m.name === 'on') &&
relevantMethods.find(m => m.name === 'removeListener')
) {
return true;
}

// Structure and Elements are not eventemitters, so bail here
return false;
};
export const isPrimitive = (type: string) => {
const primitives = ['boolean', 'number', 'any', 'string', 'void', 'unknown'];
Expand Down
11 changes: 9 additions & 2 deletions test/utils_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,18 @@ describe('utils', () => {

describe('isEmitter', () => {
it('should return true on most modules', () => {
expect(utils.isEmitter({ name: 'app' })).to.eq(true);
expect(utils.isEmitter({ name: 'app', type: 'Module', events: [1] })).to.eq(true);
});

it('should return false for specific non-emitter modules', () => {
expect(utils.isEmitter({ name: 'menuitem' })).to.eq(false);
expect(
utils.isEmitter({
name: 'menuitem',
type: 'Class',
instanceEvents: [],
instanceMethods: [],
}),
).to.eq(false);
});
});

Expand Down

0 comments on commit 478d24b

Please sign in to comment.