Skip to content
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8cef837
add jsDocs
plbstl Aug 14, 2025
f74482d
separate encoding `Options` to `DecodeOptions` and `EncodeOptions`
plbstl Aug 14, 2025
2cc3a01
add typedefs for all supported encodings
plbstl Aug 14, 2025
318accc
add more exhaustive lists of supported encodings
plbstl Aug 14, 2025
55dd479
add script to auto-generate `iconv-lite` typedefs
plbstl Aug 14, 2025
c8daf93
add `typegen` script to package.json
plbstl Aug 14, 2025
d4df2ec
add manual edits warning to generated `index.d.ts`
plbstl Aug 14, 2025
ed4d59c
move `generate-typings` script to `generation` folder
plbstl Aug 14, 2025
b8fc5b6
remove "declare module" from typings
plbstl Aug 16, 2025
429c890
make sure typings correctly describes usage in both cjs and esm
plbstl Aug 16, 2025
60d80da
process all encodings
plbstl Aug 16, 2025
aee31d5
typings: add legacy aliases (`toEncoding`, `fromEncoding`), `enableSt…
plbstl Aug 16, 2025
f4e3513
typings: add `supportsStreams` property
plbstl Aug 16, 2025
a9a5bdc
add jsDocs to legacy aliases
plbstl Aug 16, 2025
88e6647
small doc change
plbstl Aug 16, 2025
17d9b17
small js docs change
plbstl Aug 16, 2025
a2bf322
improve var names and docs
plbstl Aug 16, 2025
72e0fa4
mirror the lib's `_canonicalizeEncoding` logic
plbstl Aug 16, 2025
ed46ed8
change placeholder for `SupportedEncoding` type
plbstl Aug 16, 2025
ed3f39e
improve docs
plbstl Aug 16, 2025
f66e8ec
improve docs
plbstl Aug 16, 2025
a773a6f
refactor: separate generated encodings into a dedicated file
plbstl Aug 16, 2025
088e997
remove unused `index-template.d.ts`
plbstl Aug 16, 2025
f54b92a
Merge branch 'master' of github.com:ashtuchkin/iconv-lite into typede…
bjohansebas Aug 17, 2025
c4d3a80
test: add typescript test
bjohansebas Aug 17, 2025
37f734a
fixup install node types
bjohansebas Aug 17, 2025
4977980
fixup ci
bjohansebas Aug 17, 2025
ea6d519
fix imports and type name
plbstl Aug 17, 2025
a68d5de
fix typescript tests
plbstl Aug 17, 2025
d578371
fix eslint issues
plbstl Aug 17, 2025
41a4833
allow CJS imports from node10
plbstl Aug 17, 2025
9234c9d
improve `@ts-expect-error` comment
plbstl Aug 17, 2025
3bc5c76
correct `@ts-expect-error` comment
plbstl Aug 17, 2025
1d22041
fix typedefs
plbstl Aug 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ jobs:
shell: bash

- name: Remove npm module(s) ${{ matrix.npm-rm }}
run: npm rm --silent --save-dev ${{ matrix.npm-rm }} neostandard @stylistic/eslint-plugin-js @stylistic/eslint-plugin eslint
run: npm rm --silent --save-dev ${{ matrix.npm-rm }} neostandard @stylistic/eslint-plugin-js @stylistic/eslint-plugin eslint typescript @arethetypeswrong/cli expect-type
if: matrix.npm-rm != ''

- name: Install Node version specific dev deps
Expand Down Expand Up @@ -249,9 +249,31 @@ jobs:
node-version: ${{ matrix.node-version }}

- name: Remove npm module(s) iconv, eslint, neostandard, @stylistic/eslint-plugin-js, @stylistic/eslint-plugin
run: npm rm --silent --save-dev iconv neostandard @stylistic/eslint-plugin-js @stylistic/eslint-plugin eslint
run: npm rm --silent --save-dev iconv neostandard @stylistic/eslint-plugin-js @stylistic/eslint-plugin eslint typescript @arethetypeswrong/cli expect-type

- name: Webpack test
shell: bash
run: |
npm run test:webpack
npm run test:webpack

test_typescript:
needs:
- lint
- coverage
runs-on: 'ubuntu-latest'

steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- uses: actions/setup-node@v4
with:
node-version: '22'

- name: Install
run: |
npm install --ignore-scripts

- name: Run typescript tests
run: npm run test:typescript
2 changes: 1 addition & 1 deletion .github/workflows/iojs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
npm config set shrinkwrap false

- name: Remove npm module(s) ${{ matrix.npm-rm }}
run: npm rm --silent --save-dev ${{ matrix.npm-rm }} neostandard @stylistic/eslint-plugin-js @stylistic/eslint-plugin eslint
run: npm rm --silent --save-dev ${{ matrix.npm-rm }} neostandard @stylistic/eslint-plugin-js @stylistic/eslint-plugin eslint typescript @arethetypeswrong/cli expect-type
if: matrix.npm-rm != ''

- name: Install npm module(s) ${{ matrix.npm-i }}
Expand Down
3 changes: 2 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ performance
.nyc_output
eslint.config.js
*.tgz
.git-blame-ignore-revs
.git-blame-ignore-revs
tsconfig.json
3 changes: 2 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ module.exports = [
"encodings/sbcs-data-generated.js", // This a generate file
// We need work on this
"generation"
]
],
ts: true
}),
{
rules: {
Expand Down
80 changes: 80 additions & 0 deletions generation/gen-typings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const fs = require("fs");
const path = require("path");

function getEncodingData(fileName) {
try {
const encodingsDir = path.join(__dirname, "..", "encodings");
return require(path.join(encodingsDir, fileName));
} catch (e) {
console.error(`Error reading ${fileName}:`, e);
return {};
}
}

function collectAllEncodings() {
const allNames = new Set();
const canonicalize = (name) => ("" + name).toLowerCase().replace(/:\d{4}$|[^0-9a-z]/g, "");

const processEncodingObject = (obj) => {
for (const key in obj) {
// Skip codecs
if (key.startsWith("_")) continue;

const value = obj[key];
allNames.add(key); // Add the alias itself

if (typeof value === "string") {
allNames.add(value); // Add the canonical name it points to
} else if (typeof value === "object" && value.name) {
allNames.add(value.name); // Add the name from the object
}
}
};

// Process all relevant files
processEncodingObject(getEncodingData("internal.js"));
processEncodingObject(getEncodingData("utf32.js"));
processEncodingObject(getEncodingData("utf16.js"));
processEncodingObject(getEncodingData("utf7.js"));
processEncodingObject(getEncodingData("sbcs-codec.js"));
processEncodingObject(getEncodingData("sbcs-data.js"));
processEncodingObject(getEncodingData("sbcs-data-generated.js"));
processEncodingObject(getEncodingData("dbcs-codec.js"));
processEncodingObject(getEncodingData("dbcs-data.js"));

// Add the canonicalized (lowercase, alphanumeric, no appended year) versions
const finalNames = new Set();
allNames.forEach((name) => {
finalNames.add(name);
const canon = canonicalize(name);
if (canon) {
finalNames.add(canon);
}
});

return Array.from(finalNames).sort();
}

function generateTypingsFile() {
const allEncodings = collectAllEncodings();
const supportedEncodingType = allEncodings.map((name) => ` | "${name}"`).join("\n");

const generatedHeader = `/*
* ---------------------------------------------------------------------------------------------
* DO NOT EDIT THIS FILE MANUALLY.
* THIS FILE IS AUTOMATICALLY GENERATED.
* TO UPDATE, RUN \`npm run typegen\` AND COMMIT THE CHANGES.
* ---------------------------------------------------------------------------------------------
*/`;

const fileContent = `${generatedHeader}\n
/** A union of all supported encoding strings in \`iconv-lite\`. */
export type Encodings =\n${supportedEncodingType}\n | (string & {})
`;

const outputPath = path.join(__dirname, "..", "types", "encodings.d.ts");
fs.writeFileSync(outputPath, fileContent, "utf8");
}

// Run the script
generateTypingsFile();
150 changes: 120 additions & 30 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,131 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
* REQUIREMENT: This definition is dependent on the @types/node definition.
* Install with `npm install @types/node --save-dev`
*--------------------------------------------------------------------------------------------*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot remove Microsoft’s copyright unless Microsoft gives explicit approval for it to be removed (https://github.com/openjs-foundation/cross-project-council/blob/main/governance/IP_POLICY_GUIDANCE.md#2-copyright-notices).

/* ---------------------------------------------------------------------------------------------
* REQUIREMENT: This definition is dependent on the @types/node definition.
*
* Install with `npm install @types/node --save-dev`
*
* This file provides detailed typings for the public API of iconv-lite
*-------------------------------------------------------------------------------------------- */

declare module 'iconv-lite' {
// Basic API
export function decode(buffer: Buffer | Uint8Array, encoding: string, options?: Options): string;
import type { Encodings } from "../types/encodings"

export function encode(content: string, encoding: string, options?: Options): Buffer;
// --- Options ---

export function encodingExists(encoding: string): boolean;
declare namespace iconv {
export interface DecodeOptions {
/** Strip the byte order mark (BOM) from the input, when decoding. @default true */
stripBOM?: boolean;
/** Override the default endianness for `UTF-16` and `UTF-32` decodings. */
defaultEncoding?: "utf16be" | "utf32be";
}

// Stream API
export function decodeStream(encoding: string, options?: Options): NodeJS.ReadWriteStream;
export interface EncodeOptions {
/** Add a byte order mark (BOM) to the output, when encoding. @default false */
addBOM?: boolean;
/** Override the default endianness for `UTF-32` encoding. */
defaultEncoding?: "utf32be";
}

export function encodeStream(encoding: string, options?: Options): NodeJS.ReadWriteStream;
// --- Return values ---

// Low-level stream APIs
export function getEncoder(encoding: string, options?: Options): EncoderStream;
export interface EncoderStream {
write(str: string): Buffer;

Check failure on line 31 in lib/index.d.ts

View workflow job for this annotation

GitHub Actions / test_typescript

Cannot find name 'Buffer'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`.
end(): Buffer | undefined;

