Skip to content
File

Blob: types/test/index.spec.ts

typescript187 lines
1import assert from 'assert';
2import fs from 'fs/promises';
3import { test } from 'node:test';
4import path from 'path';
5import { BuiltinType_Type, StructureGroups } from '@workerd/jsg/rtti';
6import { Message } from 'capnp-es';
7import { printDefinitions } from '../src';
8import { readComments } from '../scripts/build-worker';
9 
10test('main: generates types', async () => {
11 const message = new Message();
12 const root = message.initRoot(StructureGroups);
13 const groups = root._initGroups(1);
14 const group = groups.get(0);
15 group.name = 'definitions';
16 const structures = group._initStructures(5);
17 
18 const eventTarget = structures.get(0);
19 eventTarget.name = 'EventTarget';
20 eventTarget.fullyQualifiedName = 'workerd::api::EventTarget';
21 {
22 const members = eventTarget._initMembers(2);
23 members.get(0)._initConstructor();
24 const method = members.get(1)._initMethod();
25 method.name = 'addEventListener';
26 {
27 const args = method._initArgs(2);
28 args.get(0)._initString().name = 'kj::String';
29 args.get(1)._initBuiltin().type = BuiltinType_Type.V8FUNCTION;
30 }
31 method._initReturnType().voidt = true;
32 }
33 eventTarget.tsDefine = 'interface Event {}';
34 eventTarget.tsOverride = `<EventMap extends Record<string, Event> = Record<string, Event>> {
35 addEventListener<Type extends keyof EventMap>(type: Type, handler: (event: EventMap[Type]) => void): void;
36 }`;
37 
38 const workerGlobalScope = structures.get(1);
39 workerGlobalScope.name = 'WorkerGlobalScope';
40 workerGlobalScope.fullyQualifiedName = 'workerd::api::WorkerGlobalScope';
41 let extendsStructure = workerGlobalScope._initExtends()._initStructure();
42 extendsStructure.name = 'EventTarget';
43 extendsStructure.fullyQualifiedName = 'workerd::api::EventTarget';
44 workerGlobalScope.tsDefine = `type WorkerGlobalScopeEventMap = {
45 fetch: Event;
46 scheduled: Event;
47 }`;
48 workerGlobalScope.tsOverride =
49 'extends EventTarget<WorkerGlobalScopeEventMap>';
50 
51 const serviceWorkerGlobalScope = structures.get(2);
52 serviceWorkerGlobalScope.name = 'ServiceWorkerGlobalScope';
53 serviceWorkerGlobalScope.fullyQualifiedName =
54 'workerd::api::ServiceWorkerGlobalScope';
55 extendsStructure = serviceWorkerGlobalScope._initExtends()._initStructure();
56 extendsStructure.name = 'WorkerGlobalScope';
57 extendsStructure.fullyQualifiedName = 'workerd::api::WorkerGlobalScope';
58 serviceWorkerGlobalScope.tsRoot = true;
59 {
60 const members = serviceWorkerGlobalScope._initMembers(2);
61 
62 // Test that global extraction is performed after iterator processing
63 const method = members.get(0)._initMethod();
64 method.name = 'things';
65 const methodArgs = method._initArgs(1);
66 methodArgs.get(0).boolt = true;
67 const methodReturn = method._initReturnType()._initStructure();
68 methodReturn.name = 'ThingIterator';
69 methodReturn.fullyQualifiedName = 'workerd::api::ThingIterator';
70 
71 const prop = members.get(1)._initProperty();
72 prop.name = 'prop';
73 prop.readonly = true;
74 prop.prototype = true;
75 prop._initType()._initPromise()._initValue()._initNumber().name = 'int';
76 }
77 
78 const iterator = structures.get(3);
79 iterator.name = 'ThingIterator';
80 iterator.fullyQualifiedName = 'workerd::api::ThingIterator';
81 iterator._initExtends()._initIntrinsic().name = 'v8::kIteratorPrototype';
82 iterator.iterable = true;
83 {
84 const members = iterator._initMembers(1);
85 const nextMethod = members.get(0)._initMethod();
86 nextMethod.name = 'next';
87 const nextStruct = nextMethod._initReturnType()._initStructure();
88 nextStruct.name = 'ThingIteratorNext';
89 nextStruct.fullyQualifiedName = 'workerd::api::ThingIteratorNext';
90 const iteratorMethod = iterator._initIterator();
91 iteratorMethod._initReturnType().unknown = true;
92 }
93 const iteratorNext = structures.get(4);
94 iteratorNext.name = 'ThingIteratorNext';
95 iteratorNext.fullyQualifiedName = 'workerd::api::ThingIteratorNext';
96 {
97 const members = iteratorNext._initMembers(2);
98 const doneProp = members.get(0)._initProperty();
99 doneProp.name = 'done';
100 doneProp._initType().boolt = true;
101 const valueProp = members.get(1)._initProperty();
102 valueProp.name = 'value';
103 const valueType = valueProp._initType()._initMaybe();
104 valueType.name = 'jsg::Optional';
105 valueType._initValue()._initString().name = 'kj::String';
106 }
107 
108 // https://bazel.build/reference/test-encyclopedia#initial-conditions
109 const tmpPath = process.env.TEST_TMPDIR;
110 assert(tmpPath !== undefined);
111 const definitionsDir = path.join(tmpPath, 'definitions');
112 await fs.mkdir(definitionsDir);
113 const inputDir = path.join(tmpPath, 'capnp');
114 await fs.mkdir(inputDir);
115 const inputPath = path.join(inputDir, 'types.api.capnp.bin');
116 const comments = readComments();
117 
118 await fs.writeFile(inputPath, new Uint8Array(message.toArrayBuffer()));
119 const { ambient } = printDefinitions(
120 message.getRoot(StructureGroups),
121 comments,
122 ''
123 );
124 
125 assert.strictEqual(
126 ambient,
127 `/*! *****************************************************************************
128Copyright (c) Cloudflare. All rights reserved.
129Copyright (c) Microsoft Corporation. All rights reserved.
130
131Licensed under the Apache License, Version 2.0 (the "License"); you may not use
132this file except in compliance with the License. You may obtain a copy of the
133License at http://www.apache.org/licenses/LICENSE-2.0
134THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
135KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
136WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
137MERCHANTABLITY OR NON-INFRINGEMENT.
138See the Apache Version 2.0 License for specific language governing permissions
139and limitations under the License.
140***************************************************************************** */
141/* eslint-disable */
142// noinspection JSUnusedGlobalSymbols
143declare var onmessage: never;
144/**
145 * The **\`Event\`** interface represents an event which takes place on an \`EventTarget\`.
146 *
147 * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event)
148 */
149interface Event {
150}
151/**
152 * The **\`EventTarget\`** interface is implemented by objects that can receive events and may have listeners for them.
153 *
154 * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget)
155 */
156declare class EventTarget<EventMap extends Record<string, Event> = Record<string, Event>> {
157 constructor();
158 /**
159 * The **\`addEventListener()\`** method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target.
160 *
161 * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener)
162 */
163 addEventListener<Type extends keyof EventMap>(type: Type, handler: (event: EventMap[Type]) => void): void;
164}
165type WorkerGlobalScopeEventMap = {
166 fetch: Event;
167 scheduled: Event;
168};
169declare abstract class WorkerGlobalScope extends EventTarget<WorkerGlobalScopeEventMap> {
170}
171/**
172 * The **\`ServiceWorkerGlobalScope\`** interface of the Service Worker API represents the global execution context of a service worker.
173 * Available only in secure contexts.
174 *
175 * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ServiceWorkerGlobalScope)
176 */
177interface ServiceWorkerGlobalScope extends WorkerGlobalScope {
178 things(param0: boolean): IterableIterator<string>;
179 get prop(): Promise<number>;
180}
181declare function addEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: (event: WorkerGlobalScopeEventMap[Type]) => void): void;
182declare function things(param0: boolean): IterableIterator<string>;
183declare const prop: Promise<number>;
184`
185 );
186});