Skip to content

Compile hbjs.js from harfbuzz.ts #99

@tristan-f-r

Description

@tristan-f-r

As of now, harfbuzzjs itself is untyped and requires explicitly using the harfbuzz.ts file - to avoid unnecessary duplication, the .js and .d.ts files could be generated instead.

Activity

lianghai

lianghai commented on Sep 4, 2024

@lianghai

@khaledhosny, what’s actually the currently relationship between this harfbuzz.ts and the rest of this project?

khaledhosny

khaledhosny commented on Sep 4, 2024

@khaledhosny
Contributor

I don’t know. I don’t even know what .ts is (I’m not much of a web developer myself and I’m maintaining this project only because no one else does).

lianghai

lianghai commented on Sep 5, 2024

@lianghai

Haha alright… I see. Yeah TypeScript (.ts) is JS with static type checking, usually compiled to JS for distribution. It’s difficult for me to read C++, but I’m quite comfortable with writing TS. Will see if I get to contribute and unify the JS and TS aspects of this repo.

lianghai

lianghai commented on Mar 9, 2025

@lianghai

Hi @ebraminio, @alker0, @chearon, @Jackie1210, and @tomasdev,

You guys all have tried to improve the TypeScript aspect of this project:

Seems like it’ll benefit everyone if this neglected harfbuzz.ts can converge with hbjs.js. Any idea how we can make some progress?

tomasdev

tomasdev commented on Mar 9, 2025

@tomasdev
chearon

chearon commented on Apr 6, 2025

@chearon
Contributor

I don't think community-driven types are better than having them written by the authors of the actual code, and published alongside it.

#54 has problems and should be closed. #90 does a lot of other things that I don't think are necessary. I agree we should converge into one TS file. I have been sort of avoiding that since it's going to be somewhat of a change-the-whole-world PR, but I think it's going to be the best way forward.

lianghai

lianghai commented on Apr 6, 2025

@lianghai

Yeah, I also feel community-maintained typing is usually only a solution when it’s not practical to maintain the typing in the project itself. In this case, as long as we get the project’s (reluctant) lead @khaledhosny’s bless, it should be easy to convert such a small project to TS. It’s even already written with some JSDoc type annotations.

I hope it won’t make it complicated for Khaled’s future maintenance though, as TS certainly has its own quirkiness. I do hope the static type checking can balance that.

What can be some next steps? For example, certainly we’ll need to set up a TS-based npm package – what’s the best practice these days? We should definitely avoid the complicated direction of #90.

khaledhosny

khaledhosny commented on Apr 6, 2025

@khaledhosny
Contributor

I think I’ll have to learn my way through, so whatever people who actually use this library best is fine by me.

jlarmstrongiv

jlarmstrongiv commented on Apr 9, 2025

@jlarmstrongiv

In the meantime, I wrote:

.d.ts file for harfbuzzjs
declare module "harfbuzzjs" {
  export type HBBlob = {
    ptr: number;
    destroy: () => void;
  };

  export type HBFace = {
    prt: number;
    upem: number;
    reference_table: (name: string) => Uint8Array;
    getAxisInfos: () => Record<
      string,
      { min: number; default: number; max: number }
    >;
    collectUnicodes: () => Uint32Array;
    destroy: () => void;
  };

  export type SvgPathCommand =
    | { type: "M"; values: [number, number] }
    | { type: "L"; values: [number, number] }
    | { type: "Q"; values: [number, number, number, number] }
    | { type: "C"; values: [number, number, number, number, number, number] }
    | { type: "Z"; values: [] };

  export type HBVariations = Record<string, number>;
  export type HBFont = {
    ptr: number;
    glyphName: (glyphId: number) => string;
    glyphToPath: (glyphId: number) => string;
    glyphToJson: (glyphId: number) => SvgPathCommand[];
    setScale: (xScale: number, yScale: number) => void;
    setVariations: (variations: HBVariations) => void;
    destroy: () => void;
  };

