+4
-4
| { | ||
| "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": { |
+10
-29
@@ -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 @@ |
+3
-12
@@ -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 @@ | { |
+58
-176
@@ -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>' |
+67
-41
@@ -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, '/'), |
+1
-4
@@ -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( |
108264
0.12%2741
-4.56%