Move services to public (#6156)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev
2024-07-28 14:55:43 +07:00
committed by Andrey Sobolev
parent 9aad4a4561
commit ddecae80dd
578 changed files with 109084 additions and 390 deletions
@@ -0,0 +1,59 @@
//
// Copyright © 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import hljs from 'highlight.js'
import { hljsDefineSvelte } from './languages/svelte-hljs'
hljs.registerLanguage('svelte', hljsDefineSvelte)
export interface HighlightOptions {
language: string
}
export function highlightText (text: string, options: HighlightOptions): string {
// We should always use highlighter because it sanitizes the input
// We have to always use highlighter to ensure that the input is sanitized
const validLanguage = options.language !== '' && hljs.getLanguage(options.language) !== undefined
const language = validLanguage ? options.language : 'text'
const { value: highlighted } = hljs.highlight(text, { language })
const normalized = normalizeHighlightTags(highlighted)
return normalized
}
export function highlightLines (lines: string[], options: HighlightOptions): string[] {
const highlighted = highlightText(lines.join('\n'), options)
return highlighted.split('\n')
}
function normalizeHighlightTags (highlighted: string): string {
const openTags: string[] = []
const normalized = highlighted.replace(/(<span[^>]*>)|(<\/span>)|(\n)/g, (match) => {
if (match === '\n') {
return '</span>'.repeat(openTags.length) + '\n' + openTags.join('')
}
if (match === '</span>') {
openTags.pop()
} else {
openTags.push(match)
}
return match
})
return normalized
}
@@ -0,0 +1,17 @@
//
// Copyright © 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
export * from './highlight'
export * from './render'
@@ -0,0 +1,48 @@
export function hljsDefineSvelte (hljs: any): any {
return {
subLanguage: 'xml',
contains: [
hljs.COMMENT('<!--', '-->', {
relevance: 10
}),
{
begin: /^(\s*)(<script(\s*context="module")?>)/gm,
end: /^(\s*)(<\/script>)/gm,
subLanguage: 'javascript',
excludeBegin: true,
excludeEnd: true,
contains: [
{
begin: /^(\s*)(\$:)/gm,
end: /(\s*)/gm,
className: 'keyword'
}
]
},
{
begin: /^(\s*)(<style.*>)/gm,
end: /^(\s*)(<\/style>)/gm,
subLanguage: 'css',
excludeBegin: true,
excludeEnd: true
},
{
begin: /\{/gm,
end: /\}/gm,
subLanguage: 'javascript',
contains: [
{
begin: /[{]/,
end: /[}]/,
skip: true
},
{
begin: /([#:/@])(if|else|each|await|then|catch|debug|html)/gm,
className: 'keyword',
relevance: 10
}
]
}
]
}
}
@@ -0,0 +1,86 @@
//
// Copyright © 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import { type DiffHunk, type DiffLine, DiffLineType, EmptyLine } from '@hcengineering/diffview'
import { type HighlightOptions, highlightLines } from './highlight'
export interface RenderOptions {
syntaxHighlight: {
language: string
}
}
export interface DiffLineRenderResult {
before: DiffLine
after: DiffLine
}
export interface DiffHunkRenderResult {
hunk: DiffHunk
lines: DiffLineRenderResult[]
}
export function renderHunk (hunk: DiffHunk, options: RenderOptions): DiffHunkRenderResult {
const syntaxHighlight = options.syntaxHighlight
const highlightOptions: HighlightOptions = { language: syntaxHighlight.language }
const { before, after } = splitDiffLines(hunk.lines)
const beforeHighlighted = highlightDiffLines(before, highlightOptions)
const afterHighlighted = highlightDiffLines(after, highlightOptions)
const lines: DiffLineRenderResult[] = []
while (beforeHighlighted.length > 0 || afterHighlighted.length > 0) {
const beforeLine = beforeHighlighted.shift() ?? EmptyLine
const afterLine = afterHighlighted.shift() ?? EmptyLine
lines.push({ before: beforeLine, after: afterLine })
}
return { hunk, lines }
}
function splitDiffLines (lines: DiffLine[]): { before: DiffLine[], after: DiffLine[] } {
const before: DiffLine[] = []
const after: DiffLine[] = []
for (const line of lines) {
if (line.type === DiffLineType.CONTEXT) {
before.push(line)
after.push(line)
} else if (line.type === DiffLineType.DELETE) {
before.push(line)
after.push(EmptyLine)
} else if (line.type === DiffLineType.INSERT) {
before.push(EmptyLine)
after.push(line)
} else {
before.push(line)
after.push(line)
}
}
return { before, after }
}
function highlightDiffLines (lines: DiffLine[], options: HighlightOptions): DiffLine[] {
// Highlight entire diff hunk content, it is more accurate than highlighting line-by-line
const content = lines.filter((line) => line.type !== DiffLineType.EMPTY).map((line) => line.content)
const highlighted = highlightLines(content, options)
// Reconstruct DiffLine items with highlighted content
return lines.map((line) =>
line.type === DiffLineType.EMPTY ? { ...line } : { ...line, content: highlighted.shift() ?? '' }
)
}