  export type HBFlag =
    | "BOT"
    | "EOT"
    | "PRESERVE_DEFAULT_IGNORABLES"
    | "REMOVE_DEFAULT_IGNORABLES"
    | "DO_NOT_INSERT_DOTTED_CIRCLE"
    | "PRODUCE_UNSAFE_TO_CONCAT";
  export type HBDir = "ltr" | "rtl" | "ttb" | "btt";
  export type HBJson = {
    g: number;
    cl: number;
    ax: number;
    ay: number;
    dx: number;
    dy: number;
    flags: number;
  };
  export type HBBuffer = {
    ptr: number;
    addText: (text: string) => void;
    guessSegmentProperties: () => void;
    setDirection: (dir: HBDir) => void;
    setFlags: (flags: HBFlag[]) => void;
    setLanguage: (language: string) => void;
    setScript: (script: string) => void;
    setClusterLevel: (level: number) => void;
    json: () => HBJson[];
    destroy: () => void;
  };
  export type HBHandle = {
    createBlob: (blob: Uint8Array) => HBBlob;
    createFace: (blob: HBBlob, index: number) => HBFace;
    createFont: (face: HBFace) => HBFont;
    createBuffer: () => HBBuffer;
    shape: (font: HBFont, buffer: HBBuffer, features: string) => void;
  };
}

declare module "harfbuzzjs/hb.js" {
  export type CreateHarfbuzzParameters = {
    locateFile?: (file: string) => string;
  };
  export default async function createHarfbuzz({
    locateFile,
  }: CreateHarfbuzzParameters = {}): Promise<WebAssembly.WebAssemblyInstantiatedSource>;
}

declare module "harfbuzzjs/hbjs.js" {
  export default function hbjs(
    webAssemblyInstantiatedSource: WebAssembly.WebAssemblyInstantiatedSource,
  ): HBHandle;
}

I would think that because the project is now using emscripten, types for the wasmExports could be generated too:

