mirror of
https://github.com/hcengineering/platform.git
synced 2025-06-04 23:04:47 +00:00
UBERF-8969 Rewrite extractReferences to use JSON only (#7506)
This commit is contained in:
parent
5bd3424c9b
commit
63464cbc54
@ -16,6 +16,7 @@
|
|||||||
export * from './extensions'
|
export * from './extensions'
|
||||||
export * from './markup/dsl'
|
export * from './markup/dsl'
|
||||||
export * from './markup/model'
|
export * from './markup/model'
|
||||||
|
export * from './markup/reference'
|
||||||
export * from './markup/traverse'
|
export * from './markup/traverse'
|
||||||
export * from './markup/utils'
|
export * from './markup/utils'
|
||||||
export * from './nodes'
|
export * from './nodes'
|
||||||
|
@ -17,8 +17,8 @@ describe('traverseNode', () => {
|
|||||||
traverseNode(node as MarkupNode, callback)
|
traverseNode(node as MarkupNode, callback)
|
||||||
|
|
||||||
expect(callback).toHaveBeenCalledTimes(2)
|
expect(callback).toHaveBeenCalledTimes(2)
|
||||||
expect(callback).toHaveBeenCalledWith(node)
|
expect(callback).toHaveBeenCalledWith(node, undefined)
|
||||||
expect(callback).toHaveBeenCalledWith(node.content[0])
|
expect(callback).toHaveBeenCalledWith(node.content[0], node)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should stop traversing if the callback returns false', () => {
|
it('should stop traversing if the callback returns false', () => {
|
||||||
@ -40,7 +40,7 @@ describe('traverseNode', () => {
|
|||||||
traverseNode(node, callback)
|
traverseNode(node, callback)
|
||||||
|
|
||||||
expect(callback).toHaveBeenCalledTimes(1)
|
expect(callback).toHaveBeenCalledTimes(1)
|
||||||
expect(callback).toHaveBeenCalledWith(node)
|
expect(callback).toHaveBeenCalledWith(node, undefined)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -84,6 +84,7 @@ export interface LinkMark extends MarkupMark {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export interface ReferenceMark extends MarkupMark {
|
export interface ReferenceMarkupNode extends MarkupNode {
|
||||||
|
type: MarkupNodeType.reference
|
||||||
attrs: { id: string, label: string, objectclass: string }
|
attrs: { id: string, label: string, objectclass: string }
|
||||||
}
|
}
|
||||||
|
49
packages/text/src/markup/reference.ts
Normal file
49
packages/text/src/markup/reference.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// 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 { Class, Doc, Ref } from '@hcengineering/core'
|
||||||
|
import { MarkupNode, MarkupNodeType, ReferenceMarkupNode } from '../markup/model'
|
||||||
|
import { traverseNode } from '../markup/traverse'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export interface Reference {
|
||||||
|
objectId: Ref<Doc>
|
||||||
|
objectClass: Ref<Class<Doc>>
|
||||||
|
parentNode: MarkupNode | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export function extractReferences (content: MarkupNode): Array<Reference> {
|
||||||
|
const result: Array<Reference> = []
|
||||||
|
|
||||||
|
traverseNode(content, (node, parent) => {
|
||||||
|
if (node.type === MarkupNodeType.reference) {
|
||||||
|
const reference = node as ReferenceMarkupNode
|
||||||
|
const objectId = reference.attrs.id as Ref<Doc>
|
||||||
|
const objectClass = reference.attrs.objectclass as Ref<Class<Doc>>
|
||||||
|
const e = result.find((e) => e.objectId === objectId && e.objectClass === objectClass)
|
||||||
|
if (e === undefined) {
|
||||||
|
result.push({ objectId, objectClass, parentNode: parent ?? node })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
@ -15,11 +15,22 @@
|
|||||||
|
|
||||||
import { MarkupMark, MarkupNode } from './model'
|
import { MarkupMark, MarkupNode } from './model'
|
||||||
|
|
||||||
export function traverseNode (node: MarkupNode, f: (el: MarkupNode) => boolean | undefined): void {
|
export function traverseNode (
|
||||||
const result = f(node)
|
node: MarkupNode,
|
||||||
|
fn: (el: MarkupNode, parent: MarkupNode | undefined) => boolean | undefined
|
||||||
|
): void {
|
||||||
|
_traverseNode(node, undefined, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
function _traverseNode (
|
||||||
|
node: MarkupNode,
|
||||||
|
parent: MarkupNode | undefined,
|
||||||
|
fn: (el: MarkupNode, parent: MarkupNode | undefined) => boolean | undefined
|
||||||
|
): void {
|
||||||
|
const result = fn(node, parent)
|
||||||
if (result !== false) {
|
if (result !== false) {
|
||||||
node.content?.forEach((p) => {
|
node.content?.forEach((p) => {
|
||||||
traverseNode(p, f)
|
_traverseNode(p, node, fn)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,14 +14,6 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import { Node } from '@tiptap/core'
|
import { Node } from '@tiptap/core'
|
||||||
import { Node as ProseMirrorNode } from '@tiptap/pm/model'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export interface Comment {
|
|
||||||
parentNode: ProseMirrorNode | null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
|
@ -13,42 +13,9 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
import { Class, Doc, Ref } from '@hcengineering/core'
|
|
||||||
import { Node, mergeAttributes } from '@tiptap/core'
|
import { Node, mergeAttributes } from '@tiptap/core'
|
||||||
import { Node as ProseMirrorNode } from '@tiptap/pm/model'
|
|
||||||
import { getDataAttribute } from './utils'
|
import { getDataAttribute } from './utils'
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export interface Reference {
|
|
||||||
objectId: Ref<Doc>
|
|
||||||
objectClass: Ref<Class<Doc>>
|
|
||||||
parentNode: ProseMirrorNode | null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export function extractReferences (content: ProseMirrorNode): Array<Reference> {
|
|
||||||
const result: Array<Reference> = []
|
|
||||||
|
|
||||||
content.descendants((node, _pos, parent): boolean => {
|
|
||||||
if (node.type.name === ReferenceNode.name) {
|
|
||||||
const objectId = node.attrs.id as Ref<Doc>
|
|
||||||
const objectClass = node.attrs.objectclass as Ref<Class<Doc>>
|
|
||||||
const e = result.find((e) => e.objectId === objectId && e.objectClass === objectClass)
|
|
||||||
if (e === undefined) {
|
|
||||||
result.push({ objectId, objectClass, parentNode: parent })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ReferenceOptions {
|
export interface ReferenceOptions {
|
||||||
renderLabel: (props: { options: ReferenceOptions, node: any }) => string
|
renderLabel: (props: { options: ReferenceOptions, node: any }) => string
|
||||||
suggestion: { char: string }
|
suggestion: { char: string }
|
||||||
|
@ -73,7 +73,7 @@ describe('extractBacklinks', () => {
|
|||||||
srcDocId: 'srcDocId',
|
srcDocId: 'srcDocId',
|
||||||
srcDocClass: 'srcDocClass',
|
srcDocClass: 'srcDocClass',
|
||||||
message:
|
message:
|
||||||
'{"type":"paragraph","content":[{"type":"reference","attrs":{"id":"id","objectclass":"contact:class:Person","label":"Appleseed John","class":null}},{"type":"text","text":" hello"}]}',
|
'{"type":"paragraph","content":[{"type":"reference","attrs":{"id":"id","objectclass":"contact:class:Person","label":"Appleseed John"}},{"type":"text","text":" hello"}]}',
|
||||||
attachedDocId: 'attachedDocId',
|
attachedDocId: 'attachedDocId',
|
||||||
attachedDocClass: 'attachedDocClass'
|
attachedDocClass: 'attachedDocClass'
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import core, {
|
|||||||
Doc,
|
Doc,
|
||||||
generateId,
|
generateId,
|
||||||
Hierarchy,
|
Hierarchy,
|
||||||
|
Markup,
|
||||||
Ref,
|
Ref,
|
||||||
Space,
|
Space,
|
||||||
Tx,
|
Tx,
|
||||||
@ -50,12 +51,12 @@ import {
|
|||||||
toReceiverInfo,
|
toReceiverInfo,
|
||||||
type NotificationProviderControl
|
type NotificationProviderControl
|
||||||
} from '@hcengineering/server-notification-resources'
|
} from '@hcengineering/server-notification-resources'
|
||||||
import { areEqualJson, extractReferences, markupToPmNode, pmNodeToMarkup } from '@hcengineering/text'
|
import { areEqualJson, extractReferences, jsonToMarkup, markupToJSON } from '@hcengineering/text'
|
||||||
|
|
||||||
export function isDocMentioned (doc: Ref<Doc>, content: string): boolean {
|
export function isDocMentioned (doc: Ref<Doc>, content: string): boolean {
|
||||||
const references = []
|
const references = []
|
||||||
|
|
||||||
const node = markupToPmNode(content)
|
const node = markupToJSON(content)
|
||||||
references.push(...extractReferences(node))
|
references.push(...extractReferences(node))
|
||||||
|
|
||||||
for (const ref of references) {
|
for (const ref of references) {
|
||||||
@ -491,13 +492,13 @@ export function getReferencesData (
|
|||||||
srcDocClass: Ref<Class<Doc>>,
|
srcDocClass: Ref<Class<Doc>>,
|
||||||
attachedDocId: Ref<Doc> | undefined,
|
attachedDocId: Ref<Doc> | undefined,
|
||||||
attachedDocClass: Ref<Class<Doc>> | undefined,
|
attachedDocClass: Ref<Class<Doc>> | undefined,
|
||||||
content: string
|
content: Markup
|
||||||
): Array<Data<ActivityReference>> {
|
): Array<Data<ActivityReference>> {
|
||||||
const result: Array<Data<ActivityReference>> = []
|
const result: Array<Data<ActivityReference>> = []
|
||||||
const references = []
|
const references = []
|
||||||
|
|
||||||
const doc = markupToPmNode(content)
|
const node = markupToJSON(content)
|
||||||
references.push(...extractReferences(doc))
|
references.push(...extractReferences(node))
|
||||||
|
|
||||||
for (const ref of references) {
|
for (const ref of references) {
|
||||||
if (ref.objectId !== attachedDocId && ref.objectId !== srcDocId) {
|
if (ref.objectId !== attachedDocId && ref.objectId !== srcDocId) {
|
||||||
@ -507,7 +508,7 @@ export function getReferencesData (
|
|||||||
collection: 'references',
|
collection: 'references',
|
||||||
srcDocId,
|
srcDocId,
|
||||||
srcDocClass,
|
srcDocClass,
|
||||||
message: ref.parentNode !== null ? pmNodeToMarkup(ref.parentNode) : '',
|
message: ref.parentNode !== null ? jsonToMarkup(ref.parentNode) : '',
|
||||||
attachedDocId,
|
attachedDocId,
|
||||||
attachedDocClass
|
attachedDocClass
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user