主要功能: - 修改RequirementModal支持12个订单班选择 - 添加OrderClassIconMap图标映射组件 - Store中添加selectedOrderClass状态管理 - WorkflowPage支持传递orderClass参数 - web_result添加URL参数切换功能 - 创建order-class-handler.js动态处理页面主题 技术改进: - 创建软链接关联订单班数据目录 - 生成wenlu.json和food.json数据结构 - 删除重复的web_result目录 - 添加测试页面test-order-class.html 影响范围: - 展会策划系统现支持12个订单班 - 结果展示页面自动适配不同订单班主题 - 用户可选择不同行业生成对应方案 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
175 lines
4.5 KiB
JavaScript
175 lines
4.5 KiB
JavaScript
/**
|
|
* @import {SafeConfig, State} from 'mdast-util-to-markdown'
|
|
*/
|
|
|
|
import {encodeCharacterReference} from './encode-character-reference.js'
|
|
import {patternInScope} from './pattern-in-scope.js'
|
|
|
|
/**
|
|
* Make a string safe for embedding in markdown constructs.
|
|
*
|
|
* In markdown, almost all punctuation characters can, in certain cases,
|
|
* result in something.
|
|
* Whether they do is highly subjective to where they happen and in what
|
|
* they happen.
|
|
*
|
|
* To solve this, `mdast-util-to-markdown` tracks:
|
|
*
|
|
* * Characters before and after something;
|
|
* * What “constructs” we are in.
|
|
*
|
|
* This information is then used by this function to escape or encode
|
|
* special characters.
|
|
*
|
|
* @param {State} state
|
|
* Info passed around about the current state.
|
|
* @param {string | null | undefined} input
|
|
* Raw value to make safe.
|
|
* @param {SafeConfig} config
|
|
* Configuration.
|
|
* @returns {string}
|
|
* Serialized markdown safe for embedding.
|
|
*/
|
|
export function safe(state, input, config) {
|
|
const value = (config.before || '') + (input || '') + (config.after || '')
|
|
/** @type {Array<number>} */
|
|
const positions = []
|
|
/** @type {Array<string>} */
|
|
const result = []
|
|
/** @type {Record<number, {before: boolean, after: boolean}>} */
|
|
const infos = {}
|
|
let index = -1
|
|
|
|
while (++index < state.unsafe.length) {
|
|
const pattern = state.unsafe[index]
|
|
|
|
if (!patternInScope(state.stack, pattern)) {
|
|
continue
|
|
}
|
|
|
|
const expression = state.compilePattern(pattern)
|
|
/** @type {RegExpExecArray | null} */
|
|
let match
|
|
|
|
while ((match = expression.exec(value))) {
|
|
const before = 'before' in pattern || Boolean(pattern.atBreak)
|
|
const after = 'after' in pattern
|
|
const position = match.index + (before ? match[1].length : 0)
|
|
|
|
if (positions.includes(position)) {
|
|
if (infos[position].before && !before) {
|
|
infos[position].before = false
|
|
}
|
|
|
|
if (infos[position].after && !after) {
|
|
infos[position].after = false
|
|
}
|
|
} else {
|
|
positions.push(position)
|
|
infos[position] = {before, after}
|
|
}
|
|
}
|
|
}
|
|
|
|
positions.sort(numerical)
|
|
|
|
let start = config.before ? config.before.length : 0
|
|
const end = value.length - (config.after ? config.after.length : 0)
|
|
index = -1
|
|
|
|
while (++index < positions.length) {
|
|
const position = positions[index]
|
|
|
|
// Character before or after matched:
|
|
if (position < start || position >= end) {
|
|
continue
|
|
}
|
|
|
|
// If this character is supposed to be escaped because it has a condition on
|
|
// the next character, and the next character is definitly being escaped,
|
|
// then skip this escape.
|
|
if (
|
|
(position + 1 < end &&
|
|
positions[index + 1] === position + 1 &&
|
|
infos[position].after &&
|
|
!infos[position + 1].before &&
|
|
!infos[position + 1].after) ||
|
|
(positions[index - 1] === position - 1 &&
|
|
infos[position].before &&
|
|
!infos[position - 1].before &&
|
|
!infos[position - 1].after)
|
|
) {
|
|
continue
|
|
}
|
|
|
|
if (start !== position) {
|
|
// If we have to use a character reference, an ampersand would be more
|
|
// correct, but as backslashes only care about punctuation, either will
|
|
// do the trick
|
|
result.push(escapeBackslashes(value.slice(start, position), '\\'))
|
|
}
|
|
|
|
start = position
|
|
|
|
if (
|
|
/[!-/:-@[-`{-~]/.test(value.charAt(position)) &&
|
|
(!config.encode || !config.encode.includes(value.charAt(position)))
|
|
) {
|
|
// Character escape.
|
|
result.push('\\')
|
|
} else {
|
|
// Character reference.
|
|
result.push(encodeCharacterReference(value.charCodeAt(position)))
|
|
start++
|
|
}
|
|
}
|
|
|
|
result.push(escapeBackslashes(value.slice(start, end), config.after))
|
|
|
|
return result.join('')
|
|
}
|
|
|
|
/**
|
|
* @param {number} a
|
|
* @param {number} b
|
|
* @returns {number}
|
|
*/
|
|
function numerical(a, b) {
|
|
return a - b
|
|
}
|
|
|
|
/**
|
|
* @param {string} value
|
|
* @param {string} after
|
|
* @returns {string}
|
|
*/
|
|
function escapeBackslashes(value, after) {
|
|
const expression = /\\(?=[!-/:-@[-`{-~])/g
|
|
/** @type {Array<number>} */
|
|
const positions = []
|
|
/** @type {Array<string>} */
|
|
const results = []
|
|
const whole = value + after
|
|
let index = -1
|
|
let start = 0
|
|
/** @type {RegExpExecArray | null} */
|
|
let match
|
|
|
|
while ((match = expression.exec(whole))) {
|
|
positions.push(match.index)
|
|
}
|
|
|
|
while (++index < positions.length) {
|
|
if (start !== positions[index]) {
|
|
results.push(value.slice(start, positions[index]))
|
|
}
|
|
|
|
results.push('\\')
|
|
start = positions[index]
|
|
}
|
|
|
|
results.push(value.slice(start))
|
|
|
|
return results.join('')
|
|
}
|