feat: publish HoloLake model-native living system source
This commit is contained in:
parent
6ad10edde1
commit
c395dd3a99
2467 changed files with 615073 additions and 0 deletions
92
product-source/hololake-platform/src/utils/markdownFences.ts
Normal file
92
product-source/hololake-platform/src/utils/markdownFences.ts
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
export type MarkdownFenceCharacter = '`' | '~'
|
||||
|
||||
export interface MarkdownFence {
|
||||
character: MarkdownFenceCharacter
|
||||
length: number
|
||||
}
|
||||
|
||||
export interface MarkdownFenceScanOptions {
|
||||
closingMustEndLine?: boolean
|
||||
maxLeadingSpaces?: number | null
|
||||
}
|
||||
|
||||
const DEFAULT_MAX_LEADING_SPACES = 3
|
||||
|
||||
function fencePrefixPattern(options: MarkdownFenceScanOptions): RegExp {
|
||||
return options.maxLeadingSpaces === null
|
||||
? /^(\s*)(`{3,}|~{3,})/u
|
||||
: /^( *)(`{3,}|~{3,})/u
|
||||
}
|
||||
|
||||
function hasAllowedIndent(match: RegExpExecArray, options: MarkdownFenceScanOptions): boolean {
|
||||
if (options.maxLeadingSpaces === null) return true
|
||||
return (match[1]?.length ?? 0) <= (options.maxLeadingSpaces ?? DEFAULT_MAX_LEADING_SPACES)
|
||||
}
|
||||
|
||||
function readFenceMatch(line: string, options: MarkdownFenceScanOptions): RegExpExecArray | null {
|
||||
const match = fencePrefixPattern(options).exec(line)
|
||||
return match && hasAllowedIndent(match, options) ? match : null
|
||||
}
|
||||
|
||||
function fenceFromMatch(match: RegExpExecArray): MarkdownFence {
|
||||
const fence = match[2] ?? ''
|
||||
return {
|
||||
character: fence.charAt(0) as MarkdownFenceCharacter,
|
||||
length: fence.length,
|
||||
}
|
||||
}
|
||||
|
||||
export function readMarkdownFence(
|
||||
line: string,
|
||||
options: MarkdownFenceScanOptions = {},
|
||||
): MarkdownFence | null {
|
||||
const match = readFenceMatch(line, options)
|
||||
return match ? fenceFromMatch(match) : null
|
||||
}
|
||||
|
||||
function closingTailIsAllowed(
|
||||
line: string,
|
||||
match: RegExpExecArray,
|
||||
options: MarkdownFenceScanOptions,
|
||||
): boolean {
|
||||
if (options.closingMustEndLine === false) return true
|
||||
return /^[ \t]*$/u.test(line.slice(match[0].length))
|
||||
}
|
||||
|
||||
function isClosingMarkdownFence(
|
||||
line: string,
|
||||
opening: MarkdownFence,
|
||||
options: MarkdownFenceScanOptions,
|
||||
): boolean {
|
||||
const match = readFenceMatch(line, options)
|
||||
if (!match) return false
|
||||
|
||||
const closing = fenceFromMatch(match)
|
||||
return closing.character === opening.character
|
||||
&& closing.length >= opening.length
|
||||
&& closingTailIsAllowed(line, match, options)
|
||||
}
|
||||
|
||||
export function advanceMarkdownFence(
|
||||
line: string,
|
||||
current: MarkdownFence | null,
|
||||
options: MarkdownFenceScanOptions = {},
|
||||
): MarkdownFence | null {
|
||||
if (current) {
|
||||
return isClosingMarkdownFence(line, current, options) ? null : current
|
||||
}
|
||||
return readMarkdownFence(line, options)
|
||||
}
|
||||
|
||||
export function isInsideMarkdownFence(
|
||||
markdownBeforeCursor: string,
|
||||
options: MarkdownFenceScanOptions = {},
|
||||
): boolean {
|
||||
let fence: MarkdownFence | null = null
|
||||
|
||||
for (const line of markdownBeforeCursor.split(/\r?\n/u)) {
|
||||
fence = advanceMarkdownFence(line, fence, options)
|
||||
}
|
||||
|
||||
return fence !== null
|
||||
}
|
||||
Loading…
Reference in a new issue