Linking KotlinJS generated packages using npm

After developing a Kotlin Multiplatform application that generates JS and TypeScript output files, I am now exploring how to integrate these output files into a TypeScript project. As someone new to TypeScript and the npm ecosystem, I'm navigating through the process step by step.

https://i.sstatic.net/NMxbg.png

The initial package.json file located inside the hotel directory is configured as follows:

{
  "main": "kotlin/hotel.js",
  "devDependencies": {
    "webpack": "4.42.1",
    "webpack-cli": "3.3.11",
    "source-map-loader": "0.2.4",
    "webpack-dev-server": "3.10.3",
    "css-loader": "3.4.2",
    "style-loader": "1.1.3"
  },
  "dependencies": {
    "kotlin": "file:/home/vlad/Code/hotel-state/build/js/packages_imported/kotlin/1.4.0-M2",
    "kotlin-source-map-loader": "file:/home/vlad/Code/hotel-state/build/js/packages_imported/kotlin-source-map-loader/1.4.0-M2"
  },
  "peerDependencies": {},
  "optionalDependencies": {},
  "bundledDependencies": [],
  "name": "hotel",
  "version": "1.0.0"
}

The second package.json file found inside the js directory has the following setup:

{
  "private": true,
  "workspaces": [
    "packages/hotel",
    "packages/hotel-test"
  ],
  "devDependencies": {},
  "dependencies": {},
  "peerDependencies": {},
  "optionalDependencies": {},
  "bundledDependencies": [],
  "name": "hotel",
  "version": "1.0.0"
}

In order to link from the hotel directory, I executed:

sudo npm link hotel 

For my second project, I added the following to my package.json followed by an npm install:

  "dependencies": {
    "hotel": "file:/usr/lib/node_modules/hotel",
    "lit-html": "^1.2.1"
  },

https://i.sstatic.net/UgRgM.png

Despite seeing the hotel package in the autocomplete prompt, it consistently displays a red line underneath. When attempting to use it within other TypeScript files, the compilation process halts.

The typescript headers in the hotel.d.ts contain a namespace delineation:

declare namespace hotel {
    type Nullable<T> = T | null | undefined
    namespace com.harakati.hotel {
        /* ErrorDeclaration: Class com.harakati.hotel.TH with kind: OBJECT */
    }

    namespace com.harakati.hotel {
        class Room {
            constructor(roomNumber: Nullable<number>)
            static Room_init_$Create$(roomNumber: Nullable<number>, $mask0: number, $marker: Nullable<any /*Class kotlin.js.DefaultConstructorMarker with kind: OBJECT*/>): com.harakati.hotel.Room
            roomNumber: number;
        }
    }

Have I properly linked the packages?

Is the inclusion of this linked package accurate?

Are there any additional steps or details that may have been overlooked during this integration process?

Answer №1

It appears that the TypeScript headers generated in Kotlin 1.4 M2 are not being exported, and a bug has already been reported for this issue.

A temporary solution I developed involves running a Kotlin script at the end of a Gradle build to modify the generated TypeScript output.

To implement this workaround, insert the following code snippet inside the Kotlin section of your build.gradle.kts. This will ensure that the TypeScript headers import correctly into your TS project.

    gradle.buildFinished {
        println("==============================================================")
        val path = "$buildDir/js/packages/${project.name}/kotlin/${project.name}.d.ts"
        println("Making some adjustments to \n$path")
        val newLines = mutableListOf<String>()
        println("==============================================================")
        if (File(path).exists()) {
            File(path).readLines().forEach { line ->
                if (line.startsWith("declare namespace") || line.startsWith("}")) {
                    "// $line".let {
                        newLines.add(it)
                        println(it)
                    }
                } else if (line.trim().startsWith("namespace")) {
                    line.replace("namespace", "export namespace").let {
                        newLines.add(it)
                        println(it)
                    }
                } else {
                    line.let {
                        newLines.add(it)
                        println(it)
                    }
                }
            }
            File(path).writeText(newLines.joinToString("\n"))
        } else {
            println("$path does not exist")
        }
        println("==============================================================")
    }

In the package.json file of your TypeScript project, including this modification is simple:

  "dependencies": {
    "hotel": "/home/vlad/Code/.../hotel/build/js",
    "lit-html": "^1.2.1",
    "tslib": "^2.0.0"
  },

Alternatively, you can use npm link to create a symbolic link to the generated output. This allows you to reference the symlink instead of an absolute path, which could be beneficial if you're frequently moving files around.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Encountering an unknown parse error while working with Typescript, Vue, vue-property-decorator, and VSCode

I am brand new to Typescript and Vue.js, and I haven't been able to find a solution here. The code below is causing a parsing error: '}' expected I have double-checked all the bracket pairs and as far as my eye can see, everything looks co ...

Pushing information from an embedded array using Typescript

