blob: 4bbfd9a2fdd5bbe7bf972db36401c2fc44b82d34 [file] [log] [blame]
Tim van der Lippec2cb4302020-03-11 17:22:14 +00001// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Joel Einbinder3f23eb22018-05-14 23:27:51 +00005const WebIDL2 = require('webidl2');
6const fs = require('fs');
7const path = require('path');
8const ts = require('typescript');
9const glob = require('glob');
10const methods = {
11 __proto__: null
12};
Tim van der Lippee6a98682020-01-15 14:23:08 +000013const program = ts.createProgram(
14 [
15 path.join(__dirname, 'node_modules', 'typescript', 'lib', 'lib.esnext.d.ts'),
16 ],
17 {noLib: true});
Joel Einbinder3f23eb22018-05-14 23:27:51 +000018for (const file of program.getSourceFiles()) {
19 ts.forEachChild(file, node => {
20 if (node.kind === ts.SyntaxKind.InterfaceDeclaration) {
21 for (const member of node.members) {
Tim van der Lippeba26b2b2020-03-11 14:40:00 +000022 if (member.kind === ts.SyntaxKind.MethodSignature) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +000023 parseTSFunction(member, node);
Tim van der Lippeba26b2b2020-03-11 14:40:00 +000024 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +000025 }
26 }
Tim van der Lippeba26b2b2020-03-11 14:40:00 +000027 if (node.kind === ts.SyntaxKind.FunctionDeclaration) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +000028 parseTSFunction(node, {name: {text: 'Window'}});
Tim van der Lippeba26b2b2020-03-11 14:40:00 +000029 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +000030
31 });
32}
33
34function parseTSFunction(func, node) {
Tim van der Lippeba26b2b2020-03-11 14:40:00 +000035 if (!func.name.escapedText) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +000036 return;
Tim van der Lippeba26b2b2020-03-11 14:40:00 +000037 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +000038
39 const args = func.parameters
40 .map(p => {
41 let text = p.name.escapedText;
Tim van der Lippeba26b2b2020-03-11 14:40:00 +000042 if (p.questionToken) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +000043 text = '?' + text;
Tim van der Lippeba26b2b2020-03-11 14:40:00 +000044 }
45 if (p.dotDotDotToken) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +000046 text = '...' + text;
Tim van der Lippeba26b2b2020-03-11 14:40:00 +000047 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +000048 return text;
49 })
50 .filter(x => x !== 'this');
51 storeMethod(node.name.text, func.name.escapedText, args);
52}
53
Mathias Bynensb1b64fc2021-10-08 14:10:49 +020054// Assume the DevTools front-end repository is at
55// `devtools/devtools-frontend`, where `devtools` is on the same level
56// as `chromium`. This matches `scripts/npm_test.js`.
57glob(
58 '../../../../chromium/src/third_party/blink/renderer/+(core|modules)/**/*.idl', {cwd: process.env.PWD},
59 function(er, files) {
60 for (const file of files) {
61 if (file.includes('testing')) {
62 continue;
63 }
64 const data = fs.readFileSync(path.join(process.env.PWD, file), 'utf8');
65 const lines = data.split('\n');
66 const newLines = [];
67 for (const line of lines) {
68 if (!line.includes(' attribute ')) {
69 newLines.push(line);
70 }
71 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +000072
Mathias Bynensb1b64fc2021-10-08 14:10:49 +020073 try {
74 WebIDL2.parse(newLines.join('\n')).forEach(walk);
75 } catch (e) {
76 // console.error(file);
77 }
78 }
79 WebIDL2
80 .parse(`
Joel Einbinder3f23eb22018-05-14 23:27:51 +000081 namespace console {
82 void assert(optional boolean condition = false, any... data);
83 void clear();
84 void count(optional DOMString label = "default");
85 void debug(any... data);
86 void dir(any item, optional object? options);
87 void dirxml(any... data);
88 void error(any... data);
89 void group(any... data);
90 void groupCollapsed(any... data);
91 void groupEnd();
92 void info(any... data);
93 void log(any... data);
94 void profile(optional DOMString title);
95 void profileEnd(optional DOMString title);
96 void table(any... tabularData);
97 void time(optional DOMString label);
98 void timeEnd(optional DOMString label);
99 void timeStamp(optional DOMString name);
100 void trace(any... data);
101 void warn(any... data);
102 };
103`).forEach(walk);
Mathias Bynensb1b64fc2021-10-08 14:10:49 +0200104 postProcess();
105 });
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000106
107function walk(thing, parent) {
108 if (thing.type === 'interface') {
109 const constructor = thing.extAttrs.find(extAttr => extAttr.name === 'Constructor');
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000110 if (constructor && constructor.arguments && thing.extAttrs.find(extAttr => extAttr.name === 'Exposed')) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000111 storeMethod('Window', thing.name, constructor.arguments.map(argName));
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000112 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000113
114 const namedConstructor = thing.extAttrs.find(extAttr => extAttr.name === 'NamedConstructor');
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000115 if (namedConstructor && namedConstructor.arguments) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000116 storeMethod('Window', namedConstructor.rhs.value, namedConstructor.arguments.map(argName));
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000117 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000118 }
119 if (thing.type.includes('operation')) {
120 storeMethod(thing.static ? (parent.name + 'Constructor') : parent.name, thing.name, thing.arguments.map(argName));
121 return;
122 }
123 if (thing.members) {
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000124 for (const member of thing.members) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000125 walk(member, thing);
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000126 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000127 }
128}
129
130function argName(a) {
131 let name = a.name;
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000132 if (a.optional) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000133 name = '?' + name;
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000134 }
135 if (a.variadic) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000136 name = '...' + name;
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000137 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000138 return name;
139}
140
141function storeMethod(parent, name, args) {
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000142 if (!methods[name]) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000143 methods[name] = {__proto__: null};
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000144 }
145 if (!methods[name][parent]) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000146 methods[name][parent] = [];
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000147 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000148 methods[name][parent].push(args);
149}
150
151function postProcess() {
152 for (const name in methods) {
153 const jsonParents = new Set();
154 for (const parent in methods[name]) {
155 const signatures = methods[name][parent];
156 signatures.sort((a, b) => a.length - b.length);
157 const filteredSignatures = [];
158 for (const signature of signatures) {
159 const smallerIndex = filteredSignatures.findIndex(smaller => startsThesame(smaller, signature));
160 if (smallerIndex !== -1) {
161 filteredSignatures[smallerIndex] = (signature.map((arg, index) => {
Joel Einbinder705daf02018-05-16 23:57:41 +0000162 const otherArg = filteredSignatures[smallerIndex][index];
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000163 if (otherArg) {
Joel Einbinder705daf02018-05-16 23:57:41 +0000164 return otherArg.length > arg.length ? otherArg : arg;
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000165 }
166 if (arg.startsWith('?') || arg.startsWith('...')) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000167 return arg;
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000168 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000169 return '?' + arg;
170 }));
171 } else {
172 filteredSignatures.push(signature);
173 }
174 }
175
176 function startsThesame(smaller, bigger) {
177 for (let i = 0; i < smaller.length; i++) {
Joel Einbinder705daf02018-05-16 23:57:41 +0000178 const withoutQuestion = str => /[\?]?(.*)/.exec(str)[1];
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000179 if (withoutQuestion(smaller[i]) !== withoutQuestion(bigger[i])) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000180 return false;
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000181 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000182 }
183 return true;
184 }
185
186 methods[name][parent] = filteredSignatures;
187 jsonParents.add(JSON.stringify(filteredSignatures));
188 }
189 if (jsonParents.size === 1) {
190 methods[name] = {'*': JSON.parse(jsonParents.values().next().value)};
191 }
192 for (const parent in methods[name]) {
193 const signatures = methods[name][parent];
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000194 if (signatures.length === 1 && !signatures[0].length) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000195 delete methods[name][parent];
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000196 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000197 }
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000198 if (!Object.keys(methods[name]).length) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000199 delete methods[name];
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000200 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000201 }
202 const functions = [];
203 for (const name in methods) {
204 if (methods[name]['*']) {
205 functions.push({name, signatures: methods[name]['*']});
206 } else {
207 for (const parent in methods[name]) {
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000208 if (parent.endsWith('Constructor')) {
209 functions.push({
210 name,
211 signatures: methods[name][parent],
212 static: true,
213 receiver: parent.substring(0, parent.length - 'Constructor'.length)
214 });
215 } else {
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000216 functions.push({name, signatures: methods[name][parent], receiver: parent});
Tim van der Lippeba26b2b2020-03-11 14:40:00 +0000217 }
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000218 }
219 }
220 }
221
222 fs.writeFileSync(
Mathias Bynensb1b64fc2021-10-08 14:10:49 +0200223 path.join(__dirname, '..', '..', 'front_end', 'models', 'javascript_metadata', 'NativeFunctions.js'),
Brandon Goddard53faba12020-01-24 16:55:04 +0000224 `// Copyright 2020 The Chromium Authors. All rights reserved.
225// Use of this source code is governed by a BSD-style license that can be
226// found in the LICENSE file.
227// Generated from ${path.relative(path.join(__dirname, '..', '..'), __filename)}
Mathias Bynensb1b64fc2021-10-08 14:10:49 +0200228
229export const NativeFunctions = ${JSON.stringify(functions, null, 2)};
Paul Lewisea12f142019-11-26 17:00:09 +0000230`);
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000231}