116 lines
3.0 KiB
JavaScript
116 lines
3.0 KiB
JavaScript
import { existsSync, readFileSync } from 'node:fs'
|
|
import { extname, join } from 'node:path'
|
|
import process from 'node:process'
|
|
|
|
import { parse as VueParser } from 'vue/compiler-sfc'
|
|
import { normalizePath } from 'vite'
|
|
|
|
function stripJsonComments(jsonText) {
|
|
return jsonText
|
|
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
.replace(/(^|[^:\\])\/\/.*$/gm, '$1')
|
|
}
|
|
|
|
function parseJsonc(jsonText) {
|
|
const withoutComments = stripJsonComments(jsonText)
|
|
const withoutTrailingComma = withoutComments.replace(/,\s*([}\]])/g, '$1')
|
|
return JSON.parse(withoutTrailingComma)
|
|
}
|
|
|
|
export async function parseSFC(code) {
|
|
try {
|
|
return VueParser(code, { pad: 'space' }).descriptor
|
|
} catch {
|
|
throw new Error('[@up-root] Vue version must support compiler-sfc parser.')
|
|
}
|
|
}
|
|
|
|
const PAGE_FILE_EXTS = ['.vue', '.nvue', '.uvue']
|
|
|
|
export function formatPagePath(root, path) {
|
|
const joinedPath = join(root, path)
|
|
const pathExt = extname(joinedPath)
|
|
|
|
if (pathExt) {
|
|
return normalizePath(joinedPath)
|
|
}
|
|
|
|
const pageFilePath = PAGE_FILE_EXTS
|
|
.map(fileExt => `${joinedPath}${fileExt}`)
|
|
.find(filePath => existsSync(filePath))
|
|
|
|
return normalizePath(pageFilePath || `${joinedPath}.vue`)
|
|
}
|
|
|
|
export function loadPagesJson(path, rootPath) {
|
|
const pagesJsonRaw = readFileSync(path, 'utf-8')
|
|
const parsed = parseJsonc(pagesJsonRaw) || {}
|
|
const pages = parsed.pages || []
|
|
const subPackages = parsed.subPackages || []
|
|
|
|
return [
|
|
...pages.map((page) => formatPagePath(rootPath, page.path)),
|
|
...subPackages
|
|
.map(({ pages: subPages = [], root = '' }) => {
|
|
return subPages.map((page) => formatPagePath(join(rootPath, root), page.path))
|
|
})
|
|
.flat(),
|
|
]
|
|
}
|
|
|
|
export function toKebabCase(str) {
|
|
return str
|
|
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
.replace(/[_\s]+/g, '-')
|
|
.toLowerCase()
|
|
}
|
|
|
|
export function toPascalCase(str) {
|
|
return str
|
|
.replace(/(^\w|-+\w)/g, (match) => match.toUpperCase().replace(/-/g, ''))
|
|
}
|
|
|
|
export function findNode(sfc, rawTagName) {
|
|
const templateSource = sfc.template?.content
|
|
if (!templateSource) return
|
|
|
|
let tagName = ''
|
|
if (templateSource.includes(`<${toKebabCase(rawTagName)}`)) {
|
|
tagName = toKebabCase(rawTagName)
|
|
} else if (templateSource.includes(`<${toPascalCase(rawTagName)}`)) {
|
|
tagName = toPascalCase(rawTagName)
|
|
}
|
|
if (!tagName) return
|
|
|
|
const nodeAst = sfc.template?.ast
|
|
if (!nodeAst) return
|
|
|
|
const traverse = (nodes) => {
|
|
for (const node of nodes) {
|
|
if (node.type === 1) {
|
|
if (node.tag === tagName) return node
|
|
if (node.children?.length) {
|
|
const found = traverse(node.children)
|
|
if (found) return found
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return traverse(nodeAst.children)
|
|
}
|
|
|
|
const platform = process.env.UNI_PLATFORM
|
|
|
|
export function normalizePlatformPath(id) {
|
|
const idExt = extname(id)
|
|
if (idExt !== '.vue') return id
|
|
if (!id.includes(`.${platform}.`)) return id
|
|
return id.replace(`.${platform}.`, '.')
|
|
}
|
|
|
|
export function toArray(value) {
|
|
if (!value) return []
|
|
return Array.isArray(value) ? value : [value]
|
|
}
|