I am encountering an issue when trying to extract data from a nested array. The JSON object I have looks like this: { component: Assembly, title: "Assembly", path: "/assembly", sections: { title: "Frame Assembly", steps: { ["Step ...

Get a file by clicking on a button with Selenium and NodeJS

I'm currently facing a problem while attempting to download a file into a specific folder using Selenium and nodeJS. The code snippet below illustrates how I am triggering the download by clicking on the button: const chai = require('chai') ...

Troubleshooting the creation of migration paths in NestJS with TypeORM

After diligently studying the NestJS and TypeORM documentation, I have reached a point where I need to start generating migrations. While the migration itself is creating the correct queries, it is not being generated in the desired location. Currently, m ...

Ways to filter down categories by utilizing a specific attribute

How can we define the function getInterface in a way that the returned type by res is specifically number? Just to be clear: I am not attempting to write these functions myself; rather, I have an environment where a method exists that returns different ob ...

NG0303: Unable to establish a connection with 'ngbTooltip' as it is not recognized as a valid property of 'button'

ERROR: 'NG0303: Can't bind to 'ngbTooltip' since it isn't a known property of 'button'.' Encountering this issue in my Angular 12 project when running local tests, the ngbTooltip error is present in all .spec files. ...

Typescript's definition file includes imports that can result in errors

Occasionally, typescript may generate a definition file with code like the following, leading to compile errors: // issue.ts import { Observable } from 'rxjs'; class Issue { get data() { return new Observable(); } } // issue.d.ts class ...

Combining the values of two input fields in Angular

Within my form, I have three input fields labeled Name, hours, and minutes. When I execute a POST operation, I combine the values of hours and minutes into a variable named duration before sending it to the api. The resulting JSON structure appears as fo ...

Setting up a dynamic transition effect with TailwindCSS during page load

One interesting feature I implemented involves a button that, when clicked, makes a div element transparent using a transition effect. To ensure consistency across sessions, I utilized cookies with js-cookie to save and load the visibility state of the el ...

Disregard any metadata contained in JSON

Currently, I am utilizing Retrofit in combination with the GsonConverterFactory on Android. The JSON response received from the API endpoint contains JSON meta information. Here is an example of how a typical response appears: { meta:{"some meta infor ...

Enhancing labels and data in Angular 8 with ng2 charts

I am currently working on an Angular project that involves a chart created with ng2-charts. The data for this chart is entered by the user through a select box for labels and an input field for the data. While I have been able to update the chart with new ...

Tips for incorporating a prototype in TypeScript

Exploring angular 2 has led me to create a TypeScript definition for a truncate method that I plan to implement in one of my services. truncate.ts interface String { truncate(max: number, decorator: string): string; } String.prototype.truncate = fun ...

Tips for choosing a value using the index in Angular 12's Reactive Forms

Check out the following code snippet: <select formControlName="test"> <option value="1">A</option> <option value="2"& selected>B</option> <option value="1">C</option> ...

Testing Material-UI's autocomplete with React Testing Library: a step-by-step guide

I am currently using the material-ui autocomplete component and attempting to test it with react-testing-library. Component: /* eslint-disable no-use-before-define */ import TextField from '@material-ui/core/TextField'; import Autocomplete from ...

Having difficulties launching Electron application - [603:0827/215406.435140:FATAL:electron_main_delegate.cc(264)] It is not supported to run as root without using --no-sandbox option

Setting up an electron project has been a bit tricky for me. I've been following various tutorials, including this one, but I always seem to run into issues. For example, when it comes to "Running your App" and I enter the command npm start, I encoun ...

When executing `docker-compose up` with volumes, the error message "package.json not found" is displayed

While working with my Dockerfile and docker-compose.yml file, I encountered a strange error that only occurs when I add the volumes lines to the docker-compose file. My setup involves using Docker toolbox with Oracle VM VirtualBox on a Windows 7 machine. ...

What is the simplest method for converting a large JSON array of objects into an object containing the same data under the key "data" in TypeScript?

What is the most efficient method for converting a large JSON array of objects into an object with a key named "data" using TypeScript: Original Format: [ { "label":"testing", "id":1, "children":[ { "label":"Pream ...

Guide to Implementing Code Splitting in Webpack 4 for a Library that Exports Separate Modules in a Similar Manner to Lodash or Office Fabric UI

I currently have a large custom NPM library that is utilized by multiple teams within the organization. The library is currently published as one extensive single file, similar to the main lodash file. However, this approach results in bloated application ...

TS7053: The element is implicitly assigned an 'any' type as the expression of type 'string' cannot be used to index the type '{ username: string; email: string; '

Having trouble incorporating TypeScript into a custom React Form Component, and I keep encountering an error that I can't seem to resolve. Error message TS7053: Element implicitly has an 'any' type because expression of type 'string&apo ...

Webpack is unable to resolve the 'style' module

I tried to follow the step-by-step guide for beginners on the website. But when I attempted to load style.css, I encountered an error. ERROR in ./entry.js Module not found: Error: Can't resolve 'style' in 'Path to project in my comput ...