diff --git a/.eslintrc.local.cjs b/.eslintrc.local.cjs index cff40b4..010aa7a 100644 --- a/.eslintrc.local.cjs +++ b/.eslintrc.local.cjs @@ -5,10 +5,4 @@ module.exports = { typescript: {}, }, }, - overrides: [{ - files: ['test/fixtures/*.ts'], - rules: { - 'max-len': 0, - }, - }], } diff --git a/test/fixtures.ts b/test/fixtures.ts index 8ec7ed9..4eab390 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -5,13 +5,7 @@ import t from 'tap' const REGISTRY = 'https://registry.npmjs.org' -type FixtureEntry = { - name: string; - version?: string; - manifestFormat?: boolean; -}; - -const FIXTURES: FixtureEntry[] = [ +const FIXTURES = [ { name: 'not-licensed', version: '1.0.0' }, { name: 'not-licensed' }, { name: 'tiny-tarball', version: '1.0.0' }, @@ -40,63 +34,55 @@ t.test('fixtures', async (t) => { rootDir: 'fixtures', }, include: ['fixtures'], - }, null, 2), - fixtures: Object.fromEntries(Object.entries(fixtures).map(([k, v]) => [ - k, - `import type * as npmTypes from '../../../../types/index.d.ts'\n` + - `export const metadata: npmTypes.${v}`, - ])), + }), + fixtures: Object.fromEntries( + Object.entries(fixtures).map(([k, v]) => [ + k, + `import type * as npmTypes from '../../../../types/index.d.ts'\n` + + `export const metadata: npmTypes.${v}`, + ]) + ), }) - t.test('snapshots', async t => { + t.test('snapshots', async (t) => { for (const [k, v] of Object.entries(fixtures)) { t.matchSnapshot(v, k) } }) - t.test('tsc', async t => new Promise(res => { - const proc = spawn( - resolve(root, './node_modules/.bin/tsc'), - ['--noEmit', '-p', './tsconfig-test.json'], - { cwd: dir } - ) - let output = '' - proc.stdout.on('data', (d) => output += d.toString()) - proc.on('close', (code) => { - if (code === 0) { - t.ok(true, 'tsc works') - } else { - t.fail(`tsc failed with code ${code} and message:\n${output}`) - } - res() + t.test('tsc', (t) => + new Promise((res) => { + const proc = spawn( + resolve(root, './node_modules/.bin/tsc'), + ['--noEmit', '-p', './tsconfig-test.json'], + { cwd: dir } + ) + let output = '' + proc.stdout.on('data', (d) => (output += d.toString())) + proc.on('close', (code) => { + t.equal(code, 0, output) + res() + }) }) - })) + ) }) async function getFixtures () { const fixtures: Record = {} for (const { name, version } of FIXTURES) { - const fixtureName = version ? `${name}@${version}` : name + const fixtureName = `${name}${version ? `@${version}` : ''}` - for (const manifestFormat of [false, true]) { - // Manifest format is only available for Packument documents, not - // PackumentVersions - if (manifestFormat && version) { + for (const corgi of [false, true]) { + // Corgis are only available for Packument documents, not PackumentVersions + if (corgi && version) { continue } - const fixturePath = manifestFormat ? `${fixtureName}.manifest.ts` : `${fixtureName}.ts` - const tsType = manifestFormat - ? (version ? 'ManifestVersion' : 'Manifest') - : version ? 'PackumentVersion' : 'Packument' - - const pkg = await registryFetch({ - name, - version, - manifestFormat, - }) + const pkg = await registryFetch(name, version, corgi) + const fixturePath = `${fixtureName}${corgi ? '.manifest' : ''}.ts` + const tsType = `${corgi ? 'Manifest' : 'Packument'}${version ? 'Version' : ''}` fixtures[fixturePath] = `${tsType} = ${JSON.stringify(pkg, null, 2)}` } } @@ -108,19 +94,14 @@ async function getFixtures () { // intended to document the types returned by registry requests. Fetching URLs // directly here insures there's no manipulation of the data between the // registry and the fixture. -async function registryFetch ({ name, version, manifestFormat }: FixtureEntry) { - const url = new URL(version ? `/${name}/${version}` : `/${name}`, REGISTRY) - - const headers: Record = {} - if (manifestFormat) { - headers.Accept = 'application/vnd.npm.install-v1+json' - } - - const res = await fetch(url, { headers }) +async function registryFetch (name: string, version?: string, corgi?: boolean) { + const res = await fetch(`${REGISTRY}/${name}${version ? `/${version}` : ''}`, { + headers: corgi ? { Accept: 'application/vnd.npm.install-v1+json' } : {}, + }) if (!res.ok) { - throw new Error(`Fetch failed: ${url} (status: ${res.status})`) + throw new Error(`Fetch failed: ${res.url} (status: ${res.status})`) } - return await res.json() + return res.json() } diff --git a/types/index.d.ts b/types/index.d.ts index ec83495..754e032 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,18 +1,18 @@ interface Contact { - email?: string; - url?: string; - name: string; + email?: string + url?: string + name: string } interface Signature { - keyid: string; - sig: string; + keyid: string + sig: string } interface Repository { - directory?: string; - type?: string; - url: string; + directory?: string + type?: string + url: string } /** @@ -21,117 +21,117 @@ interface Repository { */ interface Dist { // Deprecated? (ref: found in uuid@0.0.2) - bin?: Record; + bin?: Record /** * the number of files in the tarball. this is on most packages published >= 2018 */ - fileCount?: number; + fileCount?: number /** * subresource integrity string! `npm view ssri` * https://w3c.github.io/webappsec-subresource-integrity/ */ - integrity?: string; + integrity?: string /** * PGP signature for the tarball */ - 'npm-signature'?: string; + 'npm-signature'?: string /** * the sha1 sum of the tarball */ - shasum: string; + shasum: string /** * Out-of-date blog post about this, below. (Says this is "npm-signature", but * that's not what the registry provides). * https://blog.npmjs.org/post/172999548390/new-pgp-machinery */ - signatures: Signature[]; + signatures: Signature[] /** * the url to the tarball for the package version */ - tarball: string; + tarball: string /** * the unpacked size of the files in the tarball. >= 2018 */ - unpackedSize?: number; + unpackedSize?: number } // this is in the tarball or the project. it really could have anything in it. export interface PackageJSON { - author?: Contact | string; - bin?: Record; - browser?: Record | string; - bugs?: Omit | string; - bundledDependencies?: string[] | boolean; - bundleDependencies?: string[] | boolean; - config?: Record; - contributors?: Contact[] | string[]; - cpu?: string[]; - dependencies?: Record; - description?: string; - devDependencies?: Record; - directories?: Record; - engines?: Record; - files?: string[]; - homepage?: string; - keywords?: string[]; - license?: string; - main?: string; - man?: string | string[]; - name: string; - optionalDependencies?: Record; - os?: string[]; - peerDependencies?: Record; - private?: boolean; - publishConfig?: Record; - repository?: Repository | string; - scripts?: Record; - types?: string; - version: string; - - [field: string]: unknown; + author?: Contact | string + bin?: Record + browser?: Record | string + bugs?: Omit | string + bundledDependencies?: string[] | boolean + bundleDependencies?: string[] | boolean + config?: Record + contributors?: Contact[] | string[] + cpu?: string[] + dependencies?: Record + description?: string + devDependencies?: Record + directories?: Record + engines?: Record + files?: string[] + homepage?: string + keywords?: string[] + license?: string + main?: string + man?: string | string[] + name: string + optionalDependencies?: Record + os?: string[] + peerDependencies?: Record + private?: boolean + publishConfig?: Record + repository?: Repository | string + scripts?: Record + types?: string + version: string + + [field: string]: unknown } export interface PackumentVersion extends PackageJSON { // bugs, author, contributors, and repository can be simple strings in // package.json, but not in registry metadata. - bugs?: Omit; - author?: Contact; + bugs?: Omit + author?: Contact // ref: Record type found in uuid@1.4.1 et al - browser?: Record; - contributors?: Contact[]; - repository?: Repository; - gitHead?: string; - _id: string; - _npmVersion: string; + browser?: Record + contributors?: Contact[] + repository?: Repository + gitHead?: string + _id: string + _npmVersion: string // Optional (ref: not defined in uuid@1.4.0) - _nodeVersion?: string; - - _npmUser?: Contact; - maintainers?: Contact[]; - dist: Dist; - readme?: string; - readmeFilename?: string; - _hasShrinkwrap?: boolean; - deprecated?: string; + _nodeVersion?: string + + _npmUser?: Contact + maintainers?: Contact[] + dist: Dist + readme?: string + readmeFilename?: string + _hasShrinkwrap?: boolean + deprecated?: string } // this is what you get from the npm api. export type Packument = { - _cached?: boolean; - _id: string; - _rev: string; - 'dist-tags': { latest?: string } & Record; - time: { modified: string; created: string } & Record; - users?: Record; - versions: Record; + _cached?: boolean + _id: string + _rev: string + 'dist-tags': { latest?: string } & Record + time: { modified: string; created: string } & Record + users?: Record + versions: Record // The following fields are hoisted to the top-level of the packument from the latest version published. } & Pick< @@ -148,7 +148,7 @@ export type Packument = { | 'readme' | 'readmeFilename' | 'repository' ->; +> export type ManifestVersion = Pick< PackumentVersion, @@ -166,7 +166,7 @@ export type ManifestVersion = Pick< | 'optionalDependencies' | 'peerDependencies' | 'version' ->; +> /** * abbreviated metadata format (aka corgi) @@ -176,6 +176,6 @@ export type ManifestVersion = Pick< * `application/vnd.npm.install-v1+json` */ export type Manifest = { - modified: string; - versions: Record; -} & Pick; + modified: string + versions: Record +} & Pick