wasmExports
{
  wasmExports: [Object: null prototype] {
    memory: Memory [WebAssembly.Memory] {},
    __wasm_call_ctors: [Function: 268],
    hb_blob_create: [Function: 492],
    hb_blob_destroy: [Function: 6],
    hb_blob_get_length: [Function: 643],
    hb_blob_get_data: [Function: 639],
    hb_buffer_serialize_glyphs: [Function: 635],
    hb_buffer_create: [Function: 494],
    hb_buffer_destroy: [Function: 493],
    hb_buffer_get_content_type: [Function: 667],
    hb_buffer_set_direction: [Function: 666],
    hb_buffer_set_script: [Function: 665],
    hb_buffer_set_language: [Function: 664],
    hb_buffer_set_flags: [Function: 663],
    hb_buffer_set_cluster_level: [Function: 662],
    hb_buffer_get_length: [Function: 661],
    hb_buffer_get_glyph_infos: [Function: 660],
    hb_buffer_get_glyph_positions: [Function: 179],
    hb_glyph_info_get_glyph_flags: [Function: 659],
    hb_buffer_guess_segment_properties: [Function: 658],
    hb_buffer_add_utf8: [Function: 657],
    hb_buffer_add_utf16: [Function: 656],
    hb_buffer_set_message_func: [Function: 654],
    hb_language_from_string: [Function: 496],
    hb_script_from_string: [Function: 653],
    hb_version: [Function: 652],
    hb_version_string: [Function: 651],
    hb_feature_from_string: [Function: 650],
    malloc: [Function: 29],
    free: [Function: 5],
    hb_draw_funcs_set_move_to_func: [Function: 277],
    hb_draw_funcs_set_line_to_func: [Function: 276],
    hb_draw_funcs_set_quadratic_to_func: [Function: 274],
    hb_draw_funcs_set_cubic_to_func: [Function: 273],
    hb_draw_funcs_set_close_path_func: [Function: 272],
    hb_draw_funcs_create: [Function: 278],
    hb_draw_funcs_destroy: [Function: 271],
    hb_face_create: [Function: 649],
    hb_face_destroy: [Function: 482],
    hb_face_reference_table: [Function: 27],
    hb_face_get_upem: [Function: 646],
    hb_face_collect_unicodes: [Function: 645],
    hb_font_draw_glyph: [Function: 638],
    hb_font_glyph_to_string: [Function: 637],
    hb_font_create: [Function: 636],
    hb_font_destroy: [Function: 371],
    hb_font_set_scale: [Function: 620],
    hb_font_set_variations: [Function: 447],
    hb_set_create: [Function: 526],
    hb_set_destroy: [Function: 525],
    hb_ot_var_get_axis_infos: [Function: 524],
    hb_set_get_population: [Function: 523],
    hb_set_next_many: [Function: 522],
    hb_shape: [Function: 520],
    __indirect_function_table: Table [WebAssembly.Table] {},
    _emscripten_timeout: [Function: 518]
  },
  wasmMemory: Memory [WebAssembly.Memory] {},
  HEAP8: Int8Array(262144) [
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0,
    ... 262044 more items
  ],
  HEAP16: Int16Array(131072) [
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0,
    ... 130972 more items
  ],
  HEAPU8: Uint8Array(262144) [
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0,
    ... 262044 more items
  ],
  HEAPU16: Uint16Array(131072) [
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0,
    ... 130972 more items
  ],
  HEAP32: Int32Array(65536) [
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0,
    ... 65436 more items
  ],
  HEAPU32: Uint32Array(65536) [
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0,
    ... 65436 more items
  ],
  HEAPF32: Float32Array(65536) [
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0,
    ... 65436 more items
  ],
  HEAPF64: Float64Array(32768) [
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0,
    ... 32668 more items
  ],
  HEAP64: BigInt64Array(32768) [
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n,
    ... 32668 more items
  ],
  HEAPU64: BigUint64Array(32768) [
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n,
    0n, 0n, 0n, 0n,
    ... 32668 more items
  ],
  _hb_blob_create: [Function: 492],
  _hb_blob_destroy: [Function: 6],
  _hb_blob_get_length: [Function: 643],
  _hb_blob_get_data: [Function: 639],
  _hb_buffer_serialize_glyphs: [Function: 635],
  _hb_buffer_create: [Function: 494],
  _hb_buffer_destroy: [Function: 493],
  _hb_buffer_get_content_type: [Function: 667],
  _hb_buffer_set_direction: [Function: 666],
  _hb_buffer_set_script: [Function: 665],
  _hb_buffer_set_language: [Function: 664],
  _hb_buffer_set_flags: [Function: 663],
  _hb_buffer_set_cluster_level: [Function: 662],
  _hb_buffer_get_length: [Function: 661],
  _hb_buffer_get_glyph_infos: [Function: 660],
  _hb_buffer_get_glyph_positions: [Function: 179],
  _hb_glyph_info_get_glyph_flags: [Function: 659],
  _hb_buffer_guess_segment_properties: [Function: 658],
  _hb_buffer_add_utf8: [Function: 657],
  _hb_buffer_add_utf16: [Function: 656],
  _hb_buffer_set_message_func: [Function: 654],
  _hb_language_from_string: [Function: 496],
  _hb_script_from_string: [Function: 653],
  _hb_version: [Function: 652],
  _hb_version_string: [Function: 651],
  _hb_feature_from_string: [Function: 650],
  _malloc: [Function: 29],
  _free: [Function: 5],
  _hb_draw_funcs_set_move_to_func: [Function: 277],
  _hb_draw_funcs_set_line_to_func: [Function: 276],
  _hb_draw_funcs_set_quadratic_to_func: [Function: 274],
  _hb_draw_funcs_set_cubic_to_func: [Function: 273],
  _hb_draw_funcs_set_close_path_func: [Function: 272],
  _hb_draw_funcs_create: [Function: 278],
  _hb_draw_funcs_destroy: [Function: 271],
  _hb_face_create: [Function: 649],
  _hb_face_destroy: [Function: 482],
  _hb_face_reference_table: [Function: 27],
  _hb_face_get_upem: [Function: 646],
  _hb_face_collect_unicodes: [Function: 645],
  _hb_font_draw_glyph: [Function: 638],
  _hb_font_glyph_to_string: [Function: 637],
  _hb_font_create: [Function: 636],
  _hb_font_destroy: [Function: 371],
  _hb_font_set_scale: [Function: 620],
  _hb_font_set_variations: [Function: 447],
  _hb_set_create: [Function: 526],
  _hb_set_destroy: [Function: 525],
  _hb_ot_var_get_axis_infos: [Function: 524],
  _hb_set_get_population: [Function: 523],
  _hb_set_next_many: [Function: 522],
  _hb_shape: [Function: 520],
  addFunction: [Function: addFunction],
  removeFunction: [Function: removeFunction],
  calledRun: true
}

I think it would be best to generate hbjs.js and hbjs.d.ts from a TypeScript file, which would also support tsdoc to explain the parameters and give inline examples.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @chearon@khaledhosny@lianghai@tomasdev@jlarmstrongiv

        Issue actions

          Compile hbjs.js from harfbuzz.ts · Issue #99 · harfbuzz/harfbuzzjs