#!/usr/bin/env node /** * @file * Updates the SDK Typescript definitions located in the file sdk.d.ts * to match the current definitions of functions of sdk.mjs. */ import {execSync} from 'node:child_process'; import fs from 'node:fs/promises'; import path from 'node:path'; import process from 'node:process'; import {getDirnameFromImportMeta} from '../../sdk.mjs'; const __dirname = getDirnameFromImportMeta(import.meta.url); const rootDirectory = path.resolve(__dirname, '..', '..'); const sdkTs = path.resolve(rootDirectory, 'sdk.d.ts'); const sdkMts = path.resolve(rootDirectory, 'sdk.d.mts'); const sdkMjs = path.resolve(rootDirectory, 'sdk.mjs'); const generateSdkMts = async () => { // Remove temporally type definitions imported with comments // in sdk.mjs to avoid circular imports const originalSdkMjsContent = await fs.readFile(sdkMjs, 'utf8'); const temporarySdkMjsContent = originalSdkMjsContent .split('\n') .filter((line) => { return !line.startsWith(' * @typedef {import("./sdk")'); }) .join('\n'); await fs.writeFile(sdkMjs, temporarySdkMjsContent); try { execSync( 'npx tsc sdk.mjs' + ' --declaration --emitDeclarationOnly --allowJs --removeComments', ); } catch (/** @type {unknown} */ error) { await fs.writeFile(sdkMjs, originalSdkMjsContent); let errorMessage = error; if (error instanceof Error) { // The `execSync` function throws a generic Node.js Error errorMessage = error.message; } process.stdout.write( `Error generating Typescript definitions: '${errorMessage}'\n`, ); process.exit(1); } await fs.writeFile(sdkMjs, originalSdkMjsContent); }; /** * We must remove the duplicated export types that tsc generates from * JSDoc `typedef` comments. * See {@link https://github.com/microsoft/TypeScript/issues/46011} * @param {string} content Content of the file * @returns {string} The content without duplicated export types */ const removeDuplicatedExportTypes = (content) => { const newContent = []; const lines = content.split('\n'); /** @type {string[]} */ const exportTypesFound = []; for (const line of lines) { if (line.startsWith('export type ')) { const type = line.split(' ')[2]; if (!exportTypesFound.includes(type)) { newContent.push(line); exportTypesFound.push(type); } } else { newContent.push(line); } } return newContent.join('\n'); }; const generateSdkTs = async () => { const fileExists = await fs .access(sdkMts) .then(() => true) .catch(() => false); if (fileExists) await fs.unlink(sdkMts); await generateSdkMts(); const autogeneratedMessage = '/* The next code is autogenerated from sdk.mjs */\n/* eslint-disable */'; const newSdkTsContent = // eslint-disable-next-line unicorn/no-await-expression-member (await fs.readFile(sdkTs, 'utf8')).split(autogeneratedMessage)[0] + `${autogeneratedMessage}\n\n${await fs.readFile(sdkMts, 'utf8')}`; await fs.writeFile(sdkTs, removeDuplicatedExportTypes(newSdkTsContent)); await fs.unlink(sdkMts); try { execSync('npx prettier -w sdk.d.ts'); } catch (error) { let errorMessage = error; if (error instanceof Error) { // The `execSync` function throws a generic Node.js Error errorMessage = error.message; } process.stdout.write( 'Error executing Prettier to prettify' + ` SDK TS definitions: '${errorMessage}'` + '\n', ); process.exit(1); } }; await generateSdkTs();