Socket
Socket
Sign inDemoInstall

publint

Package Overview
Dependencies
Maintainers
1
Versions
31
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.8 to 0.1.9

index.d.ts

8

lib/browser.js
import { publint as _publint } from '../src/index.js'
/**
* @type {import('.').publint}
* @type {import('..').publint}
*/
export function publint(options) {
if (!options?.vfs) {
throw new Error('The vfs option is required in the browser')
}
return _publint({
pkgDir: options.pkgDir ?? '/',
vfs: options.vfs,
level: options?.level
level: options.level ?? 'suggestion'
})
}

@@ -28,3 +28,3 @@ #!/usr/bin/env node

const pkgDir = dir ? path.resolve(dir) : process.cwd()
const { logs } = await lintDir(pkgDir, opts.level)
const logs = await lintDir(pkgDir, opts.level)
logs.forEach((l) => console.log(l))

@@ -74,3 +74,3 @@ })

const depDir = await findDepPath(deps[i], pkgDir)
const { logs } = await lintDir(depDir, opts.level, true)
const logs = depDir ? await lintDir(depDir, opts.level, true) : []
// log this lint result

@@ -104,3 +104,3 @@ const log = () => {

* @param {string} pkgDir
* @param {import('./index.js').Options['level']} level
* @param {import('../index.js').Options['level']} level
* @param {boolean} [compact]

@@ -118,4 +118,5 @@ */

})
if (!rootPkgContent) return { logs }
if (!rootPkgContent) return logs
const rootPkg = JSON.parse(rootPkgContent)
const pkgName = rootPkg.name || path.basename(pkgDir)
const messages = await publint({ pkgDir, level })

@@ -150,17 +151,17 @@

if (compact) {
logs.unshift(`${c.red('x')} ${c.bold(rootPkg.name)}`)
logs.unshift(`${c.red('x')} ${c.bold(pkgName)}`)
} else {
logs.unshift(`${c.bold(rootPkg.name)} lint results:`)
logs.unshift(`${c.bold(pkgName)} lint results:`)
}
return { logs }
return logs
} else {
if (compact) {
logs.unshift(`${c.green('✓')} ${c.bold(rootPkg.name)}`)
logs.unshift(`${c.green('✓')} ${c.bold(pkgName)}`)
} else {
logs.unshift(`${c.bold(rootPkg.name)} lint results:`)
logs.unshift(`${c.bold(pkgName)} lint results:`)
logs.push(c.bold(c.green('All good!')))
}
return { logs }
return logs
}

@@ -179,6 +180,4 @@ }

/**
*
* @param {string} dep
* @param {string} parent
* @returns
*/

@@ -185,0 +184,0 @@ async function findDepPath(dep, parent) {

@@ -8,20 +8,9 @@ import fs from 'node:fs/promises'

/**
* @type {import('.').publint}
* @type {import('..').publint}
*/
export async function publint(options) {
const pkgDir = options?.pkgDir ?? process.cwd()
// Find packed files for `publint` `_include` if no `exports` field.
// This is because without `exports` field, all files can be accessed
// by the consumer, but we need to know which files are packed,
// since those are the ones getting published.
const rootPkgContent = await fs.readFile(
path.join(pkgDir, 'package.json'),
'utf8'
const packedFiles = (await packlist({ path: pkgDir })).map((file) =>
path.join(pkgDir, file)
)
const rootPkg = JSON.parse(rootPkgContent)
const hasExports = !!rootPkg.exports
const packedFiles = hasExports
? []
: (await packlist({ path: pkgDir })).map((file) => path.join(pkgDir, file))

@@ -31,7 +20,5 @@ return _publint({

vfs: options?.vfs ?? createNodeVfs(),
level: options?.level,
_include: hasExports
? undefined
: (p) => packedFiles.some((file) => file.startsWith(p))
level: options?.level ?? 'suggestion',
_packedFiles: packedFiles
})
}
export { formatMessagePath, getPkgPathValue } from '../src/utils.js'
/**
* no-op. leave users to implement themselves.
* @type {import('../utils').printMessage}
*/
export function printMessage() {
return
}
{
"name": "publint",
"version": "0.1.8",
"version": "0.1.9",
"description": "Lint packaging errors",

@@ -9,6 +9,6 @@ "type": "module",

"bin": "./lib/cli.js",
"types": "./lib/index.d.ts",
"types": "./index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"types": "./index.d.ts",
"import": {

@@ -21,4 +21,7 @@ "browser": "./lib/browser.js",

"./utils": {
"types": "./lib/utils.d.ts",
"import": "./lib/utils.js"
"types": "./utils.d.ts",
"import": {
"node": "./lib/utils-node.js",
"default": "./lib/utils.js"
}
}

@@ -31,3 +34,4 @@ },

"lib",
"src"
"src",
"*.d.ts"
],

@@ -54,2 +58,3 @@ "funding": "https://bjornlu.com/sponsor",

"devDependencies": {
"@types/npm-packlist": "3.0.0",
"uvu": "^0.5.6"

@@ -56,0 +61,0 @@ },

@@ -57,3 +57,10 @@ <br>

*/
vfs: createCustomVfsObj()
vfs: createCustomVfsObj(),
/**
* The level of messages to log (default: `'suggestion'`).
* - `suggestion`: logs all messages
* - `warning`: logs only `warning` and `error` messages
* - `error`: logs only `error` messages
*/
level: 'warning'
})

@@ -64,4 +71,16 @@

Extra utilities are exported under `publint/utils`:
```js
import { printMessage } from 'publint/utils'
for (const message of messages) {
// Prints default message in Node.js. Always a no-op in browsers.
// Useful for re-implementing the CLI in a programmatic way.
printMessage(message)
}
```
## License
MIT

