+1
-1
| { | ||
| "name": "publint", | ||
| "version": "0.3.19", | ||
| "version": "0.3.20", | ||
| "description": "Lint packaging errors", | ||
@@ -5,0 +5,0 @@ "type": "module", |
+1
-0
@@ -65,2 +65,3 @@ export type MessageType = 'suggestion' | 'warning' | 'error' | ||
| | BaseMessage<'EXPORTS_FALLBACK_ARRAY_USE'> | ||
| | BaseMessage<'USE_ENGINES_NODE'> | ||
| | BaseMessage<'USE_EXPORTS_BROWSER'> | ||
@@ -67,0 +68,0 @@ | BaseMessage<'USE_EXPORTS_OR_IMPORTS_BROWSER'> |
+35
-0
@@ -159,2 +159,37 @@ import { | ||
| // Check if is Node.js package and the "engines.node" field is missing | ||
| const [engines, enginesPkgPath] = getPublishedField(rootPkg, 'engines') | ||
| if (engines == null || typeof engines !== 'object' || engines.node == null) { | ||
| promiseQueue.push(async () => { | ||
| /** @type {import('../index.d.ts').Message} */ | ||
| const msg = { | ||
| code: 'USE_ENGINES_NODE', | ||
| args: {}, | ||
| path: engines != null ? enginesPkgPath : ['name'], | ||
| type: 'suggestion', | ||
| } | ||
| // `node` and `require` conditions are treated as a signal CJS code is published, which | ||
| // is mostly applicable for Node.js only | ||
| if ( | ||
| exports != null && | ||
| typeof exports === 'object' && | ||
| (objectHasKeyNested(exports, 'node') || objectHasKeyNested(exports, 'require')) | ||
| ) { | ||
| messages.push(msg) | ||
| return | ||
| } | ||
| // `main` isn't always CJS, so only use it as a signal when the file content is CJS. | ||
| if (main != null && typeof main === 'string') { | ||
| const mainPath = vfs.pathJoin(pkgDir, main) | ||
| const mainContent = await readFile(mainPath, undefined, ['.js', '/index.js']) | ||
| if (mainContent && getCodeFormat(mainContent) === 'CJS') { | ||
| messages.push(msg) | ||
| return | ||
| } | ||
| } | ||
| }) | ||
| } | ||
| // Relies on default node resolution | ||
@@ -161,0 +196,0 @@ // https://nodejs.org/api/modules.html#all-together |
@@ -74,5 +74,5 @@ import picocolors from 'picocolors' | ||
| case 'HAS_ESM_MAIN_BUT_NO_EXPORTS': | ||
| return `${h.bold('pkg.main')} is an ESM file, but it is usually better to use ${h.bold('pkg.exports')} instead. If you don't support Node.js 12.6 and below, you can also remove ${h.bold('pkg.main')}. (This will be a breaking change)` | ||
| return `${h.bold('pkg.main')} is an ESM file, but it is usually better to use ${h.bold('pkg.exports')} instead. If you don't support Node.js 12.6 and below, you can also remove ${h.bold('pkg.main')}. (This may be a breaking change)` | ||
| case 'HAS_MODULE_BUT_NO_EXPORTS': | ||
| return `${h.bold('pkg.module')} is used to output ESM, but ${h.bold('pkg.exports')} is not defined. As Node.js doesn't read ${h.bold('pkg.module')}, the ESM output may be skipped. Consider adding ${h.bold('pkg.exports')} to export the ESM output. ${h.bold('pkg.module')} can usually be removed alongside too. (This will be a breaking change)` | ||
| return `${h.bold('pkg.module')} is used to output ESM, but ${h.bold('pkg.exports')} is not defined. As Node.js doesn't read ${h.bold('pkg.module')}, the ESM output may be skipped. Consider adding ${h.bold('pkg.exports')} to export the ESM output. ${h.bold('pkg.module')} can usually be removed alongside too. (This may be a breaking change)` | ||
| case 'MODULE_SHOULD_BE_ESM': | ||
@@ -130,6 +130,6 @@ case 'EXPORTS_MODULE_SHOULD_BE_ESM': | ||
| `${h.bold('pkg.browser')} with a string value can be refactored to use ${h.bold('pkg.exports')} and the ${h.bold('"browser"')} condition to declare browser-specific exports. ` + | ||
| `e.g. ${h.bold('pkg.exports["."].browser')}: "${h.bold(pv(m.path))}". (This will be a breaking change)` | ||
| `e.g. ${h.bold('pkg.exports["."].browser')}: "${h.bold(pv(m.path))}". (This may be a breaking change)` | ||
| ) | ||
| case 'USE_EXPORTS_OR_IMPORTS_BROWSER': | ||
| return `${h.bold('pkg.browser')} with an object value can be refactored to use ${h.bold('pkg.exports')}/${h.bold('pkg.imports')} and the ${h.bold('"browser"')} condition to declare browser-specific exports. (This will be a breaking change)` | ||
| return `${h.bold('pkg.browser')} with an object value can be refactored to use ${h.bold('pkg.exports')}/${h.bold('pkg.imports')} and the ${h.bold('"browser"')} condition to declare browser-specific exports. (This may be a breaking change)` | ||
| case 'USE_FILES': | ||
@@ -139,2 +139,4 @@ return `The package ${h.bold('publishes internal tests or config files')}. You can use ${h.bold('pkg.files')} to only publish certain files and save user bandwidth.` | ||
| return `The package does not specify the ${h.bold('"type"')} field. Node.js may attempt to detect the package type causing a small performance hit. Consider adding ${h.bold('"type"')}: "${h.bold('commonjs')}".` | ||
| case 'USE_ENGINES_NODE': | ||
| return `The package does not specify the ${h.bold('"engines.node"')} field. Consumers may install it on an unsupported Node.js version. Consider adding the field with your actual minimum supported Node.js version. (This may be a breaking change)` | ||
| case 'USE_LICENSE': | ||
@@ -141,0 +143,0 @@ return `The package does not specify the ${h.bold('"license"')} field but a license file was detected at ${h.bold(m.args.licenseFilePath)}. Consider adding a ${h.bold('"license"')} field so it's displayed on npm.` |
@@ -139,3 +139,2 @@ import { lintableFileExtensions } from './constants.js' | ||
| // But since we use regex, we can't correct identify ESM and CJS, so when this happens we should bail instead. | ||
| // TODO: Yak shave a correct implementation. | ||
| if (isEsm && isCjs) { | ||
@@ -142,0 +141,0 @@ return 'mixed' |
113264
1.38%2866
1.2%