Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ jobs:
- run: npm ci
- run: npm run build --if-present
- run: npm test
- run: npm publish
- run: npm publish --provenance --access public
19 changes: 19 additions & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Release Please

on:
push:
branches:
- main

permissions:
contents: write
pull-requests: write

jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: googleapis/release-please-action@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
release-type: node
3 changes: 3 additions & 0 deletions .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
".": "5.0.7"
}
110 changes: 78 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# isBinaryFile

Detects if a file is binary in Node.js using ✨promises✨. Similar to [Perl's `-B` switch](http://stackoverflow.com/questions/899206/how-does-perl-know-a-file-is-binary), in that:
Detects if a file is binary in Node.js. Similar to [Perl's `-B` switch](http://stackoverflow.com/questions/899206/how-does-perl-know-a-file-is-binary), in that:

- it reads the first few thousand bytes of a file
- checks for a `null` byte; if it's found, it's binary
- flags non-ASCII characters. After a certain number of "weird" characters, the file is flagged as binary
Expand All @@ -19,52 +20,97 @@ npm install isbinaryfile

Returns `Promise<boolean>` (or just `boolean` for `*Sync`). `true` if the file is binary, `false` otherwise.

### isBinaryFile(filepath)

* `filepath` - a `string` indicating the path to the file.
### isBinaryFile(filepath[, options])

### isBinaryFile(bytes[, size])
- `filepath` - a `string` indicating the path to the file.
- `options` - an optional object with the following properties:
- `encoding` - an encoding hint (see [Encoding Hints](#encoding-hints) below)

* `bytes` - a `Buffer` of the file's contents.
* `size` - an optional `number` indicating the file size.
### isBinaryFile(bytes[, options])

### isBinaryFileSync(filepath)
- `bytes` - a `Buffer` of the file's contents.
- `options` - an optional object with the following properties:
- `size` - the size of the buffer (defaults to `bytes.length`)
- `encoding` - an encoding hint (see [Encoding Hints](#encoding-hints) below)

* `filepath` - a `string` indicating the path to the file.
### isBinaryFileSync(filepath[, options])

Synchronous version of `isBinaryFile`.

### isBinaryFileSync(bytes[, size])
### isBinaryFileSync(bytes[, options])

* `bytes` - a `Buffer` of the file's contents.
* `size` - an optional `number` indicating the file size.
Synchronous version of `isBinaryFile` for buffers.

### Examples

Here's an arbitrary usage:

```javascript
const isBinaryFile = require("isbinaryfile").isBinaryFile;
const fs = require("fs");

const filename = "fixtures/pdf.pdf";
const data = fs.readFileSync(filename);
const stat = fs.lstatSync(filename);

isBinaryFile(data, stat.size).then((result) => {
if (result) {
console.log("It is binary!")
}
else {
console.log("No it is not.")
}
});

const isBinaryFileSync = require("isbinaryfile").isBinaryFileSync;
import { isBinaryFile, isBinaryFileSync } from 'isbinaryfile';
import fs from 'fs';

const filename = 'fixtures/pdf.pdf';

// Async with file path
const result = await isBinaryFile(filename);
if (result) {
console.log('It is binary!');
} else {
console.log('No it is not.');
}

// Sync with buffer
const bytes = fs.readFileSync(filename);
const size = fs.lstatSync(filename).size;
console.log(isBinaryFileSync(bytes, size)); // true or false
console.log(isBinaryFileSync(bytes)); // true or false

// With explicit size option
const partialBuffer = Buffer.alloc(100);
fs.readSync(fs.openSync(filename, 'r'), partialBuffer, 0, 100, 0);
console.log(isBinaryFileSync(partialBuffer, { size: 100 }));
```

### Encoding Hints

For files that use non-UTF-8 encodings, you can provide encoding hints to improve detection accuracy:

```javascript
import { isBinaryFile, isBinaryFileSync } from 'isbinaryfile';

// UTF-16 files without BOM are auto-detected in most cases
const result1 = await isBinaryFile('utf16-file.txt');

// Or provide explicit encoding hint
const result2 = await isBinaryFile('utf16-file.txt', { encoding: 'utf-16' });

// ISO-8859-1 / Latin-1 encoded files
const result3 = isBinaryFileSync('german-text.txt', { encoding: 'latin1' });

// CJK encoded files (Big5, GB2312, EUC-KR, etc.)
const result4 = isBinaryFileSync('chinese-big5.txt', { encoding: 'big5' });
const result5 = isBinaryFileSync('korean-text.txt', { encoding: 'euc-kr' });

// Generic CJK hint when exact encoding is unknown
const result6 = isBinaryFileSync('asian-text.txt', { encoding: 'cjk' });
```

#### Supported Encoding Hints

| Hint | Description |
| ------------ | ------------------------------------------ |
| `utf-16` | UTF-16 (auto-detect endianness) |
| `utf-16le` | UTF-16 Little Endian |
| `utf-16be` | UTF-16 Big Endian |
| `latin1` | ISO-8859-1 / Latin-1 |
| `iso-8859-1` | Alias for latin1 |
| `cjk` | Generic CJK (use when encoding is unknown) |
| `big5` | Traditional Chinese |
| `gb2312` | Simplified Chinese |
| `gbk` | Extended GB2312 |
| `euc-kr` | Korean |
| `shift-jis` | Japanese |

**Note:** UTF-16 without BOM is automatically detected in most cases without needing a hint.

## Testing

Run `npm install`, then run `npm test`.
Run `npm test`.
7 changes: 6 additions & 1 deletion jestconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
{
"preset": "ts-jest/presets/default-esm",
"extensionsToTreatAsEsm": [".ts"],
"moduleNameMapper": {
"^(\\.{1,2}/.*)\\.js$": "$1"
},
"transform": {
"^.+\\.(t|j)sx?$": "ts-jest"
"^.+\\.tsx?$": ["ts-jest", { "useESM": true }]
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"]
Expand Down
18 changes: 10 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "isbinaryfile",
"description": "Detects if a file is binary in Node.js. Similar to Perl's -B.",
"version": "5.0.7",
"type": "module",
"keywords": [
"text",
"binary",
Expand All @@ -23,7 +24,6 @@
"jest": "^29.7.0",
"oxlint": "^0.16",
"prettier": "^3",
"release-it": "^19.0.4",
"ts-jest": "^29.1.4",
"typescript": "^5"
},
Expand All @@ -34,8 +34,14 @@
"lib/**/*"
],
"license": "MIT",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
}
},
"maintainers": [
{
"name": "Garen J. Torikian",
Expand All @@ -52,12 +58,8 @@
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"lint": "oxlint src test",
"prepare": "npm run build",
"release": "release-it",
"prepublishOnly": "npm test && npm run lint",
"preversion": "npm run lint",
"version": "npm run format && git add -A src",
"postversion": "git push && git push --tags",
"test": "jest --config jestconfig.json",
"test": "NODE_OPTIONS='--experimental-vm-modules' jest --config jestconfig.json",
"watch": "tsc -w"
}
}
18 changes: 18 additions & 0 deletions release-please-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
"packages": {
".": {
"release-type": "node",
"changelog-sections": [
{ "type": "feat", "section": "Features" },
{ "type": "fix", "section": "Bug Fixes" },
{ "type": "perf", "section": "Performance Improvements" },
{ "type": "docs", "section": "Documentation", "hidden": true },
{ "type": "chore", "section": "Miscellaneous", "hidden": true },
{ "type": "style", "hidden": true },
{ "type": "refactor", "hidden": true },
{ "type": "test", "hidden": true }
]
}
}
}
36 changes: 36 additions & 0 deletions release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## Release

This project uses [release-please](https://github.com/googleapis/release-please) for automated releases with [conventional commits](https://www.conventionalcommits.org/).

### Commit Message Format

Version bumps are determined automatically from commit messages:

| Commit Type | Example | Version Bump |
| ------------------------------ | ------------------------------- | --------------------- |
| `feat:` | `feat: add streaming detection` | Minor (5.0.0 → 5.1.0) |
| `fix:` | `fix: handle empty buffers` | Patch (5.0.0 → 5.0.1) |
| `feat!:` or `BREAKING CHANGE:` | `feat!: require Node 24` | Major (5.0.0 → 6.0.0) |
| `docs:`, `chore:`, `test:` | `docs: update examples` | No release |

### Release Flow

1. Create a feature branch and make changes
2. Commit using conventional commit format (e.g., `feat: add new feature`)
3. Open a PR and merge to `main`
4. **release-please** automatically creates/updates a Release PR
5. The Release PR accumulates changes and shows the pending changelog
6. When ready to release, merge the Release PR
7. A git tag and GitHub Release are created automatically
8. GitHub Actions publishes to npm

### How the Workflows Interact

Two GitHub Actions workflows handle releases:

| Workflow | Trigger | Purpose |
| -------------------- | ------------------- | -------------------------------------------------------------------- |
| `release-please.yml` | Push to `main` | Creates Release PR, manages versions and changelog, creates git tags |
| `publish.yml` | Git tag `v*` pushed | Builds, tests, and publishes to npm via OIDC |

When you merge a Release PR, `release-please.yml` creates a git tag (e.g., `v5.1.0`), which triggers `publish.yml` to publish to npm.
Loading