harfbuzzjs icon indicating copy to clipboard operation
harfbuzzjs copied to clipboard

Compile hbjs.js from harfbuzz.ts

Open tristan-f-r opened this issue 1 year ago • 10 comments

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.

tristan-f-r avatar Jun 15 '24 21:06 tristan-f-r

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

lianghai avatar Sep 04 '24 21:09 lianghai

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).

khaledhosny avatar Sep 04 '24 21:09 khaledhosny

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 avatar Sep 05 '24 00:09 lianghai

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

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

  • https://github.com/harfbuzz/harfbuzzjs/commits/main/harfbuzz.ts
  • https://github.com/harfbuzz/harfbuzzjs/pull/54
  • https://github.com/harfbuzz/harfbuzzjs/pull/90

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

lianghai avatar Mar 09 '25 02:03 lianghai

We should probably move the typings to DefinitelyTyped so they can be community driven.

On Sat, Mar 8, 2025, 11:09 PM 梁海 Liang Hai @.***> wrote:

Hi @ebraminio https://github.com/ebraminio, @alker0 https://github.com/alker0, @chearon https://github.com/chearon, @Jackie1210 https://github.com/Jackie1210, and @tomasdev https://github.com/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 https://github.com/harfbuzz/harfbuzzjs/blob/main/harfbuzz.ts can converge with hbjs.js https://github.com/harfbuzz/harfbuzzjs/blob/main/hbjs.js. Any idea how we can make some progress?

— Reply to this email directly, view it on GitHub https://github.com/harfbuzz/harfbuzzjs/issues/99#issuecomment-2708622745, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACY4AIPBY5JK4LWQRZWFLT2TOPGLAVCNFSM6AAAAABYTV5FA2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDOMBYGYZDENZUGU . You are receiving this because you were mentioned.Message ID: @.***> [image: lianghai]lianghai left a comment (harfbuzz/harfbuzzjs#99) https://github.com/harfbuzz/harfbuzzjs/issues/99#issuecomment-2708622745

Hi @ebraminio https://github.com/ebraminio, @alker0 https://github.com/alker0, @chearon https://github.com/chearon, @Jackie1210 https://github.com/Jackie1210, and @tomasdev https://github.com/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 https://github.com/harfbuzz/harfbuzzjs/blob/main/harfbuzz.ts can converge with hbjs.js https://github.com/harfbuzz/harfbuzzjs/blob/main/hbjs.js. Any idea how we can make some progress?

— Reply to this email directly, view it on GitHub https://github.com/harfbuzz/harfbuzzjs/issues/99#issuecomment-2708622745, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACY4AIPBY5JK4LWQRZWFLT2TOPGLAVCNFSM6AAAAABYTV5FA2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDOMBYGYZDENZUGU . You are receiving this because you were mentioned.Message ID: @.***>

tomasdev avatar Mar 09 '25 02:03 tomasdev

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.

chearon avatar Apr 06 '25 22:04 chearon

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.

lianghai avatar Apr 06 '25 22:04 lianghai

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

khaledhosny avatar Apr 06 '25 22:04 khaledhosny

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.

jlarmstrongiv avatar Apr 09 '25 13:04 jlarmstrongiv

Learned at the ViteConf last week that tsdown seems to be the best practice these days for packaging a TS project.

lianghai avatar Oct 12 '25 23:10 lianghai