Skip to content
This repository has been archived by the owner on May 4, 2024. It is now read-only.

feat: add types lookup #103

Merged
merged 12 commits into from
Sep 1, 2021
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,9 @@ When installing locally, npm links bins into `node_modules/.bin`, which
is in the `PATH` environ when npm runs scripts. When
installing globally, they are linked into `{prefix}/bin`, which is
presumably in the `PATH` environment variable.

### `types` field

If you do not have a `types` field, then it will check if a
corresponding `*.d.ts` file exists for your package entry file and add
it to the `package.json`.
22 changes: 22 additions & 0 deletions read-json.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ readJson.extraSet = [
mans,
bins,
githead,
fillTypes,
]

var typoWarned = {}
Expand Down Expand Up @@ -518,6 +519,27 @@ function final (file, data, log, strict, cb) {
})
}

function fillTypes (file, data, cb) {
var index = data.main ? data.main : 'index.js'
if (data.exports && typeof data.exports === 'string') {
index = data.exports
}
if (data.exports && data.exports['.']) {
index = data.exports['.']
}

var extless =
path.join(path.dirname(index), path.basename(index, path.extname(index)))
var dts = `./${extless}.d.ts`
var dtsPath = path.join(path.dirname(file), dts)
var hasDTSFields = 'types' in data || 'typings' in data
if (!hasDTSFields && fs.existsSync(dtsPath)) {
data.types = dts
}

cb(null, data)
}

function makePackageId (data) {
var name = cleanString(data.name)
var ver = cleanString(data.version)
Expand Down
100 changes: 100 additions & 0 deletions test/fill-types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
const t = require('tap')
const read = require('../')
const { resolve } = require('path')

t.test('adds types with a custom main field', t => {
const fixture = resolve(__dirname, 'fixtures/types/custom-dts/one-new-field.json')
read(fixture, (er, data) => {
if (er) {
throw er
}
t.match(data, {
main: './custom-path.js',
types: './custom-path.d.ts',
})
t.end()
})
})

t.test('handles the inferred index.js', t => {
const fixture = resolve(__dirname, 'fixtures/types/default-dts/inferred.json')
read(fixture, (er, data) => {
if (er) {
throw er
}
t.match(data, {
types: './index.d.ts',
})
t.end()
})
})

t.test('handles subpaths and starting with ./', t => {
const fixture = resolve(__dirname, 'fixtures/types/subpaths/subpath.json')
read(fixture, (er, data) => {
if (er) {
throw er
}
t.match(data, {
main: './a/b/c.js',
types: './a/b/c.d.ts',
})
t.end()
})
})

t.test('handles not overwriting existing fields', t => {
const fixture = resolve(__dirname, 'fixtures/types/with-field/has-types-field.json')
read(fixture, (er, data) => {
if (er) {
throw er
}
t.match(data, {
types: '@types/express',
})
t.end()
})
})

t.test('does not add types fields if not present', t => {
const fixture = resolve(__dirname, 'fixtures/readmes/package.json')
read(fixture, (er, data) => {
if (er) {
throw er
}
t.notOk(data.types, 'types field should not be added')
t.end()
})
})

// https://nodejs.org/api/esm.html#esm_writing_dual_packages_while_avoiding_or_minimizing_hazards

t.test('handles esm modules', t => {
const fixture = resolve(__dirname, 'fixtures/types/esmodule-exports/exports.json')
read(fixture, (er, data) => {
if (er) {
throw er
}
t.match(data, {
types: './a/b/c.d.ts',
})

t.end()
})
})

// https://nodejs.org/api/esm.html#esm_exports_sugar

t.test('handles esm modules with sugared exports', t => {
const fixture = resolve(__dirname, 'fixtures/types/esmodule-exports-sugar/sugar.json')
read(fixture, (er, data) => {
if (er) {
throw er
}
t.match(data, {
types: './a/b.d.ts',
})

t.end()
})
})
1 change: 1 addition & 0 deletions test/fixtures/types/custom-dts/custom-path.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Empty because implementation isn't important
5 changes: 5 additions & 0 deletions test/fixtures/types/custom-dts/one-new-field.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "https://json.schemastore.org/package",
"name": "one-new-field",
"main": "./custom-path.js"
}
1 change: 1 addition & 0 deletions test/fixtures/types/default-dts/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Empty because implementation isn't important
4 changes: 4 additions & 0 deletions test/fixtures/types/default-dts/inferred.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://json.schemastore.org/package",
"name": "no-main"
}
Empty file.
Empty file.
3 changes: 3 additions & 0 deletions test/fixtures/types/esmodule-exports-sugar/sugar.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"exports": "./a/b.js"
}
Empty file.
Empty file.
7 changes: 7 additions & 0 deletions test/fixtures/types/esmodule-exports/exports.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "module",
"exports": {
".": "./a/b/c.js",
"./a": "./a.mjs"
}
}
Empty file.
Empty file.
5 changes: 5 additions & 0 deletions test/fixtures/types/subpaths/subpath.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "https://json.schemastore.org/package",
"name": "subpaths",
"main": "./a/b/c.js"
}
5 changes: 5 additions & 0 deletions test/fixtures/types/with-field/has-types-field.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "https://json.schemastore.org/package",
"name": "has-types-reference",
"types": "@types/express"
}
1 change: 1 addition & 0 deletions test/fixtures/types/with-field/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Empty because implementation isn't important