Kotlin / dukat

Converter of <any kind of declarations> to Kotlin external declarations
548 stars 44 forks source link

Ignore __promisify__ or add some smarts around that translation #354

Open vlsi opened 3 years ago

vlsi commented 3 years ago

__promisify__ is a special name which is used to make TypeScript compiler happy for cases like

import { writeFile } from "fs";
import { promisify } from "util";

// uses the `__promisify__ declaration on `writeFile` to correctly type the return value
const writeFileAsync = promisify(writeFile); 

async function foo() {
  await writeFileAsync("test", "output.txt");
}

That means Dukat should ignore __promisify__ declarations, or it could use them to create something Kotlin-specific. For instance, it might create a suspending function.

See https://github.com/DefinitelyTyped/DefinitelyTyped/issues/16860#issuecomment-670788223

vlsi commented 3 years ago

Just in case, here's how promisify typed:

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/fa723dee727e433add7e700420523f0f90e87a01/types/node/util.d.ts#L86-L96

    interface CustomPromisifyLegacy<TCustom extends Function> extends Function {
        __promisify__: TCustom;
    }

    interface CustomPromisifySymbol<TCustom extends Function> extends Function {
        [promisify.custom]: TCustom;
    }

    type CustomPromisify<TCustom extends Function> = CustomPromisifySymbol<TCustom> | CustomPromisifyLegacy<TCustom>;

    function promisify<TCustom extends Function>(fn: CustomPromisify<TCustom>): TCustom;

Here's what Dukat produces:

typealias CustomInspectFunction = (depth: Number, options: InspectOptionsStylized) -> String

typealias CustomPromisifyLegacy<TCustom> = Function<*>

typealias CustomPromisifySymbol<TCustom> = Function<*>
...
external fun <TCustom : Function<*>> promisify(fn: CustomPromisifyLegacy<TCustom>): TCustom

Here's how writeFile is typed: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/9ed156df2fd82ee57bb6f109908b9aad7c0c1b02/types/node/v12/fs.d.ts#L1417-L1441

    /**
     * Asynchronously writes data to a file, replacing the file if it already exists.
     * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
     * URL support is _experimental_.
     * If a file descriptor is provided, the underlying file will _not_ be closed automatically.
     * @param data The data to write. If something other than a Buffer or Uint8Array is provided, the value is coerced to a string.
     */
    function writeFile(path: PathLike | number, data: any, callback: NoParamCallback): void;

    // NOTE: This namespace provides design-time support for util.promisify. Exported members do not exist at runtime.
    namespace writeFile {
        /**
         * Asynchronously writes data to a file, replacing the file if it already exists.
         * @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
         * URL support is _experimental_.
         * If a file descriptor is provided, the underlying file will _not_ be closed automatically.
         * @param data The data to write. If something other than a Buffer or Uint8Array is provided, the value is coerced to a string.
         * @param options Either the encoding for the file, or an object optionally specifying the encoding, file mode, and flag.
         * If `encoding` is not supplied, the default of `'utf8'` is used.
         * If `mode` is not supplied, the default of `0o666` is used.
         * If `mode` is a string, it is parsed as an octal integer.
         * If `flag` is not supplied, the default of `'w'` is used.
         */
        function __promisify__(path: PathLike | number, data: any, options?: WriteFileOptions): Promise<void>;
    }

In other words, the type declares that writeFile has __promisify__ function which enables TypeScript compiler to infer that writeFile is CustomPromisifyLegacy< (path: PathLike | number, data: any, options?: WriteFileOptions) -> Promise<void> >

I'm not sure what is the way to translate that to Kotlin properly, however, I guess it might help to avoid genering __promisify__ into the resulting Kotlin code.