sdin
Version:
JavaScript package builder.
125 lines (116 loc) • 3.72 kB
text/typescript
import { resolve } from 'path'
import { pathExistsSync, readJsonSync } from 'fs-extra'
import { isEmail, isPackageName } from './check'
import { isPlainObject } from 'lodash'
import { NpmError } from './errors'
export interface PackageInfo extends Record<string, any> {
/** 包名称 */
name: string
/** 版本 */
version: string
/** 描述 */
description: string
/** "xxx <xxx@xxx.xxx>"*/
author: string
/** "xxx" */
authorName: string
/** "xxx@xxx.xxx" */
authorEmail: string
}
export const PACKAGE_INFO: PackageInfo = {
name: 'unknown',
version: '1.0.0',
description: 'unknown',
author: 'unknown <unknown@unknown.domain>',
authorName: 'unknown',
authorEmail: 'unknown@unknown.domain'
}
export const PACKAGE_INFO_FILE_NAME = 'package.json'
const PACKAGE_AUTHOR_EXP = /^(.+) <(.+)>$/
const MODULE_NAME_SEPARATOR_EXP = /[\/\?]+/
/**
* 获取给定文件所属包的根目录
*/
export function getPackageRootPath(path: string) {
let root: string = path
for (let i = 0; root && i < 10; i++) {
if (pathExistsSync(resolve(root, PACKAGE_INFO_FILE_NAME))) {
return root
} else {
root = resolve(root, '../')
}
}
throw new NpmError(NpmError.NOT_HAS_ROOT_PATH, 'Cannot find root path.')
}
/**
* 根据文件夹目录,获取包的信息
*/
export function readPackageInfo(root: string, strict: true): PackageInfo
export function readPackageInfo(root: string, strict?: false): PackageInfo | undefined
export function readPackageInfo(root: string, strict?: boolean): PackageInfo | undefined {
const filePath = resolve(root, PACKAGE_INFO_FILE_NAME)
const data = readJsonSync(filePath)
if (!isPlainObject(data)) {
if (strict) {
throw new NpmError(
NpmError.PACKAGE_JSON_CONTENT_IS_NOT_PLAIN_OBJECT,
`File ${filePath} exports is not ${PACKAGE_INFO_FILE_NAME} content.`
)
} else {
return undefined
}
}
if (!data.name || !data.version || !data.description || !data.author) {
throw new NpmError(
NpmError.PACKAGE_JSON_MISSING_REQUIRED_FIELD,
`${PACKAGE_INFO_FILE_NAME} must contain "name", "version", "description", "author" fields`
)
}
if (!isPackageName(data.name)) {
throw new NpmError(
NpmError.PACKAGE_NAME_IS_NOT_KEBAB_CASE,
'Please change package name to kebab-case'
)
}
const atr = data.author
if (typeof atr === 'object') {
data.authorName = atr.name || ''
data.authorEmail = atr.email || ''
if (data.authorEmail) {
data.author = `${data.authorName} <${data.authorEmail}>`
} else {
data.author = data.authorName
}
} else {
const mtd = PACKAGE_AUTHOR_EXP.exec(atr)
if (mtd && mtd.length >= 3) {
data.authorName = mtd[1]
data.authorEmail = mtd[2]
} else {
throw new NpmError(
NpmError.PACKAGE_AUTHOR_MARK_FORMAT_ERROR,
`Please change author to "name <xxx@xxx.xxx>" in ${PACKAGE_INFO_FILE_NAME}`
)
}
}
if (!isEmail(data.authorEmail)) {
throw new NpmError(
NpmError.PACKAGE_AUTHOR_EMAIL_FORMAT_ERROR,
`Author email format error in ${PACKAGE_INFO_FILE_NAME}`
)
}
return data
}
export function getDependenceName(importedPath: string) {
const segments = importedPath.split(MODULE_NAME_SEPARATOR_EXP)
if (segments.length === 1) {
return importedPath
}
if (segments[0][0] === '@') {
return segments[0] + '/' + segments[1]
}
return segments[0]
}
export function getDependenceVersion(pkg: PackageInfo, dep: string): string {
return pkg.dependencies[dep] || pkg.devDependencies[dep] || ''
}