tiny-vue/build/utils.js

310 lines
7.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const fs = require('fs-extra')
const path = require('path')
const chalk = require('chalk')
const { execSync } = require('child_process')
const log = global.console
const logger = log.log
/**
* 根据运行上下文获取路径(运行时打包用)
* @returns 文件绝对路径
*/
const resolveCwd = (...args) => path.join(process.cwd(), ...args)
/**
* 获取模板替换路径(动态)
* @param {String} posixPath 路径
* @returns 文件绝对路径
*/
const assetsPath = (posixPath) => path.posix.join('static', posixPath)
/**
* 根据运行上下文获取,当前运行组件的名称
* @returns 当前运行组件目录名称
*/
const getComponentName = () => process.cwd().split(path.sep).pop()
/**
* 获取当前上下文的路径
* @returns 文件绝对路径
*/
const pathJoin = (...args) => path.join(__dirname, ...args)
/**
* 获取用户输入命令参数
* @returns 参数数组
*/
const getInputCmd = () => {
const args = []
const argv = process.argv || []
argv.forEach((item) => {
if (item.indexOf(path.sep) === -1) {
args.push(item)
}
})
return args
}
/**
* 获取当前执行 cli 命令的工具node\npm\yarn
* @returns node\npm\yarn
*/
const getCurrentCliTool = () => {
const npmExecpaths = process.env.npm_execpaths
if (!npmExecpaths) {
return 'node'
}
return npmExecpaths.substring(npmExecpaths.lastIndexOf(path.sep) + 1).replace(/.js|-cli/g, '')
}
/**
* 执行 node 命令
* @param {String} cmdStr 命令字符串
*/
const execCmd = (cmdStr) => {
cmdStr && execSync(cmdStr, { stdio: 'inherit' })
}
/**
* 首字母大写
* @param {String} str 字符串
* @returns 字符串
*/
const capitalize = (str) => (typeof str === 'string' ? str.slice(0, 1).toUpperCase() + str.slice(1) : str)
/**
* 首字母大写
* @param {String} str 字符串
* @returns 字符串
*/
const capitalizeKebabCase = (str, splitChar = '-') => (typeof str === 'string' ? str.split(splitChar).map(capitalize).join('') : str)
/**
* @description 将驼峰字符串转化为以指定字符分割的小写字符串
* @example kebabCase({ str : 'ImgPreviewItem' } )
* @example 输出结果img-preview-item
*
* @param str 字符串
* @param splitChar 分隔符
*/
const kebabCase = ({ str, splitChar = '-' }) => {
if (!str || typeof str !== 'string') {
return str
}
return str
.split('')
.map((char, index) => {
const charCod = char.charCodeAt(0)
if (charCod < 65 || charCod > 122) {
return char
}
return (charCod >= 65 && charCod) <= 90 ? (index === 0 ? '' : splitChar) + char.toLowerCase() : char
})
.join('')
}
/**
* 采用 prettier 美化字符串
* @param {String} str 格式字符
* @param {Object} options 格式字符
*/
const prettierFormat = ({ str, options = {} }) =>
require('prettier').format(str, {
printWidth: 100,
jsxBracketSameLine: false,
tabWidth: 2,
useTabs: false,
singleQuote: true,
semi: false,
trailingComma: 'none',
bracketSpacing: true,
parser: 'babel',
...options
})
/**
* @private
* @param {String} path dotted to indicate levels in an object.
* @param {Object} view for the data.
*/
function extractValue(path, view) {
if (view && view[path]) {
return view[path]
}
const parts = path.split('.')
let part = ''
while (view && (part = parts.shift())) {
view = typeof view === 'object' && part in view ? view[part] : undefined
}
return view
}
/**
* 渲染字符串模板
* @param {String} leftChar 匹配左边字符
* @param {String} rightChar 匹配右边字符
*/
const renderTemplate = ({ leftChar = '{{', rightChar = '}}' } = {}) => {
const specialChar = ['[', ']']
const _leftChar = leftChar.split('').map((item) => (specialChar.includes(item) ? '\\' : '') + item)
const _rightChar = rightChar.split('').map((item) => (specialChar.includes(item) ? '\\' : '') + item)
const REGEX = new RegExp(`${_leftChar.join('')}([a-zA-Z.-_0-9]+)${_rightChar.join('')}`, 'g')
return (input, view) => {
if (input.indexOf(leftChar) === -1) {
return input
}
let result
const replaced = input.replace(REGEX, (original, path) => {
const value = extractValue(path, view)
if (undefined === value || value === null) {
return original
}
if (typeof value === 'object') {
result = value
return
}
return value
})
return undefined === result ? replaced : result
}
}
/**
* 扫描指定目录下面的组件目录
* @param {String} dirPath 绝对路径
* @param {Boolean} isDeep 是否深度遍历
* @param {Function} fileFilter 文件筛选拦截函数
* @param {Function} callback 遍历回调
*/
const walkFileTree = ({ dirPath, isDeep = false, fileFilter, callback }) => {
if (!dirPath || typeof callback !== 'function') {
return
}
const dirs = fs.readdirSync(path.isAbsolute(dirPath) ? dirPath : path.join(__dirname, dirPath))
if (Array.isArray(dirs) && dirs.length > 0) {
dirs.forEach((file) => {
let isFind = true
const subPath = path.join(dirPath, file)
const isDirectory = fs.statSync(subPath).isDirectory()
if (typeof fileFilter === 'function') {
isFind = fileFilter({ file, subPath, dirs, isDirectory }) === true
}
if (isFind && isDirectory) {
if (isDeep) {
walkFileTree({ isDeep, dirPath: subPath, fileFilter, callback })
return
}
}
callback({ file, subPath, dirs, isDirectory })
})
}
}
/**
* 获取根目录 package.json 中的 version
* @param {String} 对象的 Key
*/
const getTinyVersion = (key = 'version') => {
const packageJson = fs.readJsonSync(pathJoin('..', 'package.json'))
return packageJson[key] || packageJson
}
/**
* 获取指定包名的版本号
*
* @param {String} name NPM 包名
* @param {String} context 上下文
* @returns
*/
const getVersion = (name, context = '..') => {
let version
const packageJSON = getTinyVersion('full')
try {
version = fs.readJsonSync(pathJoin(context, 'node_modules', name, 'package.json')).version
} catch (e) {
version = (packageJSON.devDependencies || packageJSON.dependencies || {})[name] || packageJSON.version
}
return '?v=' + version.replace(/[\^|~]/g, '')
}
/**
* 在控制台显示绿色提示
* @param {String} 提示内容
*/
const logGreen = (str) => {
logger(chalk.green('### ' + str))
}
/**
* 在控制台显示黄色提示
* @param {String} 提示内容
*/
const logYellow = (str) => {
logger(chalk.yellow('### ' + str))
}
/**
* 在控制台显示青色提示
* @param {String} 提示内容
*/
const logCyan = (str) => {
logger(chalk.cyan('### ' + str))
}
/**
* 在控制台显示红色提示
* @param {String} 提示内容
*/
const logRed = (str) => {
logger(chalk.red('### ' + str))
}
module.exports = {
logRed,
execCmd,
logCyan,
pathJoin,
logGreen,
logYellow,
kebabCase,
assetsPath,
capitalize,
getVersion,
resolveCwd,
getInputCmd,
walkFileTree,
renderTemplate,
prettierFormat,
getTinyVersion,
getComponentName,
getCurrentCliTool,
capitalizeKebabCase
}