File
Blob: types/test/index.spec.ts
| 1 | import assert from 'assert'; |
| 2 | import fs from 'fs/promises'; |
| 3 | import { test } from 'node:test'; |
| 4 | import path from 'path'; |
| 5 | import { BuiltinType_Type, StructureGroups } from '@workerd/jsg/rtti'; |
| 6 | import { Message } from 'capnp-es'; |
| 7 | import { printDefinitions } from '../src'; |
| 8 | import { readComments } from '../scripts/build-worker'; |
| 9 | |
| 10 | test('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 | `/*! ***************************************************************************** |
| 128 | Copyright (c) Cloudflare. All rights reserved. |
| 129 | Copyright (c) Microsoft Corporation. All rights reserved. |
| 130 | |
| 131 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use |
| 132 | this file except in compliance with the License. You may obtain a copy of the |
| 133 | License at http://www.apache.org/licenses/LICENSE-2.0 |
| 134 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 135 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED |
| 136 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, |
| 137 | MERCHANTABLITY OR NON-INFRINGEMENT. |
| 138 | See the Apache Version 2.0 License for specific language governing permissions |
| 139 | and limitations under the License. |
| 140 | ***************************************************************************** */ |
| 141 | /* eslint-disable */ |
| 142 | // noinspection JSUnusedGlobalSymbols |
| 143 | declare 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 | */ |
| 149 | interface 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 | */ |
| 156 | declare 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 | } |
| 165 | type WorkerGlobalScopeEventMap = { |
| 166 | fetch: Event; |
| 167 | scheduled: Event; |
| 168 | }; |
| 169 | declare 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 | */ |
| 177 | interface ServiceWorkerGlobalScope extends WorkerGlobalScope { |
| 178 | things(param0: boolean): IterableIterator<string>; |
| 179 | get prop(): Promise<number>; |
| 180 | } |
| 181 | declare function addEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: (event: WorkerGlobalScopeEventMap[Type]) => void): void; |
| 182 | declare function things(param0: boolean): IterableIterator<string>; |
| 183 | declare const prop: Promise<number>; |
| 184 | ` |
| 185 | ); |
| 186 | }); |