Bhargava 6063bd1724 Help Project:
1. Initial Commit - a boiler plate code and POC to realize the concept of context
sensitive help
2. Frontend code written in ReactJS
3. Backend code written in Java, Spring Boot Framework
4. Frontend Start:
        pre-requisites : node, npm
	npm run dev  ==> to start the frontend vite server
5. Backend Start:
	pre-requisites : java, mvn
        mvn spring-boot:run  ==> to start the backend server
6. Visit http://localhost:5173/ for basic demo of help, press F1 in textboxes
7. Visit http://localhost:5173/editor and enter "admin123" to add/modify texts.

Happy Coding !!!

Thank you,
Bhargava.
2025-07-04 15:54:13 +05:30

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('')
}