blob: 2d37b54122a07443d8db895ce59485db08514842 [file] [log] [blame]
Joel Einbinder3f23eb22018-05-14 23:27:51 +00001const WebIDL2 = require('webidl2');
2const fs = require('fs');
3const path = require('path');
4const ts = require('typescript');
5const glob = require('glob');
6const methods = {
7 __proto__: null
8};
9const methodsByName = {
10 __proto__: null
11};
Tim van der Lippee6a98682020-01-15 14:23:08 +000012const program = ts.createProgram(
13 [
14 path.join(__dirname, 'node_modules', 'typescript', 'lib', 'lib.esnext.d.ts'),
15 ],
16 {noLib: true});
Joel Einbinder3f23eb22018-05-14 23:27:51 +000017for (const file of program.getSourceFiles()) {
18 ts.forEachChild(file, node => {
19 if (node.kind === ts.SyntaxKind.InterfaceDeclaration) {
20 for (const member of node.members) {
21 if (member.kind === ts.SyntaxKind.MethodSignature)
22 parseTSFunction(member, node);
23 }
24 }
25 if (node.kind === ts.SyntaxKind.FunctionDeclaration)
26 parseTSFunction(node, {name: {text: 'Window'}});
27
28 });
29}
30
31function parseTSFunction(func, node) {
32 if (!func.name.escapedText)
33 return;
34
35 const args = func.parameters
36 .map(p => {
37 let text = p.name.escapedText;
38 if (p.questionToken)
39 text = '?' + text;
40 if (p.dotDotDotToken)
41 text = '...' + text;
42 return text;
43 })
44 .filter(x => x !== 'this');
45 storeMethod(node.name.text, func.name.escapedText, args);
46}
47
Tim van der Lippee6a98682020-01-15 14:23:08 +000048const files = glob('../../../../blink/renderer/+(core|modules)/**/*.idl', {cwd: process.env.PWD}, function(er, files) {
Joel Einbinder3f23eb22018-05-14 23:27:51 +000049 for (const file of files) {
50 if (file.includes('testing'))
51 continue;
Tim van der Lippee6a98682020-01-15 14:23:08 +000052 const data = fs.readFileSync(path.join(process.env.PWD, file), 'utf8');
Joel Einbinder3f23eb22018-05-14 23:27:51 +000053 const lines = data.split('\n');
54 const newLines = [];
55 for (line of lines) {
56 if (!line.includes(' attribute '))
57 newLines.push(line);
58 }
59
60 try {
61 WebIDL2.parse(newLines.join('\n')).forEach(walk);
62 } catch (e) {
63 // console.error(file);
64 }
65 }
66 WebIDL2
67 .parse(`
68 namespace console {
69 void assert(optional boolean condition = false, any... data);
70 void clear();
71 void count(optional DOMString label = "default");
72 void debug(any... data);
73 void dir(any item, optional object? options);
74 void dirxml(any... data);
75 void error(any... data);
76 void group(any... data);
77 void groupCollapsed(any... data);
78 void groupEnd();
79 void info(any... data);
80 void log(any... data);
81 void profile(optional DOMString title);
82 void profileEnd(optional DOMString title);
83 void table(any... tabularData);
84 void time(optional DOMString label);
85 void timeEnd(optional DOMString label);
86 void timeStamp(optional DOMString name);
87 void trace(any... data);
88 void warn(any... data);
89 };
90`).forEach(walk);
91 postProcess();
92});
93
94function walk(thing, parent) {
95 if (thing.type === 'interface') {
96 const constructor = thing.extAttrs.find(extAttr => extAttr.name === 'Constructor');
97 if (constructor && constructor.arguments && thing.extAttrs.find(extAttr => extAttr.name === 'Exposed'))
98 storeMethod('Window', thing.name, constructor.arguments.map(argName));
99
100 const namedConstructor = thing.extAttrs.find(extAttr => extAttr.name === 'NamedConstructor');
101 if (namedConstructor && namedConstructor.arguments)
102 storeMethod('Window', namedConstructor.rhs.value, namedConstructor.arguments.map(argName));
103 }
104 if (thing.type.includes('operation')) {
105 storeMethod(thing.static ? (parent.name + 'Constructor') : parent.name, thing.name, thing.arguments.map(argName));
106 return;
107 }
108 if (thing.members) {
109 for (const member of thing.members)
110 walk(member, thing);
111 }
112}
113
114function argName(a) {
115 let name = a.name;
116 if (a.optional)
117 name = '?' + name;
118 if (a.variadic)
119 name = '...' + name;
120 return name;
121}
122
123function storeMethod(parent, name, args) {
124 if (!methods[name])
125 methods[name] = {__proto__: null};
126 if (!methods[name][parent])
127 methods[name][parent] = [];
128 methods[name][parent].push(args);
129}
130
131function postProcess() {
132 for (const name in methods) {
133 const jsonParents = new Set();
134 for (const parent in methods[name]) {
135 const signatures = methods[name][parent];
136 signatures.sort((a, b) => a.length - b.length);
137 const filteredSignatures = [];
138 for (const signature of signatures) {
139 const smallerIndex = filteredSignatures.findIndex(smaller => startsThesame(smaller, signature));
140 if (smallerIndex !== -1) {
141 filteredSignatures[smallerIndex] = (signature.map((arg, index) => {
Joel Einbinder705daf02018-05-16 23:57:41 +0000142 const otherArg = filteredSignatures[smallerIndex][index];
143 if (otherArg)
144 return otherArg.length > arg.length ? otherArg : arg;
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000145 if (arg.startsWith('?') || arg.startsWith('...'))
146 return arg;
147 return '?' + arg;
148 }));
149 } else {
150 filteredSignatures.push(signature);
151 }
152 }
153
154 function startsThesame(smaller, bigger) {
155 for (let i = 0; i < smaller.length; i++) {
Joel Einbinder705daf02018-05-16 23:57:41 +0000156 const withoutQuestion = str => /[\?]?(.*)/.exec(str)[1];
157 if (withoutQuestion(smaller[i]) !== withoutQuestion(bigger[i]))
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000158 return false;
159 }
160 return true;
161 }
162
163 methods[name][parent] = filteredSignatures;
164 jsonParents.add(JSON.stringify(filteredSignatures));
165 }
166 if (jsonParents.size === 1) {
167 methods[name] = {'*': JSON.parse(jsonParents.values().next().value)};
168 }
169 for (const parent in methods[name]) {
170 const signatures = methods[name][parent];
171 if (signatures.length === 1 && !signatures[0].length)
172 delete methods[name][parent];
173 }
174 if (!Object.keys(methods[name]).length)
175 delete methods[name];
176 }
177 const functions = [];
178 for (const name in methods) {
179 if (methods[name]['*']) {
180 functions.push({name, signatures: methods[name]['*']});
181 } else {
182 for (const parent in methods[name]) {
183 if (parent.endsWith('Constructor'))
Joel Einbinder75bb4332019-03-05 22:33:55 +0000184 functions.push({name, signatures: methods[name][parent], static: true, receiver: parent.substring(0, parent.length - 'Constructor'.length)});
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000185 else
186 functions.push({name, signatures: methods[name][parent], receiver: parent});
187 }
188 }
189 }
190
191 fs.writeFileSync(
192 path.join(__dirname, '..', '..', 'front_end', 'javascript_metadata', 'NativeFunctions.js'),
Brandon Goddard53faba12020-01-24 16:55:04 +0000193 `// Copyright 2020 The Chromium Authors. All rights reserved.
194// Use of this source code is governed by a BSD-style license that can be
195// found in the LICENSE file.
196// Generated from ${path.relative(path.join(__dirname, '..', '..'), __filename)}
Paul Lewisea12f142019-11-26 17:00:09 +0000197export const NativeFunctions = ${JSON.stringify(functions)};
Paul Lewisea12f142019-11-26 17:00:09 +0000198`);
Joel Einbinder3f23eb22018-05-14 23:27:51 +0000199}