npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@think-cell/typescripten

v1.0.4444

Published

Typescripten converts TypeScript interface definitions into C++ headers for emscripten projects

Downloads

6

Readme

CI

typescripten

Calling JavaScript code from C++ via emscripten::val offers no type-safety.

typescripten uses TypeScript interface definition files to generate type-safe C++ interfaces for JavaScript and TypeScript libraries. Compare the JavaScript statements in the comments to the C++ code:

int main() {
    // var elem = document.createElement("p")
    auto elem = js::document()->createElement(js::string("p"));

    // elem.innerText = "Hello CppCon 2021"
    elem->innerText(js::string("Hello CppCon 2021"));

    // elem.style.fontSize = 20.0
    elem->style()->fontSize(js::string("20vh"));

    // document.body.appendChild(elem)
    js::document()->body()->appendChild(elem);
}

typescripten uses the parser API provided by typescript. It is now self-hosting, i.e., it can the parse interface definition file for the typescript parser itself.

typescripten has been presented at CppCon 2021 and in a slightly extended talk at CppNow 2022.

Example

Let's say you have a typescript module MyLib.d.ts for a JavaScript library you have written yourself, or maybe for a JavaScript API to some web service:

declare namespace MyLib {
    function appendNumber(a: string, b: number): string;
}

Running the typescripten compiler on this file will produce the C++ header MyLib.d.h

namespace tc::js_defs {
    using namespace jst; // no ADL
    struct _impl_js_jMyLib;
    using _js_jMyLib = ref<_impl_js_jMyLib>;
    struct _impl_js_jMyLib : virtual object_base {
        struct _tcjs_definitions {
            static auto appendNumber(string a, double b) noexcept;
        };
    };
    inline auto _impl_js_jMyLib::_tcjs_definitions::appendNumber(string a, double b) noexcept {
        return emscripten::val::global("MyLib")["appendNumber"](a, b).template as<string>();
    }
}; // namespace tc::js_defs
namespace tc::js {
    using MyLib = js_defs::_js_jMyLib;
} // namespace tc::js

By including the generated header you can use MyLib from C++ in a type-safe way.

#include "MyLib.d.h"
#include <iostream>

int main() {
    std::cout << tc::explicit_cast<std::string>( // Unpack the JavaScript string 
        tc::js::MyLib::appendNumber(
            tc::js::string("foobar"), // Create a JavaScript string
            20 // JavaScript number type maps to double
        )
    ) << std::endl;
}

See typescripten/tests and typescriptenc/tests for more examples.

Close analogues are Rust's stdweb and wasm-bindgen.

TypeScript language support

typescripten/ contains the code to support basic Typescript types and language features

  • any, undefined, null and string types
  • Support for mixed enums like
    enum E {
        a, 
        b = "I'm a string",
        c = 5.0
    }

typescripten supports

Some TypeScript constructs are not yet supported. Better support for generic type constraints and indexed access types are high priority and coming soon.

Exploring the TypeScript compiler API

Both the TypeScript Playground and the TypeScript AST Viewer (Check the JS debug console!) are invaluable when you want to improve typescripten.

Dependencies

Setup

It is easiest to download typescripten from npm.

npm install -g @think-cell/typescripten

I am working on integrating typescripten with emscripten.

If you want to include it in a project of yours, add the following to your Cmake file:

# Download typescripten (The name must not be changed)
include(FetchContent)
FetchContent_Declare(
  typescripten
  GIT_REPOSITORY https://github.com/think-cell/typescripten
)
FetchContent_MakeAvailable(typescripten)

# Include the CMake helper function
include(${typescripten_SOURCE_DIR}/cmake/TypeScripten.cmake)

# Install the types you need via npm (at configure time)
execute_process(COMMAND npm install WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})

# Add your executable target
add_executable(test ...)

# Compile the downloaded TypeScript interface definitions (here lib.dom.d.ts)
# into a header before 'test' is built.
add_typescripten_target(
  TARGET test
  INPUTS ${PROJECT_SOURCE_DIR}/node_modules/typescript/lib/lib.dom.d.ts
  OUTPUT lib.dom.d.h
)

Now you can include <lib.dom.d.h> in your C++ files. In order to build your project, download emscripten and boost, and run

source path/to/emsdk/emsdk_env.sh
emcmake cmake -S . -B build 
cmake --build build

See example and its associated README.

Debugging

typescriptenc debug builds are built with DWARF debug information. Google Chrome Dev builds can interactively debug WebAssembly applications with debug info. See this Chrome blog entry on how to setup Chrome for debugging.

In order to build with debugging support set the DEBUG_DEVTOOLS options. If you build the typescriptenc_debug target, cmake will package typescripten with webpack so it can run in a browser and it will start a web server for you:

source path/to/emsdk/emsdk_env.sh
emcmake cmake -S . -B build -DDEBUG_DEVTOOLS=ON 
cmake --build build --target typescriptenc_debug

Now you should be able to open [http://localhost:8000/debug] in Chrome and in the DevTools console you should be able to see the C++ sources, set breakpoints, look at local variables etc. This debug build cannot read local files from disk, so the input file is hard-coded in debug/index.html. Change that file and rebuild or change the live version in build/debug/index.html and reload the running page.

Naming conventions

We use Hungarian Notation in our code base, i.e.,

  • Global variables start with g_
  • Member fields start with m_
  • Constants start with c_

All variables are prefixed with a type tag <type-tag>Name

  • Name is camel-case
  • int's type tag is n, e.g. nArguments
  • std::string's type tag is str
  • std::vector<T>'s type tag is vec<type-tag-of-T>, name is singular, e.g. vecstrArguments
  • jst::ref<T>'s type tag is j<type-tag-of-T>
  • ts::Symbol's type tag is sym.
  • jst::optional<T>'s type tag is o<type-tag-of-T>.

Example: jst::ref<jst::optional<ts::Symbol>> josymDeclaration;

There should be no duplicates between type tag and name, e.g. vecstrArguments, not vecstrArgumentsVector