Skip to content

Commit 64c58c7

Browse files
fix: ensure that identical types in set/get are deduper from ctor (electron#243)
1 parent 1933412 commit 64c58c7

File tree

2 files changed

+56
-11
lines changed

2 files changed

+56
-11
lines changed

src/dynamic-param-interfaces.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,21 @@ const ignoreDescriptions = <T extends EventParameterDocumentation>(
4343
return toReturn;
4444
}).sort((a, b) => a.name.localeCompare(b.name));
4545

46+
const noDescriptionCache = new WeakMap();
47+
const unsetDescriptions = (o: any): any => {
48+
if (noDescriptionCache.has(o)) return noDescriptionCache.get(o);
49+
if (typeof o !== 'object' || !o) return o;
50+
const val = Array.isArray(o)
51+
? o.map(item => unsetDescriptions(item))
52+
: Object.keys(o).reduce((accum: any, key: string) => {
53+
if (key === 'description') return accum;
54+
accum[key] = unsetDescriptions(o[key]);
55+
return accum;
56+
}, {});
57+
noDescriptionCache.set(o, val);
58+
return val;
59+
};
60+
4661
// Given a parameter create a new interface and return it's name + array modifier
4762
// IName is the proposed interface name prefix
4863
// backupIName is a slightly longer IName in case IName is already taken
@@ -53,13 +68,31 @@ const createParamInterface = (
5368
finalBackupIName = '',
5469
): string => {
5570
const maybeArray = (type: string) => (param.collection ? `Array<${type}>` : type);
71+
const potentialExistingArgType = polite(IName);
72+
const potentialExistingArgName = _.lowerFirst(polite(IName));
5673
let argType = polite(IName) + _.upperFirst(_.camelCase(param.name));
5774
let argName = param.name;
5875
// TODO: Note. It is still possible for even backupIName to be already used
5976
let usingExistingParamInterface = false;
6077
_.forIn(paramInterfacesToDeclare, (value, key) => {
61-
const test = _.assign({}, param, { name: argName, tName: argType });
62-
if (_.isEqual(test, value)) {
78+
const test = unsetDescriptions(
79+
_.assign({}, param, {
80+
name: argName,
81+
tName: argType,
82+
required: value.required,
83+
additionalTags: (param as any).additionalTags || [],
84+
}),
85+
);
86+
const potentialTest = unsetDescriptions(
87+
_.assign({}, param, {
88+
name: potentialExistingArgName,
89+
tName: potentialExistingArgType,
90+
required: value.required,
91+
additionalTags: (param as any).additionalTags || [],
92+
}),
93+
);
94+
const unsetValue = unsetDescriptions(value);
95+
if (_.isEqual(test, unsetValue) || _.isEqual(potentialTest, unsetValue)) {
6396
usingExistingParamInterface = true;
6497
debug(
6598
chalk.cyan(

src/index.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,22 +86,34 @@ export async function generateDefinitions({ electronApi: API }: GenerateOptions)
8686

8787
// generate module declaration for every class, module, structure, element, etc
8888
const declaredStructs: string[] = [];
89-
API.sort((m1, m2) => m1.name.localeCompare(m2.name)).forEach((module, index) => {
89+
API.sort((m1, m2) => {
90+
// Ensure constructor options are declared first so as to ensure that
91+
// setters and getters for constructor options have de-duped types
92+
if (m1.name.endsWith('ConstructorOptions') && !m2.name.endsWith('ConstructorOptions')) {
93+
return -1;
94+
}
95+
if (!m1.name.endsWith('ConstructorOptions') && m2.name.endsWith('ConstructorOptions')) {
96+
return 1;
97+
}
98+
return m1.name.localeCompare(m2.name);
99+
}).forEach((module, index) => {
90100
if (module.type === 'Structure') {
91101
declaredStructs.push(module.name);
92102
}
93103
generateModuleDeclaration(module, index, API);
94104
});
95105

96106
// fetch everything that's been made and pop it into the actual API
97-
Object.keys(getModuleDeclarations()).forEach(moduleKey => {
98-
if (moduleKey === 'Process') return;
99-
const moduleAPI = getModuleDeclarations()[moduleKey];
100-
moduleAPI.push('}');
101-
addToOutput(
102-
moduleAPI.map((l, index) => (index === 0 || index === moduleAPI.length - 1 ? l : ` ${l}`)),
103-
);
104-
});
107+
Object.keys(getModuleDeclarations())
108+
.sort((m1, m2) => m1.localeCompare(m2))
109+
.forEach(moduleKey => {
110+
if (moduleKey === 'Process') return;
111+
const moduleAPI = getModuleDeclarations()[moduleKey];
112+
moduleAPI.push('}');
113+
addToOutput(
114+
moduleAPI.map((l, index) => (index === 0 || index === moduleAPI.length - 1 ? l : ` ${l}`)),
115+
);
116+
});
105117

106118
const keys = DynamicParamInterfaces.flushParamInterfaces(API, addToOutput);
107119
generatePrimaryInterfaces(API, [...keys, ...declaredStructs], addToOutput);

0 commit comments

Comments
 (0)