Check failure on line 32 in lib/index.d.ts

View workflow job for this annotation

GitHub Actions / test_typescript

Cannot find name 'Buffer'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`.
}

export function getDecoder(encoding: string, options?: Options): DecoderStream;
}
export interface DecoderStream {
write(buf: Buffer): string;

Check failure on line 36 in lib/index.d.ts

View workflow job for this annotation

GitHub Actions / test_typescript

Cannot find name 'Buffer'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`.
end(): string | undefined;
}

export interface Options {
stripBOM?: boolean;
addBOM?: boolean;
defaultEncoding?: string;
}
export interface Codec {
encoder: new (options?: EncodeOptions, codec?: any) => EncoderStream;
decoder: new (options?: DecodeOptions, codec?: any) => DecoderStream;
[key: string]: any;
}

export interface EncoderStream {
write(str: string): Buffer;
end(): Buffer | undefined;
}
const iconv: {
// --- Basic API ---

/** Encodes a `string` into a `Buffer`, using the provided `encoding`. */
encode(content: string, encoding: Encodings, options?: EncodeOptions): Buffer;

Check failure on line 50 in lib/index.d.ts

View workflow job for this annotation

GitHub Actions / test_typescript

Cannot find name 'Buffer'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`.

/** Decodes a `Buffer` into a `string`, using the provided `encoding`. */
decode(buffer: Buffer | Uint8Array, encoding: Encodings, options?: DecodeOptions): string;

Check failure on line 53 in lib/index.d.ts

View workflow job for this annotation

GitHub Actions / test_typescript

Cannot find name 'Buffer'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`.

/** Checks if a given encoding is supported by `iconv-lite`. */
encodingExists(encoding: string): encoding is Encodings;

// --- Legacy aliases ---

/** Legacy alias for {@link iconv.encode}. */
toEncoding: typeof iconv.encode;

/** Legacy alias for {@link iconv.decode}. */
fromEncoding: typeof iconv.decode;

// --- Stream API ---

/** Creates a stream that decodes binary data from a given `encoding` into strings. */
decodeStream(encoding: Encodings, options?: DecodeOptions): NodeJS.ReadWriteStream;

Check failure on line 69 in lib/index.d.ts

View workflow job for this annotation

GitHub Actions / test_typescript

Cannot find namespace 'NodeJS'.

/** Creates a stream that encodes strings into binary data in a given `encoding`. */
encodeStream(encoding: Encodings, options?: EncodeOptions): NodeJS.ReadWriteStream;

Check failure on line 72 in lib/index.d.ts

View workflow job for this annotation

GitHub Actions / test_typescript

Cannot find namespace 'NodeJS'.

/**
* Explicitly enable Streaming API in browser environments by passing in:
* ```js
* require('stream')
* ```
* @example iconv.enableStreamingAPI(require('stream'));
*/
enableStreamingAPI(stream_module: any): void;

// --- Low-level stream APIs ---

/** Creates and returns a low-level encoder stream. */
getEncoder(encoding: Encodings, options?: EncodeOptions): EncoderStream;

/** Creates and returns a low-level decoder stream. */
getDecoder(encoding: Encodings, options?: DecodeOptions): DecoderStream;

/**
* Returns a codec object for the given `encoding`.
* @throws If the `encoding` is not recognized.
*/
getCodec(encoding: Encodings): Codec;

/** Strips all non-alphanumeric characters and appended year from `encoding`. */
_canonicalizeEncoding(encoding: Encodings): string;

// --- Properties ---

/** A cache of all loaded encoding definitions. */
encodings: Record<
Encodings,
| string
| {
type: string;
[key: string]: any;
}
> | null;

/** A cache of initialized codec objects. */
_codecDataCache: Record<string, Codec>;

/** The character used for untranslatable `Unicode` characters. @default "�" */
defaultCharUnicode: string;

/** The character used for untranslatable `single-byte` characters. @default "?" */
defaultCharSingleByte: string;

/** @readonly Whether or not, Streaming API is enabled. */
readonly supportsStreams: boolean;
}

