diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..0b9a855 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,17 @@ +{ + "root": true, + + "extends": "@ljharb", + + "globals": { + "DataView": false, + }, + + "rules": { + "new-cap": ["error", { + "capIsNewExceptions": [ + "GetIntrinsic", + ], + }], + }, +} diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..e0dbc95 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: [ljharb] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: npm/data-view-buffer +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with a single custom sponsorship URL diff --git a/.github/workflows/node-aught.yml b/.github/workflows/node-aught.yml new file mode 100644 index 0000000..a4cd29e --- /dev/null +++ b/.github/workflows/node-aught.yml @@ -0,0 +1,22 @@ +name: 'Tests: node.js < 10' + +on: [pull_request, push] + +permissions: + contents: read + +jobs: + tests: + uses: ljharb/actions/.github/workflows/node.yml@main + with: + range: '< 10' + type: minors + command: npm run tests-only + skip-ls-check: true + + node: + name: 'node < 10' + needs: [tests] + runs-on: ubuntu-latest + steps: + - run: true diff --git a/.github/workflows/node-pretest.yml b/.github/workflows/node-pretest.yml new file mode 100644 index 0000000..88d49f9 --- /dev/null +++ b/.github/workflows/node-pretest.yml @@ -0,0 +1,10 @@ +name: 'Tests: pretest/posttest' + +on: [pull_request, push] + +permissions: + contents: read + +jobs: + tests: + uses: ljharb/actions/.github/workflows/pretest.yml@main diff --git a/.github/workflows/node-tens.yml b/.github/workflows/node-tens.yml new file mode 100644 index 0000000..480c893 --- /dev/null +++ b/.github/workflows/node-tens.yml @@ -0,0 +1,21 @@ +name: 'Tests: node.js >= 10' + +on: [pull_request, push] + +permissions: + contents: read + +jobs: + tests: + uses: ljharb/actions/.github/workflows/node.yml@main + with: + range: '>= 10' + type: minors + command: npm run tests-only + + node: + name: 'node >= 10' + needs: [tests] + runs-on: ubuntu-latest + steps: + - run: true diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml new file mode 100644 index 0000000..1818191 --- /dev/null +++ b/.github/workflows/rebase.yml @@ -0,0 +1,22 @@ +name: Automatic Rebase + +on: [pull_request_target] + +permissions: + contents: read + +jobs: + _: + permissions: + contents: write # for ljharb/rebase to push code to rebase + pull-requests: read # for ljharb/rebase to get info about PR + + name: "Automatic Rebase" + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: ljharb/rebase@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/require-allow-edits.yml b/.github/workflows/require-allow-edits.yml new file mode 100644 index 0000000..a685b8a --- /dev/null +++ b/.github/workflows/require-allow-edits.yml @@ -0,0 +1,18 @@ +name: Require “Allow Edits” + +on: [pull_request_target] + +permissions: + contents: read + +jobs: + _: + permissions: + pull-requests: read # for ljharb/require-allow-edits to check 'allow edits' on PR + + name: "Require “Allow Edits”" + + runs-on: ubuntu-latest + + steps: + - uses: ljharb/require-allow-edits@main diff --git a/.gitignore b/.gitignore index 5829e8e..5d47dca 100644 --- a/.gitignore +++ b/.gitignore @@ -133,3 +133,5 @@ dist npm-shrinkwrap.json package-lock.json yarn.lock + +.npmignore diff --git a/.npmrc b/.npmrc index 43c97e7..eacea13 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,3 @@ package-lock=false +allow-same-version=true +message=v%s diff --git a/.nycrc b/.nycrc new file mode 100644 index 0000000..1826526 --- /dev/null +++ b/.nycrc @@ -0,0 +1,13 @@ +{ + "all": true, + "check-coverage": false, + "reporter": ["text-summary", "text", "html", "json"], + "lines": 86, + "statements": 85.93, + "functions": 82.43, + "branches": 76.06, + "exclude": [ + "coverage", + "test" + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..03a962f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). diff --git a/LICENSE b/LICENSE index f82f389..b4213ac 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Jordan Harband +Copyright (c) 2023 Jordan Harband Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index f3059a7..9214292 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,43 @@ -# data-view-buffer +# data-view-buffer [![Version Badge][npm-version-svg]][package-url] + +[![github actions][actions-image]][actions-url] +[![coverage][codecov-image]][codecov-url] +[![License][license-image]][license-url] +[![Downloads][downloads-image]][downloads-url] + +[![npm badge][npm-badge-png]][package-url] + Get the ArrayBuffer out of a DataView, robustly. + +This will work in node <= 0.10 and < 0.11.4, where there's no prototype accessor, only a nonconfigurable own property. +It will also work in modern engines where `DataView.prototype.buffer` has been deleted after this module has loaded. + +## Example + +```js +const dataViewBuffer = require('data-view-buffer'); +const assert = require('assert'); + +const ab = new ArrayBuffer(0); +const dv = new DataView(ab); +assert.equal(dataViewBuffer(dv), ab); +``` + +## Tests +Simply clone the repo, `npm install`, and run `npm test` + +[package-url]: https://npmjs.org/package/data-view-buffer +[npm-version-svg]: https://versionbadg.es/ljharb/data-view-buffer.svg +[deps-svg]: https://david-dm.org/ljharb/data-view-buffer.svg +[deps-url]: https://david-dm.org/ljharb/data-view-buffer +[dev-deps-svg]: https://david-dm.org/ljharb/data-view-buffer/dev-status.svg +[dev-deps-url]: https://david-dm.org/ljharb/data-view-buffer#info=devDependencies +[npm-badge-png]: https://nodei.co/npm/data-view-buffer.png?downloads=true&stars=true +[license-image]: https://img.shields.io/npm/l/data-view-buffer.svg +[license-url]: LICENSE +[downloads-image]: https://img.shields.io/npm/dm/data-view-buffer.svg +[downloads-url]: https://npm-stat.com/charts.html?package=data-view-buffer +[codecov-image]: https://codecov.io/gh/ljharb/data-view-buffer/branch/main/graphs/badge.svg +[codecov-url]: https://app.codecov.io/gh/ljharb/data-view-buffer/ +[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/data-view-buffer +[actions-url]: https://github.com/ljharb/data-view-buffer/actions diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..36a9397 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,4 @@ +declare function dataViewBuffer(value: DataView): ArrayBuffer; +declare function dataViewBuffer(value: unknown): never; + +export = dataViewBuffer; \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..393d792 --- /dev/null +++ b/index.js @@ -0,0 +1,21 @@ +'use strict'; + +var GetIntrinsic = require('get-intrinsic'); + +var $TypeError = GetIntrinsic('%TypeError%'); + +var callBound = require('call-bind/callBound'); + +var $dataViewBuffer = callBound('DataView.prototype.buffer', true); + +var isDataView = require('is-data-view'); + +// node <= 0.10, < 0.11.4 has a nonconfigurable own property instead of a prototype getter +/** @type {import('.')} */ +module.exports = $dataViewBuffer || function dataViewBuffer(x) { + if (!isDataView(x)) { + throw new $TypeError('not a DataView'); + } + + return x.buffer; +}; diff --git a/package.json b/package.json index f52a80a..7efda6f 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,24 @@ ".": "./index.js", "./package.json": "./package.json" }, + "types": "./index.d.ts", + "sideEffects": false, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "prepack": "npmignore --auto --commentLines=autogenerated", + "prepublishOnly": "safe-publish-latest", + "prepublish": "not-in-publish || npm run prepublishOnly", + "prelint": "evalmd README.md", + "lint": "eslint --ext=js,mjs .", + "postlint": "tsc -p .", + "pretest": "npm run lint", + "tests-only": "nyc tape 'test/**/*.js'", + "test": "npm run tests-only", + "posttest": "aud --production", + "version": "auto-changelog && git add CHANGELOG.md", + "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" }, "repository": { "type": "git", @@ -26,5 +42,48 @@ "bugs": { "url": "https://github.com/ljharb/data-view-buffer/issues" }, - "homepage": "https://github.com/ljharb/data-view-buffer#readme" + "homepage": "https://github.com/ljharb/data-view-buffer#readme", + "dependencies": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "is-data-view": "^1.0.1" + }, + "devDependencies": { + "@ljharb/eslint-config": "^21.1.0", + "@types/call-bind": "^1.0.5", + "@types/es-value-fixtures": "^1.4.4", + "@types/for-each": "^0.3.3", + "@types/get-intrinsic": "^1.2.2", + "@types/object-inspect": "^1.8.4", + "@types/tape": "^5.6.4", + "aud": "^2.0.4", + "auto-changelog": "^2.4.0", + "es-value-fixtures": "^1.4.2", + "eslint": "=8.8.0", + "evalmd": "^0.0.19", + "for-each": "^0.3.3", + "in-publish": "^2.0.1", + "npmignore": "^0.3.1", + "nyc": "^10.3.2", + "object-inspect": "^1.13.1", + "safe-publish-latest": "^2.0.0", + "tape": "^5.7.4", + "typescript": "next" + }, + "engines": { + "node": ">= 0.4" + }, + "auto-changelog": { + "output": "CHANGELOG.md", + "template": "keepachangelog", + "unreleased": false, + "commitLimit": false, + "backfillLimit": false, + "hideCredit": true + }, + "publishConfig": { + "ignore": [ + ".github/workflows" + ] + } } diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000..50d0eeb --- /dev/null +++ b/test/index.js @@ -0,0 +1,31 @@ +'use strict'; + +var test = require('tape'); +var forEach = require('for-each'); +var v = require('es-value-fixtures'); +var inspect = require('object-inspect'); + +var dataViewBuffer = require('../'); + +test('dataViewBuffer', function (t) { + forEach( + // @ts-expect-error TS sucks at [].concat + // eslint-disable-next-line no-extra-parens + /** @type {[...typeof v.primitives, ...typeof v.objects]} */ ([].concat(v.primitives, v.objects)), + function (nonDV) { + t['throws'](function () { dataViewBuffer(nonDV); }, TypeError, inspect(nonDV) + ' is not a DataView'); + } + ); + + t.test('DataView', { skip: typeof DataView !== 'function' }, function (st) { + var ab = new ArrayBuffer(1); + var dv = new DataView(ab); + + st.equal(dataViewBuffer(dv), ab, inspect(dv) + ' has the same buffer originally passed to the DataView'); + st.equal(dataViewBuffer(dv), dv.buffer, inspect(dv) + ' has the same buffer as its own buffer property'); + + st.end(); + }); + + t.end(); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..fdfa155 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,50 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Projects */ + + /* Language and Environment */ + "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": ["types"], /* Specify multiple folders that act like `./node_modules/@types`. */ + "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + + /* JavaScript Support */ + "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + + /* Emit */ + "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + "declarationMap": true, /* Create sourcemaps for d.ts files. */ + "noEmit": true, /* Disable emitting files from a compilation. */ + + /* Interop Constraints */ + "allowSyntheticDefaultImports": true, /* Allow `import x from y` when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + + /* Completeness */ + // "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "exclude": [ + "coverage", + "test/list-exports" + ], +}