diff --git a/.github/dependabot.yml b/.github/dependabot.yml index dfa7fa6..35d66ca 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,5 +9,5 @@ updates: - package-ecosystem: "npm" directory: "/" schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 10 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d2c109e..f9fae55 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,6 @@ on: push: branches: - main - - master - next - 'v*' paths-ignore: @@ -17,8 +16,10 @@ on: jobs: test: + permissions: + contents: write + pull-requests: write uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5 with: license-check: true lint: true - node-versions: '["16", "18", "20", "22"]' diff --git a/.github/workflows/package-manager-ci.yml b/.github/workflows/package-manager-ci.yml index 1ea2c6d..c6d598e 100644 --- a/.github/workflows/package-manager-ci.yml +++ b/.github/workflows/package-manager-ci.yml @@ -4,7 +4,6 @@ on: push: branches: - main - - master - next - 'v*' paths-ignore: @@ -17,4 +16,6 @@ on: jobs: test: + permissions: + contents: read uses: fastify/workflows/.github/workflows/plugins-ci-package-manager.yml@v5 diff --git a/README.md b/README.md index 0a4eaaa..e613e0e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![NPM version](https://img.shields.io/npm/v/fast-content-type-parse.svg?style=flat)](https://www.npmjs.com/package/fast-content-type-parse) [![NPM downloads](https://img.shields.io/npm/dm/fast-content-type-parse.svg?style=flat)](https://www.npmjs.com/package/fast-content-type-parse) -[![CI](https://github.com/fastify/fast-content-type-parse/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/fastify/fast-content-type-parse/actions/workflows/ci.yml) +[![CI](https://github.com/fastify/fast-content-type-parse/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/fast-content-type-parse/actions/workflows/ci.yml) [![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard) [![Security Responsible Disclosure](https://img.shields.io/badge/Security-Responsible%20Disclosure-yellow.svg)](https://github.com/fastify/.github/blob/main/SECURITY.md) diff --git a/package.json b/package.json index c090df9..52c9f99 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fast-content-type-parse", - "version": "2.0.1", + "version": "3.0.0", "description": "Parse HTTP Content-Type header according to RFC 7231", "main": "index.js", "type": "commonjs", @@ -11,7 +11,7 @@ "lint:fix": "eslint --fix", "test": "npm run test:unit && npm run test:typescript", "test:typescript": "tsd", - "test:unit": "tap" + "test:unit": "c8 --100 node --test" }, "keywords": [ "content-type", @@ -61,10 +61,10 @@ "@fastify/pre-commit": "^2.1.0", "benchmark": "^2.1.4", "busboy": "^1.6.0", + "c8": "^10.1.3", "content-type": "^1.0.4", "eslint": "^9.17.0", "neostandard": "^0.12.0", - "tap": "^19.2.5", "tsd": "^0.31.0" }, "pre-commit": [ diff --git a/test/index.test.js b/test/index.test.js index 5c5932b..ecc314f 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,6 +1,6 @@ 'use strict' -const { test } = require('tap') +const { test } = require('node:test') const { parse, safeParse } = require('..') const invalidTypes = [ @@ -17,232 +17,232 @@ const invalidTypes = [ 'text/plain,wrong' ] -test('parse', function (t) { +test('parse', async function (t) { t.plan(13 + invalidTypes.length) - t.test('should parse basic type', function (t) { + await t.test('should parse basic type', function (t) { t.plan(1) const type = parse('text/html') - t.strictSame(type.type, 'text/html') + t.assert.deepStrictEqual(type.type, 'text/html') }) - t.test('should parse with suffix', function (t) { + await t.test('should parse with suffix', function (t) { t.plan(1) const type = parse('image/svg+xml') - t.strictSame(type.type, 'image/svg+xml') + t.assert.deepStrictEqual(type.type, 'image/svg+xml') }) - t.test('should parse basic type with surrounding OWS', function (t) { + await t.test('should parse basic type with surrounding OWS', function (t) { t.plan(1) const type = parse(' text/html ') - t.strictSame(type.type, 'text/html') + t.assert.deepStrictEqual(type.type, 'text/html') }) - t.test('should parse parameters', function (t) { + await t.test('should parse parameters', function (t) { t.plan(2) const type = parse('text/html; charset=utf-8; foo=bar') - t.strictSame(type.type, 'text/html') - t.same(type.parameters, { + t.assert.deepStrictEqual(type.type, 'text/html') + t.assert.deepEqual(type.parameters, { charset: 'utf-8', foo: 'bar' }) }) - t.test('should parse parameters with extra LWS', function (t) { + await t.test('should parse parameters with extra LWS', function (t) { t.plan(2) const type = parse('text/html ; charset=utf-8 ; foo=bar') - t.strictSame(type.type, 'text/html') - t.same(type.parameters, { + t.assert.deepStrictEqual(type.type, 'text/html') + t.assert.deepEqual(type.parameters, { charset: 'utf-8', foo: 'bar' }) }) - t.test('should lower-case type', function (t) { + await t.test('should lower-case type', function (t) { t.plan(1) const type = parse('IMAGE/SVG+XML') - t.strictSame(type.type, 'image/svg+xml') + t.assert.deepStrictEqual(type.type, 'image/svg+xml') }) - t.test('should lower-case parameter names', function (t) { + await t.test('should lower-case parameter names', function (t) { t.plan(2) const type = parse('text/html; Charset=UTF-8') - t.strictSame(type.type, 'text/html') - t.same(type.parameters, { + t.assert.deepStrictEqual(type.type, 'text/html') + t.assert.deepEqual(type.parameters, { charset: 'UTF-8' }) }) - t.test('should unquote parameter values', function (t) { + await t.test('should unquote parameter values', function (t) { t.plan(2) const type = parse('text/html; charset="UTF-8"') - t.strictSame(type.type, 'text/html') - t.same(type.parameters, { + t.assert.deepStrictEqual(type.type, 'text/html') + t.assert.deepEqual(type.parameters, { charset: 'UTF-8' }) }) - t.test('should unquote parameter values with escapes', function (t) { + await t.test('should unquote parameter values with escapes', function (t) { t.plan(2) const type = parse('text/html; charset="UT\\F-\\\\\\"8\\""') - t.strictSame(type.type, 'text/html') - t.same(type.parameters, { + t.assert.deepStrictEqual(type.type, 'text/html') + t.assert.deepEqual(type.parameters, { charset: 'UTF-\\"8"' }) }) - t.test('should handle balanced quotes', function (t) { + await t.test('should handle balanced quotes', function (t) { t.plan(2) const type = parse('text/html; param="charset=\\"utf-8\\"; foo=bar"; bar=foo') - t.strictSame(type.type, 'text/html') - t.same(type.parameters, { + t.assert.deepStrictEqual(type.type, 'text/html') + t.assert.deepEqual(type.parameters, { param: 'charset="utf-8"; foo=bar', bar: 'foo' }) }) - invalidTypes.forEach(function (type) { - t.test('should throw on invalid media type ' + type, function (t) { + invalidTypes.forEach(async function (type) { + await t.test('should throw on invalid media type ' + type, function (t) { t.plan(1) - t.throws(parse.bind(null, type), 'invalid media type') + t.assert.throws(parse.bind(null, type), new TypeError('invalid media type')) }) }) - t.test('should throw on invalid parameter format', function (t) { + await t.test('should throw on invalid parameter format', function (t) { t.plan(3) - t.throws(parse.bind(null, 'text/plain; foo="bar'), 'invalid parameter format') - t.throws(parse.bind(null, 'text/plain; profile=http://localhost; foo=bar'), 'invalid parameter format') - t.throws(parse.bind(null, 'text/plain; profile=http://localhost'), 'invalid parameter format') + t.assert.throws(parse.bind(null, 'text/plain; foo="bar'), new TypeError('invalid parameter format')) + t.assert.throws(parse.bind(null, 'text/plain; profile=http://localhost; foo=bar'), new TypeError('invalid parameter format')) + t.assert.throws(parse.bind(null, 'text/plain; profile=http://localhost'), new TypeError('invalid parameter format')) }) - t.test('should require argument', function (t) { + await t.test('should require argument', function (t) { t.plan(1) // @ts-expect-error should reject non-strings - t.throws(parse.bind(null), 'argument header is required and must be a string') + t.assert.throws(parse.bind(null), new TypeError('argument header is required and must be a string')) }) - t.test('should reject non-strings', function (t) { + await t.test('should reject non-strings', function (t) { t.plan(1) // @ts-expect-error should reject non-strings - t.throws(parse.bind(null, 7), 'argument header is required and must be a string') + t.assert.throws(parse.bind(null, 7), new TypeError('argument header is required and must be a string')) }) }) -test('safeParse', function (t) { +test('safeParse', async function (t) { t.plan(13 + invalidTypes.length) - t.test('should safeParse basic type', function (t) { + await t.test('should safeParse basic type', function (t) { t.plan(1) const type = safeParse('text/html') - t.strictSame(type.type, 'text/html') + t.assert.deepStrictEqual(type.type, 'text/html') }) - t.test('should safeParse with suffix', function (t) { + await t.test('should safeParse with suffix', function (t) { t.plan(1) const type = safeParse('image/svg+xml') - t.strictSame(type.type, 'image/svg+xml') + t.assert.deepStrictEqual(type.type, 'image/svg+xml') }) - t.test('should safeParse basic type with surrounding OWS', function (t) { + await t.test('should safeParse basic type with surrounding OWS', function (t) { t.plan(1) const type = safeParse(' text/html ') - t.strictSame(type.type, 'text/html') + t.assert.deepStrictEqual(type.type, 'text/html') }) - t.test('should safeParse parameters', function (t) { + await t.test('should safeParse parameters', function (t) { t.plan(2) const type = safeParse('text/html; charset=utf-8; foo=bar') - t.strictSame(type.type, 'text/html') - t.same(type.parameters, { + t.assert.deepStrictEqual(type.type, 'text/html') + t.assert.deepEqual(type.parameters, { charset: 'utf-8', foo: 'bar' }) }) - t.test('should safeParse parameters with extra LWS', function (t) { + await t.test('should safeParse parameters with extra LWS', function (t) { t.plan(2) const type = safeParse('text/html ; charset=utf-8 ; foo=bar') - t.strictSame(type.type, 'text/html') - t.same(type.parameters, { + t.assert.deepStrictEqual(type.type, 'text/html') + t.assert.deepEqual(type.parameters, { charset: 'utf-8', foo: 'bar' }) }) - t.test('should lower-case type', function (t) { + await t.test('should lower-case type', function (t) { t.plan(1) const type = safeParse('IMAGE/SVG+XML') - t.strictSame(type.type, 'image/svg+xml') + t.assert.deepStrictEqual(type.type, 'image/svg+xml') }) - t.test('should lower-case parameter names', function (t) { + await t.test('should lower-case parameter names', function (t) { t.plan(2) const type = safeParse('text/html; Charset=UTF-8') - t.strictSame(type.type, 'text/html') - t.same(type.parameters, { + t.assert.deepStrictEqual(type.type, 'text/html') + t.assert.deepEqual(type.parameters, { charset: 'UTF-8' }) }) - t.test('should unquote parameter values', function (t) { + await t.test('should unquote parameter values', function (t) { t.plan(2) const type = safeParse('text/html; charset="UTF-8"') - t.strictSame(type.type, 'text/html') - t.same(type.parameters, { + t.assert.deepStrictEqual(type.type, 'text/html') + t.assert.deepEqual(type.parameters, { charset: 'UTF-8' }) }) - t.test('should unquote parameter values with escapes', function (t) { + await t.test('should unquote parameter values with escapes', function (t) { t.plan(2) const type = safeParse('text/html; charset="UT\\F-\\\\\\"8\\""') - t.strictSame(type.type, 'text/html') - t.same(type.parameters, { + t.assert.deepStrictEqual(type.type, 'text/html') + t.assert.deepEqual(type.parameters, { charset: 'UTF-\\"8"' }) }) - t.test('should handle balanced quotes', function (t) { + await t.test('should handle balanced quotes', function (t) { t.plan(2) const type = safeParse('text/html; param="charset=\\"utf-8\\"; foo=bar"; bar=foo') - t.strictSame(type.type, 'text/html') - t.same(type.parameters, { + t.assert.deepStrictEqual(type.type, 'text/html') + t.assert.deepEqual(type.parameters, { param: 'charset="utf-8"; foo=bar', bar: 'foo' }) }) - invalidTypes.forEach(function (type) { - t.test('should return dummyContentType on invalid media type ' + type, function (t) { + invalidTypes.forEach(async function (type) { + await t.test('should return dummyContentType on invalid media type ' + type, function (t) { t.plan(2) - t.equal(safeParse(type).type, '') - t.equal(Object.keys(safeParse(type).parameters).length, 0) + t.assert.deepStrictEqual(safeParse(type).type, '') + t.assert.deepStrictEqual(Object.keys(safeParse(type).parameters).length, 0) }) }) - t.test('should return dummyContentType on invalid parameter format', function (t) { + await t.test('should return dummyContentType on invalid parameter format', function (t) { t.plan(6) - t.equal(safeParse('text/plain; foo="bar').type, '') - t.equal(Object.keys(safeParse('text/plain; foo="bar').parameters).length, 0) + t.assert.deepStrictEqual(safeParse('text/plain; foo="bar').type, '') + t.assert.deepStrictEqual(Object.keys(safeParse('text/plain; foo="bar').parameters).length, 0) - t.equal(safeParse('text/plain; profile=http://localhost; foo=bar').type, '') - t.equal(Object.keys(safeParse('text/plain; profile=http://localhost; foo=bar').parameters).length, 0) + t.assert.deepStrictEqual(safeParse('text/plain; profile=http://localhost; foo=bar').type, '') + t.assert.deepStrictEqual(Object.keys(safeParse('text/plain; profile=http://localhost; foo=bar').parameters).length, 0) - t.equal(safeParse('text/plain; profile=http://localhost').type, '') - t.equal(Object.keys(safeParse('text/plain; profile=http://localhost').parameters).length, 0) + t.assert.deepStrictEqual(safeParse('text/plain; profile=http://localhost').type, '') + t.assert.deepStrictEqual(Object.keys(safeParse('text/plain; profile=http://localhost').parameters).length, 0) }) - t.test('should return dummyContentType on missing argument', function (t) { + await t.test('should return dummyContentType on missing argument', function (t) { t.plan(2) // @ts-expect-error should reject non-strings - t.equal(safeParse().type, '') + t.assert.deepStrictEqual(safeParse().type, '') // @ts-expect-error should reject non-strings - t.equal(Object.keys(safeParse().parameters).length, 0) + t.assert.deepStrictEqual(Object.keys(safeParse().parameters).length, 0) }) - t.test('should return dummyContentType on non-strings', function (t) { + await t.test('should return dummyContentType on non-strings', function (t) { t.plan(2) // @ts-expect-error should reject non-strings - t.equal(safeParse(null).type, '') + t.assert.deepStrictEqual(safeParse(null).type, '') // @ts-expect-error should reject non-strings - t.equal(Object.keys(safeParse(null).parameters).length, 0) + t.assert.deepStrictEqual(Object.keys(safeParse(null).parameters).length, 0) }) })