🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

publint

Package Overview
Dependencies
Maintainers
1
Versions
55
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.3.15
to
0.3.16
+4
-4
package.json
{
"name": "publint",
"version": "0.3.15",
"version": "0.3.16",
"description": "Lint packaging errors",

@@ -41,3 +41,3 @@ "type": "module",

"dependencies": {
"package-manager-detector": "^1.3.0",
"package-manager-detector": "^1.6.0",
"picocolors": "^1.1.1",

@@ -49,5 +49,5 @@ "sade": "^1.8.1",

"@types/prompts": "^2.4.9",
"fs-fixture": "^2.8.1",
"fs-fixture": "^2.11.0",
"prompts": "^2.4.2",
"vitest": "^3.2.4"
"vitest": "^4.0.15"
},

@@ -54,0 +54,0 @@ "scripts": {

@@ -16,8 +16,4 @@ #!/usr/bin/env node

.version(version)
.option('--level', `Level of messages to log ('suggestion' | 'warning' | 'error')`, 'suggestion')
.option(
'--level',
`Level of messages to log ('suggestion' | 'warning' | 'error')`,
'suggestion',
)
.option(
'--pack',

@@ -30,7 +26,5 @@ `Package manager to use for packing ('auto' | 'npm' | 'yarn' | 'pnpm' | 'bun' | false)`,

cli
.command(
'run [path]',
'Lint a directory or tarball file path (defaults to current directory)',
{ default: true },
)
.command('run [path]', 'Lint a directory or tarball file path (defaults to current directory)', {
default: true,
})
.action(async (runPath, opts) => {

@@ -77,5 +71,3 @@ opts = normalizeOpts(opts)

console.log(
`Running ${c.bold(`publint v${version}`)} for ${c.bold(pkgName)}...`,
)
console.log(`Running ${c.bold(`publint v${version}`)} for ${c.bold(pkgName)}...`)

@@ -98,6 +90,3 @@ const { messages, pkg } = await publint({

cli
.command(
'deps [dir]',
'Lint dependencies declared in package.json (deprecated)',
)
.command('deps [dir]', 'Lint dependencies declared in package.json (deprecated)')
.option('-P, --prod', 'Only check dependencies')

@@ -125,5 +114,3 @@ .option('-D, --dev', 'Only check devDependencies')

console.log(
`Running ${c.bold(`publint v${version}`)} for ${c.bold(pkgName)} deps...`,
)
console.log(`Running ${c.bold(`publint v${version}`)} for ${c.bold(pkgName)} deps...`)

@@ -247,5 +234,3 @@ /** @type {string[]} */

logs.push(c.bold(c.red('Errors:')))
errors.forEach((m, i) =>
logs.push(c.dim(`${i + 1}. `) + formatMessage(m, pkgJson)),
)
errors.forEach((m, i) => logs.push(c.dim(`${i + 1}. `) + formatMessage(m, pkgJson)))
process.exitCode = 1

@@ -257,5 +242,3 @@ }

logs.push(c.bold(c.yellow('Warnings:')))
warnings.forEach((m, i) =>
logs.push(c.dim(`${i + 1}. `) + formatMessage(m, pkgJson)),
)
warnings.forEach((m, i) => logs.push(c.dim(`${i + 1}. `) + formatMessage(m, pkgJson)))
}

@@ -266,5 +249,3 @@

logs.push(c.bold(c.blue('Suggestions:')))
suggestions.forEach((m, i) =>
logs.push(c.dim(`${i + 1}. `) + formatMessage(m, pkgJson)),
)
suggestions.forEach((m, i) => logs.push(c.dim(`${i + 1}. `) + formatMessage(m, pkgJson)))
}

@@ -271,0 +252,0 @@

@@ -23,7 +23,4 @@ export type MessageType = 'suggestion' | 'warning' | 'error'

export type Message =
| BaseMessage<'IMPLICIT_INDEX_JS_INVALID_FORMAT', { actualFormat: string; expectFormat: string }>
| BaseMessage<
'IMPLICIT_INDEX_JS_INVALID_FORMAT',
{ actualFormat: string; expectFormat: string }
>
| BaseMessage<
'FILE_INVALID_FORMAT',

@@ -48,6 +45,3 @@ {

>
| BaseMessage<
'FILE_INVALID_JSX_EXTENSION',
{ actualExtension: string; globbedFilePath?: string }
>
| BaseMessage<'FILE_INVALID_JSX_EXTENSION', { actualExtension: string; globbedFilePath?: string }>
| BaseMessage<'FILE_DOES_NOT_EXIST'>

@@ -119,6 +113,3 @@ | BaseMessage<'FILE_NOT_PUBLISHED'>

| {
type:
| 'invalid-string-shorthand'
| 'invalid-git-url'
| 'deprecated-github-git-protocol'
type: 'invalid-string-shorthand' | 'invalid-git-url' | 'deprecated-github-git-protocol'
}

@@ -125,0 +116,0 @@ | {

@@ -35,2 +35,4 @@ import {

hasEsModuleAndExportsDefault,
hasCustomCondition,
getConditionsFromCurrentPath,
} from './utils.js'

@@ -90,6 +92,3 @@

const internalPath = vfs.pathJoin(pkgDir, p)
if (
_packedFiles &&
_packedFiles.every((f) => !f.startsWith(internalPath))
) {
if (_packedFiles && _packedFiles.every((f) => !f.startsWith(internalPath))) {
continue

@@ -190,6 +189,3 @@ }

}
if (
expectFormat === 'CJS' &&
hasEsModuleAndExportsDefault(defaultContent)
) {
if (expectFormat === 'CJS' && hasEsModuleAndExportsDefault(defaultContent)) {
messages.push({

@@ -215,6 +211,3 @@ code: 'CJS_WITH_ESMODULE_DEFAULT_EXPORT',

const mainPath = vfs.pathJoin(pkgDir, main)
const mainContent = await readFile(mainPath, mainPkgPath, [
'.js',
'/index.js',
])
const mainContent = await readFile(mainPath, mainPkgPath, ['.js', '/index.js'])
if (mainContent === false) return

@@ -225,7 +218,3 @@ if (hasInvalidJsxExtension(main, mainPkgPath)) return

const expectFormat = await getFilePathFormat(mainPath, vfs)
if (
actualFormat !== expectFormat &&
actualFormat !== 'unknown' &&
actualFormat !== 'mixed'
) {
if (actualFormat !== expectFormat && actualFormat !== 'unknown' && actualFormat !== 'mixed') {
const actualExtension = vfs.getExtName(mainPath)

@@ -282,6 +271,3 @@ messages.push({

const modulePath = vfs.pathJoin(pkgDir, module)
const moduleContent = await readFile(modulePath, modulePkgPath, [
'.js',
'/index.js',
])
const moduleContent = await readFile(modulePath, modulePkgPath, ['.js', '/index.js'])
if (moduleContent === false) return

@@ -345,10 +331,3 @@ if (hasInvalidJsxExtension(module, modulePkgPath)) return

// check file existence for other known package fields
const knownFields = [
'types',
'typings',
'jsnext:main',
'jsnext',
'unpkg',
'jsdelivr',
]
const knownFields = ['types', 'typings', 'jsnext:main', 'jsnext', 'unpkg', 'jsdelivr']
// if has typesVersions field, it complicates `types`/`typings` field resolution a lot.

@@ -362,15 +341,7 @@ // for now skip it, but further improvements are tracked at

const [fieldValue, fieldPkgPath] = getPublishedField(rootPkg, fieldName)
if (
fieldValue != null &&
ensureTypeOfField(fieldValue, ['string'], fieldPkgPath)
) {
if (fieldValue != null && ensureTypeOfField(fieldValue, ['string'], fieldPkgPath)) {
promiseQueue.push(async () => {
const fieldPath = vfs.pathJoin(pkgDir, fieldValue)
const hasContent =
(await readFile(fieldPath, fieldPkgPath, ['.js', '/index.js'])) !==
false
if (
hasContent &&
(fieldName === 'jsnext:main' || fieldName === 'jsnext')
) {
const hasContent = (await readFile(fieldPath, fieldPkgPath, ['.js', '/index.js'])) !== false
if (hasContent && (fieldName === 'jsnext:main' || fieldName === 'jsnext')) {
messages.push({

@@ -403,16 +374,6 @@ code: 'DEPRECATED_FIELD_JSNEXT',

promiseQueue.push(async () => {
const files = await exportsGlob(
vfs.pathJoin(pkgDir, './*'),
vfs,
_packedFiles,
)
const files = await exportsGlob(vfs.pathJoin(pkgDir, './*'), vfs, _packedFiles)
const pq = createPromiseQueue()
for (const filePath of files) {
if (
hasInvalidJsxExtension(
filePath,
['name'],
'/' + vfs.pathRelative(pkgDir, filePath),
)
)
if (hasInvalidJsxExtension(filePath, ['name'], '/' + vfs.pathRelative(pkgDir, filePath)))
continue

@@ -444,7 +405,3 @@ if (!isFilePathLintable(filePath)) continue

// NOTE: only relax this for globbed files, as they're implicitly exported.
const expectFilePath = replaceLast(
filePath,
actualExtension,
expectExtension,
)
const expectFilePath = replaceLast(filePath, actualExtension, expectExtension)
if (await vfs.isPathExist(expectFilePath)) return

@@ -554,4 +511,3 @@

async function checkRepositoryField(repository) {
if (!ensureTypeOfField(repository, ['string', 'object'], ['repository']))
return
if (!ensureTypeOfField(repository, ['string', 'object'], ['repository'])) return

@@ -569,7 +525,3 @@ if (typeof repository === 'string') {

}
} else if (
typeof repository === 'object' &&
repository.url &&
repository.type === 'git'
) {
} else if (typeof repository === 'object' && repository.url && repository.type === 'git') {
if (!isGitUrl(repository.url)) {

@@ -679,6 +631,3 @@ messages.push({

const browserPath = vfs.pathJoin(pkgDir, fieldValue)
const browserContent = await readFile(browserPath, currentPath, [
'.js',
'/index.js',
])
const browserContent = await readFile(browserPath, currentPath, ['.js', '/index.js'])
if (browserContent === false) return

@@ -689,7 +638,3 @@ if (!isFileContentLintable(browserContent)) return

// If exports field is specified, bundlers will prefer that over browser field
if (
!hasExports &&
expectFormat === 'CJS' &&
hasEsModuleAndExportsDefault(browserContent)
) {
if (!hasExports && expectFormat === 'CJS' && hasEsModuleAndExportsDefault(browserContent)) {
messages.push({

@@ -708,6 +653,3 @@ code: 'CJS_WITH_ESMODULE_DEFAULT_EXPORT',

const browserPath = vfs.pathJoin(pkgDir, fieldValue[key])
await readFile(browserPath, currentPath.concat(key), [
'.js',
'/index.js',
])
await readFile(browserPath, currentPath.concat(key), ['.js', '/index.js'])
})

@@ -767,8 +709,3 @@ }

*/
function crawlExportsOrImports(
exportsValue,
currentPath,
isImports = false,
state,
) {
function crawlExportsOrImports(exportsValue, currentPath, isImports = false, state) {
if (typeof exportsValue === 'string') {

@@ -821,7 +758,3 @@ promiseQueue.push(async () => {

const exportsKey = currentPath[1]
const exportsFiles = await getExportsFiles(
exportsValue,
exportsKey,
exports,
)
const exportsFiles = await getExportsFiles(exportsValue, exportsKey, exports)

@@ -845,10 +778,4 @@ if (isGlob && !exportsFiles.length) {

// if so, warn about this conflict as it's often unexpected behaviour.
if (
!isImports &&
typeof browser === 'object' &&
exportsValue in browser
) {
const browserishCondition = knownBrowserishConditions.find((c) =>
currentPath.includes(c),
)
if (!isImports && typeof browser === 'object' && exportsValue in browser) {
const browserishCondition = knownBrowserishConditions.find((c) => currentPath.includes(c))
if (browserishCondition) {

@@ -882,5 +809,9 @@ messages.push({

// if not lintable, simply check file existence. only if it's an absolute path,
// so we avoid linting strings like `std:lib`. we also skip .ts and .tsx as it's
// common for some setup to only export them locally
if (isAbsolutePath(filePath) && !isFilePathRawTs(filePath)) {
// so we avoid linting strings like `std:lib`. we also skip checking if it has
// custom conditions, as some libraries may use them internally only which means
// the file may not be published.
if (
isAbsolutePath(filePath, pkgDir) &&
!hasCustomCondition(getConditionsFromCurrentPath(currentPath))
) {
// If crawling subpath imports, files may be bundled so it doesn't exist anymore,

@@ -906,5 +837,3 @@ // so we pass `undefined` to prevent error reporting.

messages.push({
code: isImports
? 'IMPORTS_MODULE_SHOULD_BE_ESM'
: 'EXPORTS_MODULE_SHOULD_BE_ESM',
code: isImports ? 'IMPORTS_MODULE_SHOULD_BE_ESM' : 'EXPORTS_MODULE_SHOULD_BE_ESM',
args: {},

@@ -934,4 +863,3 @@ path: currentPath,

// which doesn't care of the format
if (state?.isAfterNodeCondition || currentPath.includes('browser'))
return
if (state?.isAfterNodeCondition || currentPath.includes('browser')) return
const actualFormat = getCodeFormat(fileContent)

@@ -957,7 +885,3 @@ if (

if (isGlob) {
const expectFilePath = replaceLast(
filePath,
actualExtension,
expectExtension,
)
const expectFilePath = replaceLast(filePath, actualExtension, expectExtension)
if (await vfs.isPathExist(expectFilePath)) return

@@ -975,5 +899,3 @@ }

expectExtension,
actualFilePath: isGlob
? './' + vfs.pathRelative(pkgDir, filePath)
: exportsValue,
actualFilePath: isGlob ? './' + vfs.pathRelative(pkgDir, filePath) : exportsValue,
},

@@ -991,5 +913,3 @@ path: currentPath,

messages.push({
code: isImports
? 'IMPORTS_FALLBACK_ARRAY_USE'
: 'EXPORTS_FALLBACK_ARRAY_USE',
code: isImports ? 'IMPORTS_FALLBACK_ARRAY_USE' : 'EXPORTS_FALLBACK_ARRAY_USE',
args: {},

@@ -1001,8 +921,3 @@ path: currentPath,

for (const key of exportsValue.keys()) {
crawlExportsOrImports(
exportsValue[key],
currentPath.concat('' + key),
isImports,
state,
)
crawlExportsOrImports(exportsValue[key], currentPath.concat('' + key), isImports, state)
}

@@ -1023,18 +938,12 @@ }

// we also skip any exports value of raw ts or tsx files as they also represent types.
const precedingKeys = exportsKeys
.slice(0, exportsKeys.indexOf('types'))
.filter((key) => {
if (key.startsWith('types')) return false
const precedingKeys = exportsKeys.slice(0, exportsKeys.indexOf('types')).filter((key) => {
if (key.startsWith('types')) return false
const value = exportsValue[key]
if (typeof value === 'string' && isFilePathRawTs(value))
return false
if (
typeof value === 'object' &&
objectHasValueNested(value, isFilePathRawTs)
)
return false
const value = exportsValue[key]
if (typeof value === 'string' && isFilePathRawTs(value)) return false
if (typeof value === 'object' && objectHasValueNested(value, isFilePathRawTs))
return false
return true
})
return true
})

@@ -1087,10 +996,5 @@ // TODO: check that versioned types are valid and the ranges don't overlap.

// the default export/import should be the last condition
if (
'default' in exportsValue &&
exportsKeys[exportsKeys.length - 1] !== 'default'
) {
if ('default' in exportsValue && exportsKeys[exportsKeys.length - 1] !== 'default') {
messages.push({
code: isImports
? 'IMPORTS_DEFAULT_SHOULD_BE_LAST'
: 'EXPORTS_DEFAULT_SHOULD_BE_LAST',
code: isImports ? 'IMPORTS_DEFAULT_SHOULD_BE_LAST' : 'EXPORTS_DEFAULT_SHOULD_BE_LAST',
args: {},

@@ -1103,4 +1007,3 @@ path: currentPath.concat('default'),

// Only check that imports start with `#` for the first set of keys
const isCurrentPathImports =
isImports && currentPath[currentPath.length - 1] === 'imports'
const isCurrentPathImports = isImports && currentPath[currentPath.length - 1] === 'imports'

@@ -1120,9 +1023,7 @@ const isImportRequireConditions =

isAfterNodeCondition,
isReachableByImportCondition:
state?.isReachableByImportCondition ?? true,
isReachableByImportCondition: state?.isReachableByImportCondition ?? true,
}
if (isImportRequireConditions) {
stateForNextLevel.isReachableByImportCondition &&=
key === 'import' ||
(!exportsKeys.includes('import') && key === 'default')
key === 'import' || (!exportsKeys.includes('import') && key === 'default')
}

@@ -1181,11 +1082,7 @@

const typesFilePath = await findTypesFilePath(exportsRootKey)
const exportsRootValue = exportsRootKey
? exports[exportsRootKey]
: exports
const exportsRootValue = exportsRootKey ? exports[exportsRootKey] : exports
// detect if this package intend to ship types
if (typesFilePath) {
const exportsPath = exportsRootKey
? exportsPkgPath.concat(exportsRootKey)
: exportsPkgPath
const exportsPath = exportsRootKey ? exportsPkgPath.concat(exportsRootKey) : exportsPkgPath

@@ -1213,5 +1110,3 @@ // keyed strings for seen resolved paths, so we don't trigger duplicate messages for the same thing

const isDualPublish =
importResult &&
requireResult &&
importResult.value !== requireResult.value
importResult && requireResult && importResult.value !== requireResult.value

@@ -1226,4 +1121,3 @@ for (const format of ['import', 'require']) {

// so we add the `format` to the key here.
const seenKey =
typesResult.path.join('.') + (isDualPublish ? format : '')
const seenKey = typesResult.path.join('.') + (isDualPublish ? format : '')
if (seenResolvedKeys.has(seenKey)) continue

@@ -1240,6 +1134,3 @@ seenResolvedKeys.add(seenKey)

// check if we're hitting this case :(
const dtsActualFormat = await getDtsFilePathFormat(
typesResolvedPath,
vfs,
)
const dtsActualFormat = await getDtsFilePathFormat(typesResolvedPath, vfs)

@@ -1256,11 +1147,7 @@ /** @type {'ESM' | 'CJS' | undefined} */

if (!isDualPublish) {
const jsResult =
format === 'import' ? importResult : requireResult
const jsResult = format === 'import' ? importResult : requireResult
if (jsResult) {
const jsResolvedPath = vfs.pathJoin(pkgDir, jsResult.value)
if (await vfs.isPathExist(jsResolvedPath)) {
dtsExpectFormat = await getFilePathFormat(
jsResolvedPath,
vfs,
)
dtsExpectFormat = await getFilePathFormat(jsResolvedPath, vfs)
}

@@ -1327,5 +1214,3 @@ }

typesFilePath,
actualExtension: isMatchingFormat
? undefined
: vfs.getExtName(typesFilePath),
actualExtension: isMatchingFormat ? undefined : vfs.getExtName(typesFilePath),
expectExtension: isMatchingFormat

@@ -1375,6 +1260,3 @@ ? undefined

const binPath = vfs.pathJoin(pkgDir, binValue)
const binContent = await readFile(binPath, currentPath, [
'.js',
'/index.js',
])
const binContent = await readFile(binPath, currentPath, ['.js', '/index.js'])
if (binContent === false) return

@@ -1381,0 +1263,0 @@ // Skip checks if file is not lintable

import picocolors from 'picocolors'
import {
formatMessagePath as fp,
getPkgPathValue,
replaceLast,
} from './utils.js'
import { formatMessagePath as fp, getPkgPathValue, replaceLast } from './utils.js'

@@ -8,0 +4,0 @@ const EMPTY_MSG = '<empty>'

@@ -53,6 +53,3 @@ import { lintableFileExtensions } from './constants.js'

const partialDefaultValue = match[1].trimEnd()
if (
partialDefaultValue === 'exports' ||
partialDefaultValue === 'exports;'
) {
if (partialDefaultValue === 'exports' || partialDefaultValue === 'exports;') {
// ignore `exports.default = exports`

@@ -76,5 +73,3 @@ continue

export function stripComments(code) {
return code
.replace(MULTILINE_COMMENTS_RE, '')
.replace(SINGLELINE_COMMENTS_RE, '')
return code.replace(MULTILINE_COMMENTS_RE, '').replace(SINGLELINE_COMMENTS_RE, '')
}

@@ -169,14 +164,6 @@

*/
export async function exportsGlob(
globStr,
vfs,
packedFiles,
exportsKey,
exports,
) {
export async function exportsGlob(globStr, vfs, packedFiles, exportsKey, exports) {
/** @type {string[]} */
const filePaths = []
const globStrRe = new RegExp(
`^${slash(globStr).split('*').map(escapeRegExp).join('(.+)')}$`,
)
const globStrRe = new RegExp(`^${slash(globStr).split('*').map(escapeRegExp).join('(.+)')}$`)
// the longest directory that doesn't contain `*`

@@ -192,5 +179,3 @@ const topDir = globStr.split('*')[0].match(/(.+)[/\\]/)?.[1]

if (exports[key] === null) {
excludedExportKeys.push(
new RegExp(`^${key.split('*').map(escapeRegExp).join('(.+)')}$`),
)
excludedExportKeys.push(new RegExp(`^${key.split('*').map(escapeRegExp).join('(.+)')}$`))
}

@@ -215,6 +200,3 @@ }

// ensure the file is within the packed files (if provided)
if (
!packedFiles ||
packedFiles.some((file) => file.startsWith(itemPath))
) {
if (!packedFiles || packedFiles.some((file) => file.startsWith(itemPath))) {
if (await vfs.isPathDir(itemPath)) {

@@ -245,5 +227,3 @@ await scanDir(itemPath)

const replacedExportsKey = exportsKey.replace('*', matched[1])
if (
excludedExportKeys.some((re) => re.test(replacedExportsKey))
) {
if (excludedExportKeys.some((re) => re.test(replacedExportsKey))) {
continue

@@ -352,8 +332,57 @@ }

export function isFilePathRawTs(filePath) {
return (
(filePath.endsWith('.ts') && !filePath.endsWith('.d.ts')) ||
filePath.endsWith('.tsx')
)
return (filePath.endsWith('.ts') && !filePath.endsWith('.d.ts')) || filePath.endsWith('.tsx')
}
const COMMON_CONDITIONS = [
'default',
// file type
'import',
'require',
// env type
'development',
'production',
// env
'types',
'node',
'browser',
'worker',
'deno',
]
/**
* Whether the given conditions may support raw `.ts` or `.tsx` files. Usually
* you shouldn't export these files, however some setups uses custom conditions
* to export them, which wouldn't be enabled by consumers in practice.
*
* Since we can't know all the possible custom condition names, we track a list
* of popular condition names we know of, and if one isn't found to be in the list,
* we can assume it's a custom condition and that it may export raw TS files.
*
* Note: This doesn't need to be perfect. Right now it's used for determining
* whether to check for file existence in these specified paths, so worst case
* is that we just missed some checks.
*
* @param {string[]} conditions
*/
export function hasCustomCondition(conditions) {
for (const condition of conditions) {
if (!COMMON_CONDITIONS.includes(condition)) {
return true
}
}
return false
}
/**
* When traversing the package.json `exports` or `imports` field, this function
* tries to extract the conditions from the current path.
*
* @param {string[]} currentPath
*/
export function getConditionsFromCurrentPath(currentPath) {
let sliceIndex = currentPath.findIndex((p) => p === 'exports' || p === 'imports')
if (sliceIndex === -1) return []
if (currentPath[sliceIndex + 1][0] === '.') sliceIndex++
return currentPath.slice(sliceIndex + 1)
}
// support:

@@ -390,5 +419,8 @@ // // @flow

* @param {string} filePath
* @param {string} pkgDir
*/
export function isAbsolutePath(filePath) {
export function isAbsolutePath(filePath, pkgDir) {
if (!pkgDir.endsWith('/')) pkgDir += '/'
return (
filePath.startsWith(pkgDir) ||
filePath[0] === '/' ||

@@ -479,4 +511,3 @@ (filePath[1] === ':' && filePath[0].match(/[a-zA-Z]/))

if (k === key) return true
if (typeof obj[k] === 'object' && objectHasKeyNested(obj[k], key))
return true
if (typeof obj[k] === 'object' && objectHasKeyNested(obj[k], key)) return true
}

@@ -493,4 +524,3 @@ return false

if (typeof obj[k] === 'string' && predicate(obj[k])) return true
if (typeof obj[k] === 'object' && objectHasValueNested(obj[k], predicate))
return true
if (typeof obj[k] === 'object' && objectHasValueNested(obj[k], predicate)) return true
}

@@ -539,7 +569,3 @@ return false

if (conditions.includes(key) || key === 'default') {
const result = resolveExports(
exportsValue[key],
conditions,
currentPath.concat(key),
)
const result = resolveExports(exportsValue[key], conditions, currentPath.concat(key))
if (result || key === 'default') return result

@@ -546,0 +572,0 @@ }

@@ -18,5 +18,3 @@ /**

const pathDirVariant = path.endsWith('/') ? path : path + '/'
return files.some(
(file) => file.name === path || file.name.startsWith(pathDirVariant),
)
return files.some((file) => file.name === path || file.name.startsWith(pathDirVariant))
},

@@ -23,0 +21,0 @@ pathJoin: (...parts) => parts.join('/').replace(/\/(\.?\/){1,}/g, '/'),

@@ -33,6 +33,3 @@ import type { Message } from './index.js'

export declare function getPkgPathValue(
pkg: Record<string, any>,
path: string[],
): any
export declare function getPkgPathValue(pkg: Record<string, any>, path: string[]): any

@@ -39,0 +36,0 @@ export declare function formatMessage(