Skip to content

Commit

Permalink
Change to replace Buffer with Uint8Array
Browse files Browse the repository at this point in the history
Previously, this project depended on Node’s buffer.
This commit changes that: it replaces that support with `Uint8Array`.
In most cases, this will be fine, because the Node `Buffer` class subclasses
`Uint8Array`.
However, there are differences in which encodings are supported when turning
this binary data into a string, and there are differences in how methods work.

Closes GH-85.

Reviewed-by: Christian Murphy <christian.murphy.42@gmail.com>
  • Loading branch information
wooorm committed Jun 10, 2023
1 parent f72469b commit f4edd0d
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 80 deletions.
18 changes: 2 additions & 16 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
/**
* This is the same as `Buffer` if node types are included, `never` otherwise.
*/
// eslint-disable-next-line @typescript-eslint/ban-ts-comment, @typescript-eslint/prefer-ts-expect-error
// @ts-ignore It’s important to preserve this ignore statement. This makes sure
// it works both with and without node types.
// eslint-disable-next-line n/prefer-global/buffer
type MaybeBuffer = any extends Buffer ? never : Buffer

/**
* Contents of the file.
*
* Can either be text or a `Buffer` structure.
* Can either be text or a `Uint8Array` structure.
*/
// Note: this does not directly use type `Buffer`, because it can also be used
// in a browser context.
// Instead this leverages `Uint8Array` which is the base type for `Buffer`,
// and a native JavaScript construct.
export type Value = MaybeBuffer | string
export type Value = Uint8Array | string

/**
* This map registers the type of the `data` key of a `VFile`.
Expand Down Expand Up @@ -49,7 +36,6 @@ export type {Data as VFileData, DataMap as VFileDataMap, Value as VFileValue}
export {VFile} from './lib/index.js'

export type {
BufferEncoding,
Compatible,
Map,
MessageOptions,
Expand Down
50 changes: 30 additions & 20 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,6 @@
/**
* @typedef {object & {type: string, position?: Position | undefined}} NodeLike
*
* @typedef {'ascii' | 'base64' | 'base64url' | 'binary' | 'hex' | 'latin1' | 'ucs-2' | 'ucs2' | 'utf-8' | 'utf16le' | 'utf8'} BufferEncoding
* Encodings supported by the buffer class.
*
* This is a copy of the types from Node, copied to prevent Node globals from
* being needed.
* Copied from: <https://github.com/DefinitelyTyped/DefinitelyTyped/blob/1761eec/types/node/buffer.d.ts#L223>
*
* @typedef {Options | URL | VFile | Value} Compatible
* Things that can be passed to the constructor.
*
Expand Down Expand Up @@ -83,7 +76,6 @@
* Report.
*/

import bufferLike from 'is-buffer'
import {VFileMessage} from 'vfile-message'
import {path} from 'vfile/do-not-use-conditional-minpath'
import {proc} from 'vfile/do-not-use-conditional-minproc'
Expand All @@ -109,7 +101,7 @@ export class VFile {
*
* `options` is treated as:
*
* * `string` or `Buffer` — `{value: options}`
* * `string` or `Uint8Array` — `{value: options}`
* * `URL` — `{path: options}`
* * `VFile` — shallow copies its data over to the new file
* * `object` — all fields are shallow copied over to the new file
Expand All @@ -132,10 +124,10 @@ export class VFile {

if (!value) {
options = {}
} else if (typeof value === 'string' || buffer(value)) {
options = {value}
} else if (isUrl(value)) {
options = {path: value}
} else if (typeof value === 'string' || isUint8Array(value)) {
options = {value}
} else {
options = value
}
Expand Down Expand Up @@ -619,14 +611,27 @@ export class VFile {
/**
* Serialize the file.
*
* @param {BufferEncoding | null | undefined} [encoding='utf8']
* Character encoding to understand `value` as when it’s a `Buffer`
* (default: `'utf8'`).
* > **Note**: which encodings are supported depends on the engine.
* > For info on Node.js, see:
* > <https://nodejs.org/api/util.html#whatwg-supported-encodings>.
*
* @param {string | null | undefined} [encoding='utf8']
* Character encoding to understand `value` as when it’s a `Uint8Array`
* (default: `'utf-8'`).
* @returns {string}
* Serialized file.
*/
toString(encoding) {
return (this.value || '').toString(encoding || undefined)
if (this.value === undefined) {
return ''
}

if (typeof this.value === 'string') {
return this.value
}

const decoder = new TextDecoder(encoding || undefined)
return decoder.decode(this.value)
}
}

Expand Down Expand Up @@ -681,13 +686,18 @@ function assertPath(path, name) {
}

/**
* Assert `value` is a buffer.
* Assert `value` is an `Uint8Array`.
*
* @param {unknown} value
* thing.
* @returns {value is Buffer}
* Whether `value` is a Node.js buffer.
* @returns {value is Uint8Array}
* Whether `value` is an `Uint8Array`.
*/
function buffer(value) {
return bufferLike(value)
function isUint8Array(value) {
return Boolean(
value &&
typeof value === 'object' &&
'byteLength' in value &&
'byteOffset' in value
)
}
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
],
"dependencies": {
"@types/unist": "^2.0.0",
"is-buffer": "^2.0.0",
"unist-util-stringify-position": "^3.0.0",
"vfile-message": "^4.0.0"
},
Expand Down
49 changes: 12 additions & 37 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ metadata about files (such as its `path` and `value`) and lint
* [`VFile#info(reason[, options])`](#vfileinforeason-options)
* [`VFile#message(reason[, options])`](#vfilemessagereason-options)
* [`VFile#toString(encoding?)`](#vfiletostringencoding)
* [`BufferEncoding`](#bufferencoding)
* [`Compatible`](#compatible)
* [`Data`](#data)
* [`DataMap`](#datamap)
Expand Down Expand Up @@ -170,7 +169,7 @@ Create a new virtual file.

`options` is treated as:

* `string` or [`Buffer`][buffer]`{value: options}`
* `string` or [`Uint8Array`][mdn-uint8-array]`{value: options}`
* `URL``{path: options}`
* `VFile` — shallow copies its data over to the new file
* `object` — all fields are shallow copied over to the new file
Expand All @@ -196,7 +195,7 @@ New instance (`VFile`).
```js
new VFile()
new VFile('console.log("alpha");')
new VFile(Buffer.from('exit 1'))
new VFile(new Uint8Array([0x65, 0x78, 0x69, 0x74, 0x20, 0x31]))
new VFile({path: path.join('path', 'to', 'readme.md')})
new VFile({stem: 'readme', extname: '.md', dirname: path.join('path', 'to')})
new VFile({other: 'properties', are: 'copied', ov: {e: 'r'}})
Expand Down Expand Up @@ -226,7 +225,7 @@ List of messages associated with the file

### `file.value`

Raw value ([`Buffer`][buffer], `string`, `undefined`).
Raw value ([`Uint8Array`][mdn-uint8-array], `string`, `undefined`).

### `file.basename`

Expand Down Expand Up @@ -337,39 +336,20 @@ Message ([`VFileMessage`][vmessage]).

Serialize the file.

> **Note**: which encodings are supported depends on the engine.
> For info on Node.js, see:
> <https://nodejs.org/api/util.html#whatwg-supported-encodings>.
###### Parameters

* `encoding` ([`BufferEncoding`][api-buffer-encoding], default: `'utf8'`)
* `encoding` (`string`, default: `'utf8'`)
— character encoding to understand `value` as when it’s a
[`Buffer`][buffer]
[`Uint8Array`][mdn-uint8-array]

###### Returns

Serialized file (`string`).

### `BufferEncoding`

[Encodings][encoding] supported by the [buffer][] class (TypeScript type).

This is a copy of the types from Node.

###### Type

```ts
type BufferEncoding =
| 'ascii'
| 'base64'
| 'base64url'
| 'binary'
| 'hex'
| 'latin1'
| 'ucs-2'
| 'ucs2'
| 'utf-8'
| 'utf16le'
| 'utf8'
```
### `Compatible`

Things that can be passed to the constructor (TypeScript type).
Expand Down Expand Up @@ -497,12 +477,12 @@ type ReporterSettings = Record<string, unknown>
Contents of the file (TypeScript type).
Can either be text or a `Buffer` structure.
Can either be text or a [`Uint8Array`][mdn-uint8-array] structure.
###### Type
```ts
type Value = Buffer | string
type Value = Uint8Array | string
```
### Well-known
Expand Down Expand Up @@ -586,7 +566,6 @@ There are also well-known fields on messages, see
This package is fully typed with [TypeScript][].
It exports the additional types
[`BufferEncoding`][api-buffer-encoding],
[`Compatible`][api-compatible],
[`Data`][api-data],
[`DataMap`][api-data-map],
Expand Down Expand Up @@ -773,9 +752,7 @@ for contributing commits since!
[vfile-message-options]: https://github.com/vfile/vfile-message#options
[encoding]: https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings
[buffer]: https://nodejs.org/api/buffer.html
[mdn-uint8-array]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array
[source-map]: https://github.com/mozilla/source-map/blob/58819f0/source-map.d.ts#L15-L23
Expand All @@ -789,8 +766,6 @@ for contributing commits since!
[api-vfile]: #vfileoptions
[api-buffer-encoding]: #bufferencoding
[api-compatible]: #compatible
[api-data]: #data
Expand Down
22 changes: 16 additions & 6 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,25 @@ test('new VFile(options?)', async function (t) {
)

assert.equal(
new VFile(Buffer.from('bar')).toString(),
'bar',
'buffer: should return the internal value'
new VFile(Buffer.from([0xef, 0xbb, 0xbf, 0x61, 0x62, 0x63])).toString(),
'abc',
'should return the internal value (`Buffer`, default: utf8)'
)

assert.equal(
new VFile(Buffer.from('bar')).toString('hex'),
'626172',
'buffer encoding: should return the internal value'
new VFile(
new Uint8Array([0xfe, 0xff, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63])
).toString('utf-16be'),
'abc',
'should return the internal value (`Uint8Array`, explicit utf-16be)'
)

assert.equal(
new VFile(
new Uint8Array([0xff, 0xfe, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00])
).toString('utf-16le'),
'abc',
'should return the internal value (`Uint8Array`, explicit utf-16le)'
)
})

Expand Down

0 comments on commit f4edd0d

Please sign in to comment.