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

1115 lines
22 KiB
JavaScript

const util = require('./util')
let source
let parseState
let stack
let pos
let line
let column
let token
let key
let root
module.exports = function parse (text, reviver) {
source = String(text)
parseState = 'start'
stack = []
pos = 0
line = 1
column = 0
token = undefined
key = undefined
root = undefined
do {
token = lex()
// This code is unreachable.
// if (!parseStates[parseState]) {
// throw invalidParseState()
// }
parseStates[parseState]()
} while (token.type !== 'eof')
if (typeof reviver === 'function') {
return internalize({'': root}, '', reviver)
}
return root
}
function internalize (holder, name, reviver) {
const value = holder[name]
if (value != null && typeof value === 'object') {
if (Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {
const key = String(i)
const replacement = internalize(value, key, reviver)
if (replacement === undefined) {
delete value[key]
} else {
Object.defineProperty(value, key, {
value: replacement,
writable: true,
enumerable: true,
configurable: true,
})
}
}
} else {
for (const key in value) {
const replacement = internalize(value, key, reviver)
if (replacement === undefined) {
delete value[key]
} else {
Object.defineProperty(value, key, {
value: replacement,
writable: true,
enumerable: true,
configurable: true,
})
}
}
}
}
return reviver.call(holder, name, value)
}
let lexState
let buffer
let doubleQuote
let sign
let c
function lex () {
lexState = 'default'
buffer = ''
doubleQuote = false
sign = 1
for (;;) {
c = peek()
// This code is unreachable.
// if (!lexStates[lexState]) {
// throw invalidLexState(lexState)
// }
const token = lexStates[lexState]()
if (token) {
return token
}
}
}
function peek () {
if (source[pos]) {
return String.fromCodePoint(source.codePointAt(pos))
}
}
function read () {
const c = peek()
if (c === '\n') {
line++
column = 0
} else if (c) {
column += c.length
} else {
column++
}
if (c) {
pos += c.length
}
return c
}
const lexStates = {
default () {
switch (c) {
case '\t':
case '\v':
case '\f':
case ' ':
case '\u00A0':
case '\uFEFF':
case '\n':
case '\r':
case '\u2028':
case '\u2029':
read()
return
case '/':
read()
lexState = 'comment'
return
case undefined:
read()
return newToken('eof')
}
if (util.isSpaceSeparator(c)) {
read()
return
}
// This code is unreachable.
// if (!lexStates[parseState]) {
// throw invalidLexState(parseState)
// }
return lexStates[parseState]()
},
comment () {
switch (c) {
case '*':
read()
lexState = 'multiLineComment'
return
case '/':
read()
lexState = 'singleLineComment'
return
}
throw invalidChar(read())
},
multiLineComment () {
switch (c) {
case '*':
read()
lexState = 'multiLineCommentAsterisk'
return
case undefined:
throw invalidChar(read())
}
read()
},
multiLineCommentAsterisk () {
switch (c) {
case '*':
read()
return
case '/':
read()
lexState = 'default'
return
case undefined:
throw invalidChar(read())
}
read()
lexState = 'multiLineComment'
},
singleLineComment () {
switch (c) {
case '\n':
case '\r':
case '\u2028':
case '\u2029':
read()
lexState = 'default'
return
case undefined:
read()
return newToken('eof')
}
read()
},
value () {
switch (c) {
case '{':
case '[':
return newToken('punctuator', read())
case 'n':
read()
literal('ull')
return newToken('null', null)
case 't':
read()
literal('rue')
return newToken('boolean', true)
case 'f':
read()
literal('alse')
return newToken('boolean', false)
case '-':
case '+':
if (read() === '-') {
sign = -1
}
lexState = 'sign'
return
case '.':
buffer = read()
lexState = 'decimalPointLeading'
return
case '0':
buffer = read()
lexState = 'zero'
return
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
buffer = read()
lexState = 'decimalInteger'
return
case 'I':
read()
literal('nfinity')
return newToken('numeric', Infinity)
case 'N':
read()
literal('aN')
return newToken('numeric', NaN)
case '"':
case "'":
doubleQuote = (read() === '"')
buffer = ''
lexState = 'string'
return
}
throw invalidChar(read())
},
identifierNameStartEscape () {
if (c !== 'u') {
throw invalidChar(read())
}
read()
const u = unicodeEscape()
switch (u) {
case '$':
case '_':
break
default:
if (!util.isIdStartChar(u)) {
throw invalidIdentifier()
}
break
}
buffer += u
lexState = 'identifierName'
},
identifierName () {
switch (c) {
case '$':
case '_':
case '\u200C':
case '\u200D':
buffer += read()
return
case '\\':
read()
lexState = 'identifierNameEscape'
return
}
if (util.isIdContinueChar(c)) {
buffer += read()
return
}
return newToken('identifier', buffer)
},
identifierNameEscape () {
if (c !== 'u') {
throw invalidChar(read())
}
read()
const u = unicodeEscape()
switch (u) {
case '$':
case '_':
case '\u200C':
case '\u200D':
break
default:
if (!util.isIdContinueChar(u)) {
throw invalidIdentifier()
}
break
}
buffer += u
lexState = 'identifierName'
},
sign () {
switch (c) {
case '.':
buffer = read()
lexState = 'decimalPointLeading'
return
case '0':
buffer = read()
lexState = 'zero'
return
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
buffer = read()
lexState = 'decimalInteger'
return
case 'I':
read()
literal('nfinity')
return newToken('numeric', sign * Infinity)
case 'N':
read()
literal('aN')
return newToken('numeric', NaN)
}
throw invalidChar(read())
},
zero () {
switch (c) {
case '.':
buffer += read()
lexState = 'decimalPoint'
return
case 'e':
case 'E':
buffer += read()
lexState = 'decimalExponent'
return
case 'x':
case 'X':
buffer += read()
lexState = 'hexadecimal'
return
}
return newToken('numeric', sign * 0)
},
decimalInteger () {
switch (c) {
case '.':
buffer += read()
lexState = 'decimalPoint'
return
case 'e':
case 'E':
buffer += read()
lexState = 'decimalExponent'
return
}
if (util.isDigit(c)) {
buffer += read()
return
}
return newToken('numeric', sign * Number(buffer))
},
decimalPointLeading () {
if (util.isDigit(c)) {
buffer += read()
lexState = 'decimalFraction'
return
}
throw invalidChar(read())
},
decimalPoint () {
switch (c) {
case 'e':
case 'E':
buffer += read()
lexState = 'decimalExponent'
return
}
if (util.isDigit(c)) {
buffer += read()
lexState = 'decimalFraction'
return
}
return newToken('numeric', sign * Number(buffer))
},
decimalFraction () {
switch (c) {
case 'e':
case 'E':
buffer += read()
lexState = 'decimalExponent'
return
}
if (util.isDigit(c)) {
buffer += read()
return
}
return newToken('numeric', sign * Number(buffer))
},
decimalExponent () {
switch (c) {
case '+':
case '-':
buffer += read()
lexState = 'decimalExponentSign'
return
}
if (util.isDigit(c)) {
buffer += read()
lexState = 'decimalExponentInteger'
return
}
throw invalidChar(read())
},
decimalExponentSign () {
if (util.isDigit(c)) {
buffer += read()
lexState = 'decimalExponentInteger'
return
}
throw invalidChar(read())
},
decimalExponentInteger () {
if (util.isDigit(c)) {
buffer += read()
return
}
return newToken('numeric', sign * Number(buffer))
},
hexadecimal () {
if (util.isHexDigit(c)) {
buffer += read()
lexState = 'hexadecimalInteger'
return
}
throw invalidChar(read())
},
hexadecimalInteger () {
if (util.isHexDigit(c)) {
buffer += read()
return
}
return newToken('numeric', sign * Number(buffer))
},
string () {
switch (c) {
case '\\':
read()
buffer += escape()
return
case '"':
if (doubleQuote) {
read()
return newToken('string', buffer)
}
buffer += read()
return
case "'":
if (!doubleQuote) {
read()
return newToken('string', buffer)
}
buffer += read()
return
case '\n':
case '\r':
throw invalidChar(read())
case '\u2028':
case '\u2029':
separatorChar(c)
break
case undefined:
throw invalidChar(read())
}
buffer += read()
},
start () {
switch (c) {
case '{':
case '[':
return newToken('punctuator', read())
// This code is unreachable since the default lexState handles eof.
// case undefined:
// return newToken('eof')
}
lexState = 'value'
},
beforePropertyName () {
switch (c) {
case '$':
case '_':
buffer = read()
lexState = 'identifierName'
return
case '\\':
read()
lexState = 'identifierNameStartEscape'
return
case '}':
return newToken('punctuator', read())
case '"':
case "'":
doubleQuote = (read() === '"')
lexState = 'string'
return
}
if (util.isIdStartChar(c)) {
buffer += read()
lexState = 'identifierName'
return
}
throw invalidChar(read())
},
afterPropertyName () {
if (c === ':') {
return newToken('punctuator', read())
}
throw invalidChar(read())
},
beforePropertyValue () {
lexState = 'value'
},
afterPropertyValue () {
switch (c) {
case ',':
case '}':
return newToken('punctuator', read())
}
throw invalidChar(read())
},
beforeArrayValue () {
if (c === ']') {
return newToken('punctuator', read())
}
lexState = 'value'
},
afterArrayValue () {
switch (c) {
case ',':
case ']':
return newToken('punctuator', read())
}
throw invalidChar(read())
},
end () {
// This code is unreachable since it's handled by the default lexState.
// if (c === undefined) {
// read()
// return newToken('eof')
// }
throw invalidChar(read())
},
}
function newToken (type, value) {
return {
type,
value,
line,
column,
}
}
function literal (s) {
for (const c of s) {
const p = peek()
if (p !== c) {
throw invalidChar(read())
}
read()
}
}
function escape () {
const c = peek()
switch (c) {
case 'b':
read()
return '\b'
case 'f':
read()
return '\f'
case 'n':
read()
return '\n'
case 'r':
read()
return '\r'
case 't':
read()
return '\t'
case 'v':
read()
return '\v'
case '0':
read()
if (util.isDigit(peek())) {
throw invalidChar(read())
}
return '\0'
case 'x':
read()
return hexEscape()
case 'u':
read()
return unicodeEscape()
case '\n':
case '\u2028':
case '\u2029':
read()
return ''
case '\r':
read()
if (peek() === '\n') {
read()
}
return ''
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
throw invalidChar(read())
case undefined:
throw invalidChar(read())
}
return read()
}
function hexEscape () {
let buffer = ''
let c = peek()
if (!util.isHexDigit(c)) {
throw invalidChar(read())
}
buffer += read()
c = peek()
if (!util.isHexDigit(c)) {
throw invalidChar(read())
}
buffer += read()
return String.fromCodePoint(parseInt(buffer, 16))
}
function unicodeEscape () {
let buffer = ''
let count = 4
while (count-- > 0) {
const c = peek()
if (!util.isHexDigit(c)) {
throw invalidChar(read())
}
buffer += read()
}
return String.fromCodePoint(parseInt(buffer, 16))
}
const parseStates = {
start () {
if (token.type === 'eof') {
throw invalidEOF()
}
push()
},
beforePropertyName () {
switch (token.type) {
case 'identifier':
case 'string':
key = token.value
parseState = 'afterPropertyName'
return
case 'punctuator':
// This code is unreachable since it's handled by the lexState.
// if (token.value !== '}') {
// throw invalidToken()
// }
pop()
return
case 'eof':
throw invalidEOF()
}
// This code is unreachable since it's handled by the lexState.
// throw invalidToken()
},
afterPropertyName () {
// This code is unreachable since it's handled by the lexState.
// if (token.type !== 'punctuator' || token.value !== ':') {
// throw invalidToken()
// }
if (token.type === 'eof') {
throw invalidEOF()
}
parseState = 'beforePropertyValue'
},
beforePropertyValue () {
if (token.type === 'eof') {
throw invalidEOF()
}
push()
},
beforeArrayValue () {
if (token.type === 'eof') {
throw invalidEOF()
}
if (token.type === 'punctuator' && token.value === ']') {
pop()
return
}
push()
},
afterPropertyValue () {
// This code is unreachable since it's handled by the lexState.
// if (token.type !== 'punctuator') {
// throw invalidToken()
// }
if (token.type === 'eof') {
throw invalidEOF()
}
switch (token.value) {
case ',':
parseState = 'beforePropertyName'
return
case '}':
pop()
}
// This code is unreachable since it's handled by the lexState.
// throw invalidToken()
},
afterArrayValue () {
// This code is unreachable since it's handled by the lexState.
// if (token.type !== 'punctuator') {
// throw invalidToken()
// }
if (token.type === 'eof') {
throw invalidEOF()
}
switch (token.value) {
case ',':
parseState = 'beforeArrayValue'
return
case ']':
pop()
}
// This code is unreachable since it's handled by the lexState.
// throw invalidToken()
},
end () {
// This code is unreachable since it's handled by the lexState.
// if (token.type !== 'eof') {
// throw invalidToken()
// }
},
}
function push () {
let value
switch (token.type) {
case 'punctuator':
switch (token.value) {
case '{':
value = {}
break
case '[':
value = []
break
}
break
case 'null':
case 'boolean':
case 'numeric':
case 'string':
value = token.value
break
// This code is unreachable.
// default:
// throw invalidToken()
}
if (root === undefined) {
root = value
} else {
const parent = stack[stack.length - 1]
if (Array.isArray(parent)) {
parent.push(value)
} else {
Object.defineProperty(parent, key, {
value,
writable: true,
enumerable: true,
configurable: true,
})
}
}
if (value !== null && typeof value === 'object') {
stack.push(value)
if (Array.isArray(value)) {
parseState = 'beforeArrayValue'
} else {
parseState = 'beforePropertyName'
}
} else {
const current = stack[stack.length - 1]
if (current == null) {
parseState = 'end'
} else if (Array.isArray(current)) {
parseState = 'afterArrayValue'
} else {
parseState = 'afterPropertyValue'
}
}
}
function pop () {
stack.pop()
const current = stack[stack.length - 1]
if (current == null) {
parseState = 'end'
} else if (Array.isArray(current)) {
parseState = 'afterArrayValue'
} else {
parseState = 'afterPropertyValue'
}
}
// This code is unreachable.
// function invalidParseState () {
// return new Error(`JSON5: invalid parse state '${parseState}'`)
// }
// This code is unreachable.
// function invalidLexState (state) {
// return new Error(`JSON5: invalid lex state '${state}'`)
// }
function invalidChar (c) {
if (c === undefined) {
return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
}
return syntaxError(`JSON5: invalid character '${formatChar(c)}' at ${line}:${column}`)
}
function invalidEOF () {
return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
}
// This code is unreachable.
// function invalidToken () {
// if (token.type === 'eof') {
// return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
// }
// const c = String.fromCodePoint(token.value.codePointAt(0))
// return syntaxError(`JSON5: invalid character '${formatChar(c)}' at ${line}:${column}`)
// }
function invalidIdentifier () {
column -= 5
return syntaxError(`JSON5: invalid identifier character at ${line}:${column}`)
}
function separatorChar (c) {
console.warn(`JSON5: '${formatChar(c)}' in strings is not valid ECMAScript; consider escaping`)
}
function formatChar (c) {
const replacements = {
"'": "\\'",
'"': '\\"',
'\\': '\\\\',
'\b': '\\b',
'\f': '\\f',
'\n': '\\n',
'\r': '\\r',
'\t': '\\t',
'\v': '\\v',
'\0': '\\0',
'\u2028': '\\u2028',
'\u2029': '\\u2029',
}
if (replacements[c]) {
return replacements[c]
}
if (c < ' ') {
const hexString = c.charCodeAt(0).toString(16)
return '\\x' + ('00' + hexString).substring(hexString.length)
}
return c
}
function syntaxError (message) {
const err = new SyntaxError(message)
err.lineNumber = line
err.columnNumber = column
return err
}