forked from FINAKON/HelpProject
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.
266 lines
6.6 KiB
JavaScript
266 lines
6.6 KiB
JavaScript
'use strict'
|
|
|
|
let { nanoid } = require('nanoid/non-secure')
|
|
let { isAbsolute, resolve } = require('path')
|
|
let { SourceMapConsumer, SourceMapGenerator } = require('source-map-js')
|
|
let { fileURLToPath, pathToFileURL } = require('url')
|
|
|
|
let CssSyntaxError = require('./css-syntax-error')
|
|
let PreviousMap = require('./previous-map')
|
|
let terminalHighlight = require('./terminal-highlight')
|
|
|
|
let lineToIndexCache = Symbol('lineToIndexCache')
|
|
|
|
let sourceMapAvailable = Boolean(SourceMapConsumer && SourceMapGenerator)
|
|
let pathAvailable = Boolean(resolve && isAbsolute)
|
|
|
|
function getLineToIndex(input) {
|
|
if (input[lineToIndexCache]) return input[lineToIndexCache]
|
|
let lines = input.css.split('\n')
|
|
let lineToIndex = new Array(lines.length)
|
|
let prevIndex = 0
|
|
|
|
for (let i = 0, l = lines.length; i < l; i++) {
|
|
lineToIndex[i] = prevIndex
|
|
prevIndex += lines[i].length + 1
|
|
}
|
|
|
|
input[lineToIndexCache] = lineToIndex
|
|
return lineToIndex
|
|
}
|
|
|
|
class Input {
|
|
get from() {
|
|
return this.file || this.id
|
|
}
|
|
|
|
constructor(css, opts = {}) {
|
|
if (
|
|
css === null ||
|
|
typeof css === 'undefined' ||
|
|
(typeof css === 'object' && !css.toString)
|
|
) {
|
|
throw new Error(`PostCSS received ${css} instead of CSS string`)
|
|
}
|
|
|
|
this.css = css.toString()
|
|
|
|
if (this.css[0] === '\uFEFF' || this.css[0] === '\uFFFE') {
|
|
this.hasBOM = true
|
|
this.css = this.css.slice(1)
|
|
} else {
|
|
this.hasBOM = false
|
|
}
|
|
|
|
this.document = this.css
|
|
if (opts.document) this.document = opts.document.toString()
|
|
|
|
if (opts.from) {
|
|
if (
|
|
!pathAvailable ||
|
|
/^\w+:\/\//.test(opts.from) ||
|
|
isAbsolute(opts.from)
|
|
) {
|
|
this.file = opts.from
|
|
} else {
|
|
this.file = resolve(opts.from)
|
|
}
|
|
}
|
|
|
|
if (pathAvailable && sourceMapAvailable) {
|
|
let map = new PreviousMap(this.css, opts)
|
|
if (map.text) {
|
|
this.map = map
|
|
let file = map.consumer().file
|
|
if (!this.file && file) this.file = this.mapResolve(file)
|
|
}
|
|
}
|
|
|
|
if (!this.file) {
|
|
this.id = '<input css ' + nanoid(6) + '>'
|
|
}
|
|
if (this.map) this.map.file = this.from
|
|
}
|
|
|
|
error(message, line, column, opts = {}) {
|
|
let endColumn, endLine, endOffset, offset, result
|
|
|
|
if (line && typeof line === 'object') {
|
|
let start = line
|
|
let end = column
|
|
if (typeof start.offset === 'number') {
|
|
offset = start.offset
|
|
let pos = this.fromOffset(offset)
|
|
line = pos.line
|
|
column = pos.col
|
|
} else {
|
|
line = start.line
|
|
column = start.column
|
|
offset = this.fromLineAndColumn(line, column)
|
|
}
|
|
if (typeof end.offset === 'number') {
|
|
endOffset = end.offset
|
|
let pos = this.fromOffset(endOffset)
|
|
endLine = pos.line
|
|
endColumn = pos.col
|
|
} else {
|
|
endLine = end.line
|
|
endColumn = end.column
|
|
endOffset = this.fromLineAndColumn(end.line, end.column)
|
|
}
|
|
} else if (!column) {
|
|
offset = line
|
|
let pos = this.fromOffset(offset)
|
|
line = pos.line
|
|
column = pos.col
|
|
} else {
|
|
offset = this.fromLineAndColumn(line, column)
|
|
}
|
|
|
|
let origin = this.origin(line, column, endLine, endColumn)
|
|
if (origin) {
|
|
result = new CssSyntaxError(
|
|
message,
|
|
origin.endLine === undefined
|
|
? origin.line
|
|
: { column: origin.column, line: origin.line },
|
|
origin.endLine === undefined
|
|
? origin.column
|
|
: { column: origin.endColumn, line: origin.endLine },
|
|
origin.source,
|
|
origin.file,
|
|
opts.plugin
|
|
)
|
|
} else {
|
|
result = new CssSyntaxError(
|
|
message,
|
|
endLine === undefined ? line : { column, line },
|
|
endLine === undefined ? column : { column: endColumn, line: endLine },
|
|
this.css,
|
|
this.file,
|
|
opts.plugin
|
|
)
|
|
}
|
|
|
|
result.input = { column, endColumn, endLine, endOffset, line, offset, source: this.css }
|
|
if (this.file) {
|
|
if (pathToFileURL) {
|
|
result.input.url = pathToFileURL(this.file).toString()
|
|
}
|
|
result.input.file = this.file
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
fromLineAndColumn(line, column) {
|
|
let lineToIndex = getLineToIndex(this)
|
|
let index = lineToIndex[line - 1]
|
|
return index + column - 1
|
|
}
|
|
|
|
fromOffset(offset) {
|
|
let lineToIndex = getLineToIndex(this)
|
|
let lastLine = lineToIndex[lineToIndex.length - 1]
|
|
|
|
let min = 0
|
|
if (offset >= lastLine) {
|
|
min = lineToIndex.length - 1
|
|
} else {
|
|
let max = lineToIndex.length - 2
|
|
let mid
|
|
while (min < max) {
|
|
mid = min + ((max - min) >> 1)
|
|
if (offset < lineToIndex[mid]) {
|
|
max = mid - 1
|
|
} else if (offset >= lineToIndex[mid + 1]) {
|
|
min = mid + 1
|
|
} else {
|
|
min = mid
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
col: offset - lineToIndex[min] + 1,
|
|
line: min + 1
|
|
}
|
|
}
|
|
|
|
mapResolve(file) {
|
|
if (/^\w+:\/\//.test(file)) {
|
|
return file
|
|
}
|
|
return resolve(this.map.consumer().sourceRoot || this.map.root || '.', file)
|
|
}
|
|
|
|
origin(line, column, endLine, endColumn) {
|
|
if (!this.map) return false
|
|
let consumer = this.map.consumer()
|
|
|
|
let from = consumer.originalPositionFor({ column, line })
|
|
if (!from.source) return false
|
|
|
|
let to
|
|
if (typeof endLine === 'number') {
|
|
to = consumer.originalPositionFor({ column: endColumn, line: endLine })
|
|
}
|
|
|
|
let fromUrl
|
|
|
|
if (isAbsolute(from.source)) {
|
|
fromUrl = pathToFileURL(from.source)
|
|
} else {
|
|
fromUrl = new URL(
|
|
from.source,
|
|
this.map.consumer().sourceRoot || pathToFileURL(this.map.mapFile)
|
|
)
|
|
}
|
|
|
|
let result = {
|
|
column: from.column,
|
|
endColumn: to && to.column,
|
|
endLine: to && to.line,
|
|
line: from.line,
|
|
url: fromUrl.toString()
|
|
}
|
|
|
|
if (fromUrl.protocol === 'file:') {
|
|
if (fileURLToPath) {
|
|
result.file = fileURLToPath(fromUrl)
|
|
} else {
|
|
/* c8 ignore next 2 */
|
|
throw new Error(`file: protocol is not available in this PostCSS build`)
|
|
}
|
|
}
|
|
|
|
let source = consumer.sourceContentFor(from.source)
|
|
if (source) result.source = source
|
|
|
|
return result
|
|
}
|
|
|
|
toJSON() {
|
|
let json = {}
|
|
for (let name of ['hasBOM', 'css', 'file', 'id']) {
|
|
if (this[name] != null) {
|
|
json[name] = this[name]
|
|
}
|
|
}
|
|
if (this.map) {
|
|
json.map = { ...this.map }
|
|
if (json.map.consumerCache) {
|
|
json.map.consumerCache = undefined
|
|
}
|
|
}
|
|
return json
|
|
}
|
|
}
|
|
|
|
module.exports = Input
|
|
Input.default = Input
|
|
|
|
if (terminalHighlight && terminalHighlight.registerInput) {
|
|
terminalHighlight.registerInput(Input)
|
|
}
|