@@ -14,4 +14,4 @@ import {

* Currently only used if pkg has no `exports`
* @typedef {Required<import('../lib').Options> & {
* _include?: (filePath: string) => boolean
* @typedef {Required<import('..').Options> & {
* _packedFiles?: string[]
* }} Options

@@ -22,6 +22,6 @@ */

* @param {Options} options
* @returns {Promise<import('../lib').Message[]>}
* @returns {Promise<import('..').Message[]>}
*/
export async function publint({ pkgDir, vfs, level, _include }) {
/** @type {import('../lib').Message[]} */
export async function publint({ pkgDir, vfs, level, _packedFiles }) {
/** @type {import('..').Message[]} */
const messages = []

@@ -58,7 +58,15 @@ /**

try {
return await vfs.readFile(path)
const content = await vfs.readFile(path)
if (_packedFiles && !_packedFiles.includes(path)) {
fileNotPublished(pkgPath)
}
return content
} catch {
for (const ext of tryExtensions) {
try {
return await vfs.readFile(path + ext)
const content = await vfs.readFile(path + ext)
if (_packedFiles && !_packedFiles.includes(path)) {
fileNotPublished(pkgPath)
}
return content
} catch {}

@@ -76,2 +84,14 @@ }

/**
* @param {string[]} pkgPath
*/
function fileNotPublished(pkgPath) {
messages.push({
code: 'FILE_NOT_PUBLISHED',
args: {},
path: pkgPath,
type: 'error'
})
}
// Relies on default node resolution

@@ -144,3 +164,3 @@ // https://nodejs.org/api/modules.html#all-together

}
if (expectFormat === 'ESM') {
if (expectFormat === 'ESM' && !exports) {
messages.push({

@@ -227,3 +247,3 @@ code: 'HAS_ESM_MAIN_BUT_NO_EXPORTS',

vfs,
_include
_packedFiles
)

@@ -230,0 +250,0 @@ const pq = createPromiseQueue()

@@ -5,3 +5,3 @@ import c from 'picocolors'

/**
* @param {import('../lib').Message} m
* @param {import('..').Message} m
* @param {import('./utils').Pkg} pkg

@@ -13,3 +13,2 @@ */

// TODO: verbose mode
switch (m.code) {

@@ -40,6 +39,9 @@ case 'IMPLICIT_INDEX_JS_INVALID_FORMAT':

// prettier-ignore
return `${c.bold(fp(m.path))} is ${pv(m.path)} but file does not exist.`
return `${c.bold(fp(m.path))} is ${pv(m.path)} but the file does not exist.`
case 'FILE_NOT_PUBLISHED':
// prettier-ignore
return `${c.bold(fp(m.path))} is ${pv(m.path)} but the file is not published. Is it specified in ${c.bold('pkg.files')}?`
case 'HAS_ESM_MAIN_BUT_NO_EXPORTS':
// prettier-ignore
return `${c.bold('pkg.main')} is an ESM file, but it is usually better to use ${c.bold('pkg.exports')} instead, and remove ${c.bold('pkg.main')} alongside, as compatible NodeJS versions support it as well. (This will be a breaking change)`
return `${c.bold('pkg.main')} is an ESM file, but it is usually better to use ${c.bold('pkg.exports')} instead. If you don't support NodeJS 12.6 and below, you can also remove ${c.bold('pkg.main')}. (This will be a breaking change)`
case 'HAS_MODULE_BUT_NO_EXPORTS':

@@ -73,4 +75,4 @@ // prettier-ignore

default:
// TODO
return
}
}

@@ -64,7 +64,7 @@ /**

* @param {string} globStr An absolute glob string that must contain one `*`
* @param {import('../lib').Vfs} vfs
* @param {(filePath: string) => boolean} [include]
* @param {import('..').Vfs} vfs
* @param {string[]} [packedFiles]
* @returns {Promise<string[]>} Matched file paths
*/
export async function exportsGlob(globStr, vfs, include) {
export async function exportsGlob(globStr, vfs, packedFiles) {
let filePaths = []

@@ -84,3 +84,6 @@ const [dir, ext] = globStr.split('*')

const itemPath = vfs.pathJoin(dirPath, item)
if (!include || include(itemPath)) {
if (
!packedFiles ||
packedFiles.some((file) => file.startsWith(itemPath))
) {
if (await vfs.isPathDir(itemPath)) {

@@ -98,3 +101,3 @@ await scanDir(itemPath)

* @param {string} filePath
* @param {import('../lib').Vfs} vfs
* @param {import('..').Vfs} vfs
* @returns {Promise<CodeFormat>}

@@ -106,3 +109,3 @@ */

const nearestPkg = await getNearestPkg(filePath, vfs)
return nearestPkg.type === 'module' ? 'ESM' : 'CJS'
return nearestPkg?.type === 'module' ? 'ESM' : 'CJS'
}

@@ -134,4 +137,4 @@

* @param {string} filePath
* @param {import('../lib').Vfs} vfs
* @returns {Promise<Pkg>}
* @param {import('..').Vfs} vfs
* @returns {Promise<Pkg | undefined>}
*/

@@ -138,0 +141,0 @@ export async function getNearestPkg(filePath, vfs) {

@@ -7,3 +7,3 @@ import fs from 'node:fs'

* Creates a node-compatible Vfs object
* @returns {import('../lib').Vfs}
* @returns {import('..').Vfs}
*/

@@ -10,0 +10,0 @@ export function createNodeVfs() {

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