diff options
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | packages/typescript-types/extract-dom-types.ts | 82 | ||||
-rw-r--r-- | packages/typescript-types/package.json | 1 | ||||
-rw-r--r-- | packages/typescript-types/src/dom.ts | 120 | ||||
-rw-r--r-- | packages/typescript-types/tsconfig.json | 6 |
5 files changed, 150 insertions, 60 deletions
diff --git a/package.json b/package.json index 0d38e01..5a6e1c9 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "rimraf": "^3.0.2", "semver": "^7.3.2", "ts-jest": "^25.5.1", + "ts-morph": "^9.0.0", "ts-node": "^8.10.2", "ttypescript": "^1.5.12", "typedoc": "^0.20.0-beta.8", 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(); diff --git a/packages/typescript-types/package.json b/packages/typescript-types/package.json index 4a42c95..cd361a7 100644 --- a/packages/typescript-types/package.json +++ b/packages/typescript-types/package.json @@ -17,6 +17,7 @@ }, "scripts": { "build": "rimraf dist && tsc", + "extract-dom-types": "ts-node extract-dom-types.ts", "prepublish": "npm run build" }, "keywords": [ diff --git a/packages/typescript-types/src/dom.ts b/packages/typescript-types/src/dom.ts index 8369427..6ec8148 100644 --- a/packages/typescript-types/src/dom.ts +++ b/packages/typescript-types/src/dom.ts @@ -1,6 +1,14 @@ -export interface txAuthGenericArg { - content: ArrayBuffer; - contentType: string; +// Generated from typescript@3.9.7 typescript/lib/lib.dom.d.ts +// To regenerate, run the following command from the project root: +// npx lerna --scope=@simplewebauthn/typescript-types exec -- npm run extract-dom-types +export interface AuthenticatorAssertionResponse extends AuthenticatorResponse { + readonly authenticatorData: ArrayBuffer; + readonly signature: ArrayBuffer; + readonly userHandle: ArrayBuffer | null; +} + +export interface AuthenticatorAttestationResponse extends AuthenticatorResponse { + readonly attestationObject: ArrayBuffer; } export interface AuthenticationExtensionsClientInputs { @@ -14,52 +22,12 @@ export interface AuthenticationExtensionsClientInputs { uvm?: boolean; } -export interface AuthenticationExtensionsClientOutputs { - appid?: boolean; - authnSel?: boolean; - exts?: AuthenticationExtensionsSupported; - loc?: Coordinates; - txAuthGeneric?: ArrayBuffer; - txAuthSimple?: string; - uvi?: ArrayBuffer; - uvm?: UvmEntries; -} - -export interface AuthenticatorAssertionResponse extends AuthenticatorResponse { - readonly authenticatorData: ArrayBuffer; - readonly signature: ArrayBuffer; - readonly userHandle: ArrayBuffer | null; -} - -export interface AuthenticatorAttestationResponse extends AuthenticatorResponse { - readonly attestationObject: ArrayBuffer; -} - -export interface AuthenticatorResponse { - readonly clientDataJSON: ArrayBuffer; -} - export interface AuthenticatorSelectionCriteria { authenticatorAttachment?: AuthenticatorAttachment; requireResidentKey?: boolean; userVerification?: UserVerificationRequirement; } -export interface Coordinates { - readonly accuracy: number; - readonly altitude: number | null; - readonly altitudeAccuracy: number | null; - readonly heading: number | null; - readonly latitude: number; - readonly longitude: number; - readonly speed: number | null; -} - -export interface Credential { - readonly id: string; - readonly type: string; -} - export interface PublicKeyCredential extends Credential { readonly rawId: ArrayBuffer; readonly response: AuthenticatorResponse; @@ -84,11 +52,6 @@ export interface PublicKeyCredentialDescriptor { type: PublicKeyCredentialType; } -export interface PublicKeyCredentialEntity { - icon?: string; - name: string; -} - export interface PublicKeyCredentialParameters { alg: COSEAlgorithmIdentifier; type: PublicKeyCredentialType; @@ -103,24 +66,65 @@ export interface PublicKeyCredentialRequestOptions { userVerification?: UserVerificationRequirement; } +export interface PublicKeyCredentialUserEntity extends PublicKeyCredentialEntity { + displayName: string; + id: BufferSource; +} + +export interface AuthenticatorResponse { + readonly clientDataJSON: ArrayBuffer; +} + +export interface txAuthGenericArg { + content: ArrayBuffer; + contentType: string; +} + +export interface Credential { + readonly id: string; + readonly type: string; +} + +export interface AuthenticationExtensionsClientOutputs { + appid?: boolean; + authnSel?: boolean; + exts?: AuthenticationExtensionsSupported; + loc?: Coordinates; + txAuthGeneric?: ArrayBuffer; + txAuthSimple?: string; + uvi?: ArrayBuffer; + uvm?: UvmEntries; +} + export interface PublicKeyCredentialRpEntity extends PublicKeyCredentialEntity { id?: string; } -export interface PublicKeyCredentialUserEntity extends PublicKeyCredentialEntity { - displayName: string; - id: BufferSource; +export interface PublicKeyCredentialEntity { + icon?: string; + name: string; +} + +/** The position and altitude of the device on Earth, as well as the accuracy with which these properties are calculated. */ +export interface Coordinates { + readonly accuracy: number; + readonly altitude: number | null; + readonly altitudeAccuracy: number | null; + readonly heading: number | null; + readonly latitude: number; + readonly longitude: number; + readonly speed: number | null; } -export type AAGUID = BufferSource; export type AttestationConveyancePreference = 'direct' | 'indirect' | 'none'; -export type AuthenticationExtensionsSupported = string[]; -export type AuthenticatorAttachment = 'cross-platform' | 'platform'; -export type AuthenticatorSelectionList = AAGUID[]; export type AuthenticatorTransport = 'ble' | 'internal' | 'nfc' | 'usb'; -export type BufferSource = ArrayBuffer | ArrayBufferView; export type COSEAlgorithmIdentifier = number; -export type PublicKeyCredentialType = 'public-key'; export type UserVerificationRequirement = 'discouraged' | 'preferred' | 'required'; -export type UvmEntry = number[]; +export type AuthenticatorSelectionList = AAGUID[]; +export type AuthenticatorAttachment = 'cross-platform' | 'platform'; +export type BufferSource = ArrayBufferView | ArrayBuffer; +export type PublicKeyCredentialType = 'public-key'; +export type AAGUID = BufferSource; +export type AuthenticationExtensionsSupported = string[]; export type UvmEntries = UvmEntry[]; +export type UvmEntry = number[]; diff --git a/packages/typescript-types/tsconfig.json b/packages/typescript-types/tsconfig.json index 349e40c..6dfff5f 100644 --- a/packages/typescript-types/tsconfig.json +++ b/packages/typescript-types/tsconfig.json @@ -2,6 +2,8 @@ "extends": "../../tsconfig.json", "compilerOptions": { "baseUrl": "./src", - "outDir": "./dist" - } + "outDir": "./dist", + "emitDeclarationOnly": true + }, + "include": ["src/**/*"] } |