Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

publint

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

publint - npm Package Compare versions

Comparing version 0.1.10 to 0.1.11

1

index.d.ts

@@ -65,2 +65,3 @@ export type MessageType = 'suggestion' | 'warning' | 'error'

| BaseMessage<'USE_EXPORTS_BROWSER'>
| BaseMessage<'TYPES_NOT_EXPORTED', { typesFilePath: string }>

@@ -67,0 +68,0 @@ export interface Options {

2

package.json
{
"name": "publint",
"version": "0.1.10",
"version": "0.1.11",
"description": "Lint packaging errors",

@@ -5,0 +5,0 @@ "type": "module",

@@ -8,3 +8,4 @@ import {

createPromiseQueue,
getPublishedField
getPublishedField,
objectHasKeyNested
} from './utils.js'

@@ -53,11 +54,12 @@

/**
* @param {string} path
* @param {string[]} pkgPath
* @param {string[]} tryExtensions
* @param {string} path file path to read
* @param {string[]} [pkgPath] current path that tries to read this file.
* pass `undefined` to prevent error reporting if the file is missing.
* @param {string[]} tryExtensions list of extensions to try before giving up
* @returns {Promise<string | false>}
*/
async function readFile(path, pkgPath, tryExtensions = []) {
async function readFile(path, pkgPath = undefined, tryExtensions = []) {
try {
const content = await vfs.readFile(path)
if (_packedFiles && !_packedFiles.includes(path)) {
if (pkgPath && _packedFiles && !_packedFiles.includes(path)) {
fileNotPublished(pkgPath)

@@ -70,3 +72,3 @@ }

const content = await vfs.readFile(path + ext)
if (_packedFiles && !_packedFiles.includes(path)) {
if (pkgPath && _packedFiles && !_packedFiles.includes(path)) {
fileNotPublished(pkgPath)

@@ -77,8 +79,10 @@ }

}
messages.push({
code: 'FILE_DOES_NOT_EXIST',
args: { filePath: path },
path: pkgPath,
type: 'error'
})
if (pkgPath) {
messages.push({
code: 'FILE_DOES_NOT_EXIST',
args: { filePath: path },
path: pkgPath,
type: 'error'
})
}
return false

@@ -243,2 +247,4 @@ }

crawlExports(exports, exportsPkgPath)
// make sure types are exported for moduleResolution bundler
doCheckTypesExported()
} else {

@@ -500,2 +506,67 @@ // all files can be accessed. verify them all

}
function doCheckTypesExported() {
if (typeof exports === 'string') {
checkTypesExported()
} else if (typeof exports === 'object') {
const exportsKeys = Object.keys(exports)
if (exportsKeys.length === 0) return
// check if the `exports` directly map to condition keys (doesn't start with '.').
// if so, we work on it directly.
if (!exportsKeys[0].startsWith('.')) {
checkTypesExported()
}
// else this `exports` may have multiple export entrypoints, check for '.'
// TODO: check for other entrypoints
else if ('.' in exports) {
checkTypesExported('.')
}
}
}
/**
* @param {string | undefined} exportsRootKey
*/
function checkTypesExported(exportsRootKey = undefined) {
promiseQueue.push(async () => {
const typesFilePath = await findTypesFilePath(exportsRootKey)
const exportsRootValue = exportsRootKey
? exports[exportsRootKey]
: exports
if (
typesFilePath && // check has existing types?
(typeof exportsRootValue === 'string' || // if the root value is just a string, types is not exported
!objectHasKeyNested(exportsRootValue, 'types')) // else if object, check has types condition
) {
messages.push({
code: 'TYPES_NOT_EXPORTED',
args: { typesFilePath },
path: exportsRootKey
? exportsPkgPath.concat(exportsRootKey)
: exportsPkgPath,
type: 'warning'
})
}
})
}
/**
* @param {string | undefined} exportsKey
*/
async function findTypesFilePath(exportsKey) {
let typesFilePath
if (exportsKey == null || exportsKey === '.') {
const [types] = getPublishedField(rootPkg, 'types')
if (types) {
typesFilePath = types
} else if (await readFile(vfs.pathJoin(pkgDir, './index.d.ts'))) {
typesFilePath = './index.d.ts'
}
} else {
// TODO: handle nested exports key
}
return typesFilePath
}
}

@@ -71,2 +71,12 @@ import c from 'picocolors'

return `${c.bold('pkg.browser')} can be refactored to use ${c.bold('pkg.exports')} and the ${c.bold('browser')} condition instead to declare browser-specific exports. (This will be a breaking change)`
case 'TYPES_NOT_EXPORTED': {
let target = fp(m.path)
if (target.endsWith('.exports')) {
target = 'The library'
} else {
target = c.bold(target)
}
// prettier-ignore
return `${target} has types at ${c.bold(m.args.typesFilePath)} but it is not exported from ${c.bold('pkg.exports')}. Consider adding it to ${c.bold(fp(m.path) + '.types')} to be compatible with TypeScript's ${c.bold('"moduleResolution": "bundler"')} compiler option.`
}
default:

@@ -73,0 +83,0 @@ return

@@ -240,1 +240,14 @@ /**

}
/**
* @param {Record<string, any>} obj
* @param {string} key
*/
export function objectHasKeyNested(obj, key) {
for (const k in obj) {
if (k === key) return true
if (typeof obj[k] === 'object' && objectHasKeyNested(obj[k], key))
return true
}
return false
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc