blob: 97f0bc722446974cafaa6ab64e927a9bddd35e93 [file] [log] [blame]
Johan Bay49f681a2022-01-27 09:25:13 +00001// Copyright 2022 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
5import * as assert from 'assert';
6import ts from 'typescript';
7import * as WebIDL2 from 'webidl2';
8
9import {clearState, parseTSFunction, postProcess, walkRoot} from './helpers.js';
10
11describe('NativeFunction signature generation', function() {
12 this.afterEach(() => {
13 clearState();
14 });
15
16 it('should produce correct signatures for IDL interface', function() {
17 WebIDL2
18 .parse(`
19[
20 Exposed=Window
21] interface Document : Node {
22 [CallWith=Document] constructor();
23 [Affects=Nothing] HTMLCollection getElementsByTagName(DOMString localName);
24 [Affects=Nothing] HTMLCollection getElementsByTagNameNS(DOMString? namespaceURI, DOMString localName);
25 [Affects=Nothing] HTMLCollection getElementsByClassName(DOMString classNames);
26
27 [NewObject, DoNotTestNewObject, PerWorldBindings, RaisesException, ImplementedAs=CreateElementForBinding] Element createElement(DOMString localName);
28 [NewObject, DoNotTestNewObject, RaisesException] Element createElementNS(DOMString? namespaceURI, DOMString qualifiedName);
29 [NewObject] DocumentFragment createDocumentFragment();
30 [NewObject] Text createTextNode(DOMString data);
31};
32`).forEach(walkRoot);
33 const output = postProcess(/* dryRun: */ true);
34 const expected = `export const NativeFunctions = [
35 {
36 name: "getElementsByTagName",
37 signatures: [["localName"]]
38 },
39 {
40 name: "getElementsByTagNameNS",
41 signatures: [["namespaceURI","localName"]]
42 },
43 {
44 name: "getElementsByClassName",
45 signatures: [["classNames"]]
46 },
47 {
48 name: "createElement",
49 signatures: [["localName"]]
50 },
51 {
52 name: "createElementNS",
53 signatures: [["namespaceURI","qualifiedName"]]
54 },
55 {
56 name: "createTextNode",
57 signatures: [["data"]]
58 }
59];`;
60 assert.equal(output, expected);
61 });
62
63 it('should produce correct signatures for IDL mixin interface', function() {
64 WebIDL2
65 .parse(`[
66 LegacyTreatAsPartialInterface,
67 Exposed=(Window,Worker)
68] interface mixin WindowOrWorkerGlobalScope {
69 [CallWith=ScriptState] void reportError(any e);
70
71 [RaisesException] DOMString atob(DOMString atob);
72 [CallWith=ScriptState, RuntimeCallStatsCounter=WindowSetTimeout] long setTimeout(Function handler, optional long timeout = 0, any... arguments);
73 [CallWith=ScriptState] long setTimeout(ScriptString handler, optional long timeout = 0, any... arguments);
74};
75`).forEach(walkRoot);
76 const output = postProcess(/* dryRun: */ true);
77 const expected = `export const NativeFunctions = [
78 {
79 name: "reportError",
80 signatures: [["e"]]
81 },
82 {
83 name: "atob",
84 signatures: [["atob"]]
85 },
86 {
87 name: "setTimeout",
88 signatures: [["handler","?timeout","...arguments"]]
89 }
90];`;
91 assert.equal(output, expected);
92 });
93
94 it('should produce correct signatures for Console IDL', function() {
95 WebIDL2
96 .parse(`
97[Exposed=(Window,Worker,Worklet)]
98namespace console {
99 undefined assert(optional boolean condition = false, any... data);
100 undefined table(optional any tabularData, optional sequence<DOMString> properties);
101 undefined count(optional DOMString label = "default");
102 undefined groupEnd();
103};
104`).forEach(walkRoot);
105 const output = postProcess(/* dryRun: */ true);
106 const expected = `export const NativeFunctions = [
107 {
108 name: "assert",
109 signatures: [["?condition","...data"]]
110 },
111 {
112 name: "table",
113 signatures: [["?tabularData","?properties"]]
114 },
115 {
116 name: "count",
117 signatures: [["?label"]]
118 }
119];`;
120 assert.equal(output, expected);
121 });
122
123 it('should produce correct signatures for Console IDL', function() {
124 WebIDL2
125 .parse(`
126// https://html.spec.whatwg.org/C/#the-slot-element
127[
128 Exposed=Window,
129 HTMLConstructor
130] interface HTMLSlotElement : HTMLElement {
131 [CEReactions, Reflect] attribute DOMString name;
132 [ImplementedAs=AssignedNodesForBinding] sequence<Node> assignedNodes(optional AssignedNodesOptions options = {});
133 [ImplementedAs=AssignedElementsForBinding] sequence<Element> assignedElements(optional AssignedNodesOptions options = {});
134 [RaisesException] void assign((Element or Text)... nodes);
135};
136`).forEach(walkRoot);
137 const output = postProcess(/* dryRun: */ true);
138 const expected = `export const NativeFunctions = [
139 {
140 name: "assignedNodes",
141 signatures: [["?options"]]
142 },
143 {
144 name: "assignedElements",
145 signatures: [["?options"]]
146 },
147 {
148 name: "assign",
149 signatures: [["...nodes"]]
150 }
151];`;
152 assert.equal(output, expected);
153 });
154
155 it('should produce correct signatures for typescript typings', function() {
156 const program = ts.createProgram(
157 [
158 new URL('test.d.ts', import.meta.url).pathname,
159 ],
160 {noLib: true, types: []});
161
162 for (const file of program.getSourceFiles()) {
163 ts.forEachChild(file, node => {
164 if (node.kind === ts.SyntaxKind.InterfaceDeclaration) {
165 for (const member of node.members) {
166 if (member.kind === ts.SyntaxKind.MethodSignature) {
167 parseTSFunction(member, node);
168 }
169 }
170 }
171 if (node.kind === ts.SyntaxKind.FunctionDeclaration) {
172 parseTSFunction(node, {name: {text: 'Window'}});
173 }
174 });
175 }
176 const output = postProcess(/* dryRun: */ true);
177 const expected = `export const NativeFunctions = [
178 {
179 name: "at",
180 signatures: [["index"]]
181 },
182 {
183 name: "diffSig",
184 signatures: [["oneSig"]],
Johan Bayebb70e32022-05-23 17:46:37 +0200185 receivers: ["Array"]
Johan Bay49f681a2022-01-27 09:25:13 +0000186 },
187 {
188 name: "diffSig",
189 signatures: [["twoSig"]],
Johan Bayebb70e32022-05-23 17:46:37 +0200190 receivers: ["ReadonlyArray"]
Johan Bay49f681a2022-01-27 09:25:13 +0000191 }
192];`;
193 assert.equal(output, expected);
194 });
195});