export interface DecoderStream {
write(buf: Buffer): string;
end(): string | undefined;
export type {
iconv,
Encodings
}
export { iconv as default }
}
export = iconv
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,29 @@
"test:cov": "nyc --exclude test --reporter=html --reporter=text npm test",
"test:performance": "node --allow-natives-syntax performance/index.js",
"test:tap": "mocha --reporter tap --check-leaks --grep .",
"test:webpack": "npm pack && mv iconv-lite-*.tgz test/webpack/iconv-lite.tgz && cd test/webpack && npm install && npm run test && rm iconv-lite.tgz"
"test:typescript": "tsc && attw --pack",
"test:webpack": "npm pack && mv iconv-lite-*.tgz test/webpack/iconv-lite.tgz && cd test/webpack && npm install && npm run test && rm iconv-lite.tgz",
"typegen": "node generation/gen-typings.js"
},
"browser": {
"stream": false
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.17.4",
"@stylistic/eslint-plugin": "^5.1.0",
"@stylistic/eslint-plugin-js": "^4.1.0",
"async": "^3.2.0",
"bench-node": "^0.10.0",
"eslint": "^9.0.0",
"errto": "^0.2.1",
"expect-type": "^1.2.0",
"iconv": "^2.3.5",
"mocha": "^6.2.2",
"neostandard": "^0.12.0",
"nyc": "^14.1.1",
"request": "^2.88.2",
"semver": "^6.3.0",
"typescript": "~5.9.2",
"unorm": "^1.6.0"
},
"dependencies": {
Expand Down
9 changes: 9 additions & 0 deletions test/types/iconv.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import iconv from "../../lib"
import { expectTypeOf } from "expect-type"

expectTypeOf(iconv._canonicalizeEncoding).toBeFunction()
expectTypeOf(iconv.encode).toBeFunction()
expectTypeOf(iconv.decode).toBeFunction()
expectTypeOf(iconv.encodingExists).toBeFunction()
expectTypeOf(iconv.toEncoding).toBeFunction()
expectTypeOf(iconv.enableStreamingAPI).toBeFunction()
2 changes: 2 additions & 0 deletions test/types/import.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import iconv, { iconv as iconvLite, Codec, DecodeOptions, DecoderStream, EncodeOptions, EncoderStream, Encodings } from "../../lib"
13 changes: 13 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "es5",
"lib": [ "es2015" ],
"module": "commonjs",
"noEmit": true,
"strict": true
},
"include": [
"./test/types/**/*.ts",
"./**/*.d.ts"
]
}
Loading
Loading