summaryrefslogtreecommitdiffhomepage
path: root/packages/typescript-types/extract-dom-types.ts
diff options
context:
space:
mode:
authorJonathan Stewmon <jstewmon@gmail.com>2020-11-24 17:09:35 -0600
committerJonathan Stewmon <jstewmon@gmail.com>2020-11-26 10:49:09 -0600
commit4bdcd1d13ae7127fa541b5cbef03b57355db5819 (patch)
tree6e0b420eb6d845b66def651198e353363144df03 /packages/typescript-types/extract-dom-types.ts
parentc707d9c02bab395141fb053bdcd7f26460cc7366 (diff)
build: extract-dom-types script to generate dom.ts
Diffstat (limited to 'packages/typescript-types/extract-dom-types.ts')
-rw-r--r--packages/typescript-types/extract-dom-types.ts82
1 files changed, 82 insertions, 0 deletions
diff --git a/packages/typescript-types/extract-dom-types.ts b/packages/typescript-types/extract-dom-types.ts
new file mode 100644
index 0000000..bc16554
--- /dev/null
+++ b/packages/typescript-types/extract-dom-types.ts
@@ -0,0 +1,82 @@
+// n.b. ts-morph is a sibling devDependency of typescript, so that the module
+// loader will resolve our project's typescript package, not the transient
+// dependency of ts-morph. We only want to reference our typescript dependency
+// for its version and its lib.dom.d.ts file. If any typescript functionality
+// is needed, use import { ts } from "ts-morph";
+import {
+ InterfaceDeclaration,
+ Node,
+ Project,
+ Structure,
+ SyntaxKind,
+ TypeAliasDeclaration,
+} from 'ts-morph';
+import { version } from 'typescript';
+
+// List of types we directly reference from the dom lib. Only interface and type
+// alias identifiers are valid, since other syntax types (class, function, var)
+// are implementations, which will not be available outside of the browser.
+const types = [
+ 'AuthenticatorAssertionResponse',
+ 'AttestationConveyancePreference',
+ 'AuthenticatorAttestationResponse',
+ 'AuthenticatorTransport',
+ 'AuthenticationExtensionsClientInputs',
+ 'AuthenticatorSelectionCriteria',
+ 'COSEAlgorithmIdentifier',
+ 'PublicKeyCredential',
+ 'PublicKeyCredentialCreationOptions',
+ 'PublicKeyCredentialDescriptor',
+ 'PublicKeyCredentialParameters',
+ 'PublicKeyCredentialRequestOptions',
+ 'PublicKeyCredentialUserEntity',
+ 'UserVerificationRequirement',
+];
+
+const project = new Project({ skipAddingFilesFromTsConfig: true });
+const domSourcePath = 'typescript/lib/lib.dom.d.ts';
+const domSourceFile = project.addSourceFileAtPath(require.resolve(domSourcePath));
+const resolvedNodes = new Set<InterfaceDeclaration | TypeAliasDeclaration>();
+const unresolvedNodes = new Set<InterfaceDeclaration | TypeAliasDeclaration>(
+ types.map(type => {
+ const node = domSourceFile.getInterface(type) ?? domSourceFile.getTypeAlias(type);
+ if (!node) {
+ throw new Error(`${type} does not refer to an interface or type alias`);
+ }
+ return node;
+ }),
+);
+
+while (unresolvedNodes.size > 0) {
+ for (const node of unresolvedNodes.values()) {
+ unresolvedNodes.delete(node);
+ resolvedNodes.add(node);
+
+ // Declarations in lib files are never exported because they are globally
+ // available. Since we are extracting the types to a module, we export them.
+ node.setIsExported(true);
+
+ // Find all descendant identifiers which reference an interface or type
+ // alias, and add them to the unresolved list.
+ for (const id of node.getDescendantsOfKind(SyntaxKind.Identifier)) {
+ for (const dn of id.getDefinitionNodes()) {
+ if (Node.isInterfaceDeclaration(dn) || Node.isTypeAliasDeclaration(dn)) {
+ if (!resolvedNodes.has(dn)) {
+ unresolvedNodes.add(dn);
+ }
+ }
+ }
+ }
+ }
+}
+
+const outputSourceFile = project.createSourceFile(`src/dom.ts`, undefined, { overwrite: true });
+outputSourceFile.addStatements([
+ `// Generated from typescript@${version} ${domSourcePath}`,
+ `// To regenerate, run the following command from the project root:`,
+ `// npx lerna --scope=@simplewebauthn/typescript-types exec -- npm run extract-dom-types`,
+]);
+const resolvedStructures = Array.from(resolvedNodes).map(node => node.getStructure());
+outputSourceFile.addInterfaces(resolvedStructures.filter(Structure.isInterface));
+outputSourceFile.addTypeAliases(resolvedStructures.filter(Structure.isTypeAlias));
+outputSourceFile.saveSync();