Skip to content

Commit c2ed711

Browse files
committed
Fix a lot of stuff
Found after report of DefinitelyTyped/DefinitelyTyped#49323
1 parent bde734a commit c2ed711

File tree

4 files changed

+185
-48
lines changed

4 files changed

+185
-48
lines changed

src/converter.ts

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ const RESERVED = [
4444
'void',
4545
'while',
4646
'with',
47+
'Date'
48+
];
49+
50+
//
51+
const GLOBAL_TYPES = [
52+
'ImageData',
53+
'ArrayBuffer',
54+
'ImageData',
55+
'Element',
56+
'Uint8Array',
57+
'globalThis.Date',
58+
'Window'
4759
];
4860

4961
// Types that are considered "simple"
@@ -379,22 +391,32 @@ export default class Converter {
379391
// Okay, apparently typescript doesn't need that, as all the namepaces are combined by the compiler
380392
//out += 'browser.';
381393
} else if (!this.namespaces[this.namespace].types!.find((x) => x.id === ref)) {
382-
console.log(`Warning: Cannot find reference "${ref}", assuming the browser knows better.`);
383-
// Add a type X = any, so the type can be used, but won't be typechecked
384-
this.additionalTypes.push(`type ${ref} = any;`);
394+
if (!GLOBAL_TYPES.includes(ref)) {
395+
console.error(
396+
`Cannot find reference "${ref}", fix or add tot GLOBAL_TYPES if browser knows it.`
397+
);
398+
// Add a type X = any, so the type can be used, but won't be typechecked
399+
this.additionalTypes.push(`type ${ref} = any;`);
400+
}
385401
}
386402
return ref;
387403
}
388404

