feat(server): enhance frontmatter parsing for skill descriptions
Some checks failed
Deploy skills-market-server / deploy (push) Has been cancelled
Some checks failed
Deploy skills-market-server / deploy (push) Has been cancelled
- Integrated a new utility function `parseFrontmatterScalarKey` to streamline the extraction of the description from skill files. - Improved the logic for handling frontmatter, ensuring more robust parsing and trimming of description values.
This commit is contained in:
parent
33a59df4ae
commit
de65426d64
77
lib/frontmatter-scalar.js
Normal file
77
lib/frontmatter-scalar.js
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* 从 frontmatter 文本里读一个顶层标量(整块 metadata 已由调用方从 --- … --- 切好)。
|
||||
* 多行块(description: > / |):从下一行起收到「下一个顶层键」或 metadata 结束为止。
|
||||
*/
|
||||
|
||||
function escapeRegExp(s) {
|
||||
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||||
}
|
||||
|
||||
/** 下一行若是顶层键 `foo:`(行首无缩进),则当前块结束。 */
|
||||
function isTopLevelKeyLine(line) {
|
||||
const t = line.trimStart()
|
||||
if (!t || t.startsWith('#')) return false
|
||||
return /^[A-Za-z_][\w-]*\s*:\s/.test(t)
|
||||
}
|
||||
|
||||
function minIndentOfNonEmpty(lines) {
|
||||
let min = Infinity
|
||||
for (const l of lines) {
|
||||
if (!l.trim()) continue
|
||||
const n = l.match(/^(\s*)/)[1].length
|
||||
if (n < min) min = n
|
||||
}
|
||||
return min === Infinity ? 0 : min
|
||||
}
|
||||
|
||||
function dedent(lines) {
|
||||
const min = minIndentOfNonEmpty(lines)
|
||||
return lines.map((l) => (l.length === 0 ? '' : l.slice(min)))
|
||||
}
|
||||
|
||||
function parseFrontmatterScalarKey(fmBlock, key) {
|
||||
if (!fmBlock || !key) return null
|
||||
const lines = fmBlock.split(/\r?\n/)
|
||||
const keyRe = new RegExp(`^${escapeRegExp(key)}:\\s*(.*)$`)
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const m = lines[i].match(keyRe)
|
||||
if (!m) continue
|
||||
|
||||
let after = m[1].replace(/\s+$/, '')
|
||||
const blockHead = after.match(/^([>|])([-+]?)\s*(.*)$/)
|
||||
|
||||
if (blockHead) {
|
||||
const mode = blockHead[1]
|
||||
const sameLine = (blockHead[3] || '').trimEnd()
|
||||
const raw = []
|
||||
if (sameLine) raw.push(sameLine)
|
||||
|
||||
for (let j = i + 1; j < lines.length; j++) {
|
||||
const line = lines[j]
|
||||
if (line.length > 0 && !/^\s/.test(line) && isTopLevelKeyLine(line)) break
|
||||
raw.push(line)
|
||||
}
|
||||
|
||||
const body = dedent(raw)
|
||||
if (mode === '>') {
|
||||
return body
|
||||
.map((l) => l.trim())
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
.trim()
|
||||
}
|
||||
return body.join('\n').trim()
|
||||
}
|
||||
|
||||
const t = after.trim()
|
||||
if ((t.startsWith('"') && t.endsWith('"')) || (t.startsWith("'") && t.endsWith("'"))) {
|
||||
return t.slice(1, -1)
|
||||
}
|
||||
if (t) return t.replace(/^["']|["']$/g, '')
|
||||
return ''
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
module.exports = { parseFrontmatterScalarKey }
|
||||
11
server.js
11
server.js
@ -3,6 +3,7 @@ const express = require('express')
|
||||
const cors = require('cors')
|
||||
const path = require('path')
|
||||
const { MongoClient, ObjectId } = require('mongodb')
|
||||
const { parseFrontmatterScalarKey } = require('./lib/frontmatter-scalar')
|
||||
const { createAuthRoutes } = require('./routes/auth')
|
||||
|
||||
const app = express()
|
||||
@ -196,16 +197,16 @@ function canUserAccessTaggedResource(user, resourceTags) {
|
||||
function extractDescription(files) {
|
||||
const skillFile = files.find(f => f.path === 'SKILL.md' || f.path.endsWith('SKILL.md'))
|
||||
if (!skillFile) return ''
|
||||
|
||||
|
||||
const content = skillFile.content
|
||||
const fmMatch = content.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/)
|
||||
if (fmMatch) {
|
||||
const descMatch = fmMatch[1].match(/^description:\s*(.+)$/m)
|
||||
if (descMatch) {
|
||||
return descMatch[1].trim().replace(/^["']|["']$/g, '')
|
||||
const fromFm = parseFrontmatterScalarKey(fmMatch[1], 'description')
|
||||
if (fromFm != null && String(fromFm).trim() !== '') {
|
||||
return String(fromFm).trim()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const lines = content.split('\n')
|
||||
let inFrontmatter = false
|
||||
for (const line of lines) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user