389405
convertType(type: TypeSchema, root = false): string {
390406
// Check if we've overridden it, likely for a type that can't be represented in json schema
407+
408+
if (type.converterAdditionalType) {
409+
this.additionalTypes.push(type.converterAdditionalType);
410+
if (type.converterTypeOverride) {
411+
return type.converterTypeOverride;
412+
}
413+
if (type.id) {
414+
return type.id;
415+
}
416+
}
391417
if (type.converterTypeOverride) {
392418
return type.converterTypeOverride;
393419
}
394-
if (type.converterAdditionalType && type.id) {
395-
this.additionalTypes.push(type.converterAdditionalType);
396-
return type.id;
397-
}
398420
let out = '';
399421
// Check type of type
400422
if (type.choices) {
@@ -513,19 +535,17 @@ export default class Converter {
513535
}
514536
} else if (type.isInstanceOf) {
515537
// It's an instance of another type
516-
if (type.additionalProperties && type.additionalProperties.type === 'any') {
517-
// The schemas write set additionalProperties.type = 'any' when typechecking can be anything
518-
// This usually means it's "window" included as part of DOM
519-
if (type.isInstanceOf.toLowerCase() === 'window') {
538+
// Check if it's a window
539+
if (type.isInstanceOf == 'global') {
540+
out += 'Window';
541+
} else {
542+
// Check if it's a browser type
543+
if (GLOBAL_TYPES.includes(type.isInstanceOf)) {
520544
out += type.isInstanceOf;
521545
} else {
522-
// Otherwise it's some object we don't know about, therefore just treat it as a random
523-
// object
524-
out += `object/*${type.isInstanceOf}*/`;
546+
// Other wise try to convert as ref
547+
out += this.convertRef(type.isInstanceOf);
525548
}
526-
} else {
527-
// If the schema does not do that, try converting as a reference
528-
out += this.convertRef(type.isInstanceOf);
529549
}
530550
} else if (type.additionalProperties) {
531551
// If it has additional, but not normal properties, try converting those properties as a type,
@@ -757,15 +777,19 @@ export default class Converter {
757777
if (callback) {
758778
// Remove callback from parameters as we're gonna handle it as a promise return
759779
func.parameters = func.parameters!.filter((x) => x !== callback);
760-
let parameters = this.convertParameters(callback.parameters, false, pascalCase(`${func.name}_return`));
780+
let parameters = this.convertParameters(
781+
callback.parameters,
782+
false,
783+
pascalCase(`${func.name}_return`)
784+
);
761785
if (parameters.length > 1) {
762786
// Since these files are originally chrome, some things are a bit weird
763787
// Callbacks (which is what chrome uses) have no issues with returning multiple values
764788
// but firefox uses promises, which AFAIK can't handle that
765789
// This doesn't seem to be a problem yet, as firefox hasn't actually implemented the methods in
766790
// question yet But since it's in the schemas, it's still a problem for us
767791
// TODO: Follow firefox developments in this area
768-
console.log(`Warning: Promises cannot return more than one value: ${func.name}.`);
792+
console.warn(`Promises cannot return more than one value: ${func.name}.`);
769793
// Just assume it's gonna be some kind of object that's returned from the promise
770794
// This seems like the most likely way the firefox team is going to make the promise return
771795
// multiple values
@@ -1034,14 +1058,13 @@ export default class Converter {
10341058
delete this.namespaces[name];
10351059
}
10361060

1061+
getIdOrName(type: TypeSchema) {
1062+
return type['id'] || type['name'] || type['$extend'] || type['$import'];
1063+
}
1064+
10371065
getIndex(namespace: string, section: string, id_or_name: string): number {
10381066
return (this.namespaces[namespace] as any)[section].findIndex((x: TypeSchema) => {
1039-
return (
1040-
x['id'] === id_or_name ||
1041-
x['name'] === id_or_name ||
1042-
x['$extend'] === id_or_name ||
1043-
x['$import'] === id_or_name
1044-
);
1067+
return this.getIdOrName(x) === id_or_name;
10451068
});
10461069
}
10471070

@@ -1052,7 +1075,12 @@ export default class Converter {
10521075
);
10531076
}
10541077

1055-
edit(namespace: string, section: string, id_or_name: string, edit: (x: any) => any) {
1078+
edit(
1079+
namespace: string,
1080+
section: string,
1081+
id_or_name: string,
1082+
edit: (type: TypeSchema) => TypeSchema
1083+
) {
10561084
console.log(`Editing ${namespace}.${section}.${id_or_name}`);
10571085
const index = this.getIndex(namespace, section, id_or_name);
10581086
const sectionObj = (this.namespaces[namespace] as any)[section];
@@ -1062,6 +1090,12 @@ export default class Converter {
10621090
sectionObj[index] = edit(sectionObj[index]);
10631091
}
10641092

1093+
add(namespace: string, section: string, value: TypeSchema) {
1094+
console.log(`Adding to ${namespace}.${section}.${this.getIdOrName(value)}`);
1095+
const sectionObj = (this.namespaces[namespace] as any)[section];
1096+
sectionObj.push(value);
1097+
}
1098+
10651099
edit_path(path: [string, string, string] | string[], edit: (x: any) => any) {
10661100
this.edit(path[0], path[1], path[2], edit);
10671101
}

src/index.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const HEADER = `// Type definitions for non-npm package WebExtension Development
2323
// Project: https://developer.mozilla.org/en-US/Add-ons/WebExtensions
2424
// Definitions by: Jasmin Bom <https://github.com/jsmnbom>
2525
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
26-
// TypeScript Version: 2.9
26+
// TypeScript Version: 3.4
2727
// Generated using script at github.com/jsmnbom/definitelytyped-firefox-webext-browser
2828
2929
interface WebExtEvent<TCallback extends (...args: any[]) => any> {
@@ -32,10 +32,6 @@ interface WebExtEvent<TCallback extends (...args: any[]) => any> {
3232
hasListener(cb: TCallback): boolean;
3333
}
3434
35-
interface Window {
36-
browser: typeof browser;
37-
}
38-
3935
`;
4036

4137
let converter = new Converter(argv['_'], HEADER, NAMESPACE_ALIASES);

src/overrides.ts

Lines changed: 123 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ export default function override(converter: Converter) {
44
// Remove test namespace since it's not exposed in api
55
converter.removeNamespace('test');
66

7+
// Fix extensionTypes.Date
8+
converter.edit('extensionTypes', 'types', 'Date', (Date) => {
9+
Date.choices![2].isInstanceOf = 'globalThis.Date'
10+
return Date;
11+
})
12+
713
// browser.runtime.getManifest should return WebExtensionManifest
814
converter.edit('runtime', 'functions', 'getManifest', (x) => {
915
x.returns = { $ref: 'manifest.WebExtensionManifest' };
@@ -12,8 +18,8 @@ export default function override(converter: Converter) {
1218

1319
// Fix dupe _NativeManifestType
1420
converter.edit('_manifest', 'types', 'NativeManifest', (x) => {
15-
x.choices[0].properties.type.converterTypeOverride = '"pkcs11"| "stdio"';
16-
x.choices[1].properties.type.converterTypeOverride = '"storage"';
21+
x.choices![0].properties!.type.converterTypeOverride = '"pkcs11"| "stdio"';
22+
x.choices![1].properties!.type.converterTypeOverride = '"storage"';
1723
return x;
1824
});
1925

@@ -75,7 +81,7 @@ export default function override(converter: Converter) {
7581

7682
// Additional fix for webrequest.onAuthRequired
7783
converter.edit('webRequest', 'events', 'onAuthRequired', (x) => {
78-
x.parameters = x.parameters.filter((y: TypeSchema) => y.name !== 'callback');
84+
x.parameters = x.parameters!.filter((y: TypeSchema) => y.name !== 'callback');
7985
return x;
8086
});
8187

@@ -210,11 +216,11 @@ export default function override(converter: Converter) {
210216
}
211217

212218
// Prevent some of Event from being promisified
213-
converter.edit('events', 'types', 'Event', (x) => {
214-
for (let f of x.functions.slice(0, 3)) {
219+
converter.edit('events', 'types', 'Event', (Event) => {
220+
for (let f of Event.functions!.slice(0, 3)) {
215221
f.async = false;
216222
}
217-
return x;
223+
return Event;
218224
});
219225

220226
// Remove bookmarks.import and bookmarks.export as it breaks things
@@ -227,8 +233,8 @@ export default function override(converter: Converter) {
227233
// Fix runtime.Port.postMessage
228234
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/23542
229235
converter.edit('runtime', 'types', 'Port', (Port) => {
230-
Port.properties.postMessage.parameters = [{ type: 'object', name: 'message' }];
231-
Port.properties.error = { converterTypeOverride: 'Error', optional: true };
236+
Port.properties!.postMessage.parameters = [{ type: 'object', name: 'message' }];
237+
Port.properties!.error = { converterTypeOverride: 'Error', optional: true };
232238
Port.events = [
233239
{
234240
name: 'onMessage',
@@ -241,8 +247,8 @@ export default function override(converter: Converter) {
241247
parameters: [{ $ref: 'Port', name: 'port' }],
242248
},
243249
];
244-
delete Port.properties.onDisconnect;
245-
delete Port.properties.onMessage;
250+
delete Port.properties!.onDisconnect;
251+
delete Port.properties!.onMessage;
246252

247253
return Port;
248254
});
@@ -269,7 +275,7 @@ export default function override(converter: Converter) {
269275

270276
// Fix error return type in some proxy events
271277
converter.edit('proxy', 'events', 'onError', (onError) => {
272-
onError.parameters[0].converterTypeOverride = 'Error';
278+
onError.parameters![0].converterTypeOverride = 'Error';
273279
return onError;
274280
});
275281

@@ -279,14 +285,14 @@ export default function override(converter: Converter) {
279285
'PersistentBackgroundProperty',
280286
(PersistentBackgroundProperty) => {
281287
PersistentBackgroundProperty.type = 'boolean';
282-
PersistentBackgroundProperty.deprecated = PersistentBackgroundProperty.choices[1].deprecated;
288+
PersistentBackgroundProperty.deprecated = PersistentBackgroundProperty.choices![1].deprecated;
283289
delete PersistentBackgroundProperty.choices;
284290
return PersistentBackgroundProperty;
285291
}
286292
);
287293

288294
converter.edit('permissions', 'functions', 'remove', (remove) => {
289-
remove.parameters[1].parameters = [
295+
remove.parameters![1].parameters = [
290296
{
291297
type: 'boolean',
292298
},
@@ -296,17 +302,118 @@ export default function override(converter: Converter) {
296302

297303
// https://github.com/jsmnbom/definitelytyped-firefox-webext-browser/issues/35
298304
converter.edit('alarms', 'functions', 'get', (get) => {
299-
get.parameters[1].converterPromiseOptional = true;
305+
get.parameters![1].converterPromiseOptional = true;
300306
return get;
301307
});
302308

303309
// These methods can return null for some reason
304310
converter.edit('cookies', 'functions', 'get', (get) => {
305-
get.parameters[1].converterPromiseOptionalNull = true;
311+
get.parameters![1].converterPromiseOptionalNull = true;
306312
return get;
307313
});
308314
converter.edit('cookies', 'functions', 'remove', (remove) => {
309-
remove.parameters[1].converterPromiseOptionalNull = true;
315+
remove.parameters![1].converterPromiseOptionalNull = true;
310316
return remove;
311317
});
318+
319+
// Add runtime.PlatformNaclArch
320+
converter.add('runtime', 'types', {
321+
id: 'PlatformNaclArch',
322+
type: 'string',
323+
enum: ['arm', 'x86-32', 'x86-64'],
324+
});
325+
326+
// Add webrequest.StreamFilter
327+
converter.add('webRequest', 'types', {
328+
id: 'StreamFilter',
329+
type: 'object',
330+
description: 'An object you can use to monitor and modify HTTP responses.',
331+
functions: [
332+
{
333+
name: 'close',
334+
type: 'function',
335+
description: 'Closes the request.',
336+
async: 'callback',
337+
},
338+
{
339+
name: 'disconnect',
340+
type: 'function',
341+
description: 'Disconnects the filter from the request.',
342+
async: 'callback',
343+
},
344+
{
345+
name: 'suspend',
346+
type: 'function',
347+
description: 'Suspends processing of the request.',
348+
async: 'callback',
349+
},
350+
{
351+
name: 'resume',
352+
type: 'function',
353+
description: 'Resumes processing of the request.',
354+
async: 'callback',
355+
},
356+
{
357+
name: 'write',
358+
type: 'function',
359+
description: 'Writes some data to the output stream.',
360+
async: 'callback',
361+
parameters: [
362+
{
363+
name: 'data',
364+
choices: [{ $ref: 'Uint8Array' }, { $ref: 'ArrayBuffer' }],
365+
},
366+
],
367+
},
368+
],
369+
properties: {
370+
status: {
371+
type: 'string',
372+
description: 'Describes the current status of the stream.',
373+
enum: [
374+
'uninitialized',
375+
'transferringdata',
376+
'finishedtransferringdata',
377+
'suspended',
378+
'closed',
379+
'disconnected',
380+
'failed',
381+
],
382+
},
383+
error: {
384+
type: 'string',
385+
description:
386+
'A string that will contain an error message after the onerror event has fired.',
387+
},
388+
onerror: {
389+
description: 'Event handler which is called when an error has occurred.',
390+
converterTypeOverride: '((event: Event) => void) | null',
391+
},
392+
onstop: {
393+
description:
394+
'Event handler which is called when the stream has no more data to deliver and has closed.',
395+
converterTypeOverride: '((event: Event) => void) | null',
396+
},
397+
onstart: {
398+
description:
399+
'Event handler which is called when the stream is about to start receiving data.',
400+
converterTypeOverride: '((event: Event) => void) | null',
401+
},
402+
ondata: {
403+
description: 'Event handler which is called when incoming data is available.',
404+
converterTypeOverride: '((event: _StreamFilterOndataEvent) => void) | null',
405+
converterAdditionalType: 'interface _StreamFilterOndataEvent extends Event { data: ArrayBuffer }'
406+
},
407+
},
408+
});
409+
// converter.add('webRequest', 'types', {
410+
// type: 'object',
411+
// id: '_StreamFilterOndataEvent',
412+
// $extend: 'Event',
413+
// properties: {
414+
// data: {
415+
// $ref: 'ArrayBuffer'
416+
// }
417+
// }
418+
// });
312419
}

0 commit comments

Comments
 (0)