chore(commons): prettier

enforce trailing commas as this is the norm in the frontend and makes diffs better readable

Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
Philip Molares 2025-03-21 21:13:30 +01:00
parent 59744b65ea
commit aa87ff35b3
32 changed files with 171 additions and 171 deletions

View file

@ -4,7 +4,7 @@
"jsxSingleQuote": true, "jsxSingleQuote": true,
"semi": false, "semi": false,
"tabWidth": 2, "tabWidth": 2,
"trailingComma": "none", "trailingComma": "all",
"bracketSpacing": true, "bracketSpacing": true,
"bracketSameLine": true, "bracketSameLine": true,
"arrowParens": "always" "arrowParens": "always"

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -34,7 +34,7 @@ describe('frontmatter extraction', () => {
'this is not frontmatter', 'this is not frontmatter',
'because', 'because',
'there is no', 'there is no',
'end marker' 'end marker',
] ]
const extraction = extractFrontmatter(testNote) const extraction = extractFrontmatter(testNote)
expect(extraction).toBeUndefined() expect(extraction).toBeUndefined()

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -20,7 +20,7 @@ const FRONTMATTER_INCOMPLETE_END_REGEX = /^-{1,2}$/
* given multiline string for retrieving the non-frontmatter content. * given multiline string for retrieving the non-frontmatter content.
*/ */
export const extractFrontmatter = ( export const extractFrontmatter = (
lines: string[] lines: string[],
): FrontmatterExtractionResult | undefined => { ): FrontmatterExtractionResult | undefined => {
if (lines.length < 2 || !FRONTMATTER_BEGIN_REGEX.test(lines[0])) { if (lines.length < 2 || !FRONTMATTER_BEGIN_REGEX.test(lines[0])) {
return undefined return undefined
@ -30,7 +30,7 @@ export const extractFrontmatter = (
return { return {
rawText: '', rawText: '',
lineOffset: i + 1, lineOffset: i + 1,
incomplete: true incomplete: true,
} }
} }
if ( if (
@ -40,7 +40,7 @@ export const extractFrontmatter = (
return { return {
rawText: lines.slice(1, i).join('\n'), rawText: lines.slice(1, i).join('\n'),
lineOffset: i + 1, lineOffset: i + 1,
incomplete: false incomplete: false,
} }
} }
} }

View file

@ -1,9 +1,9 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
export enum DisconnectReason { export enum DisconnectReason {
USER_NOT_PERMITTED = 4000 USER_NOT_PERMITTED = 4000,
} }

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -7,7 +7,7 @@ import {
ConnectionStateEvent, ConnectionStateEvent,
Message, Message,
MessagePayloads, MessagePayloads,
MessageType MessageType,
} from './message.js' } from './message.js'
import { TransportAdapter } from './transport-adapter.js' import { TransportAdapter } from './transport-adapter.js'
import { EventEmitter2, Listener } from 'eventemitter2' import { EventEmitter2, Listener } from 'eventemitter2'
@ -26,7 +26,7 @@ type MessageEventPayloadMap = {
export enum ConnectionState { export enum ConnectionState {
DISCONNECTED = 'DISCONNECTED', DISCONNECTED = 'DISCONNECTED',
CONNECTING = 'CONNECTING', CONNECTING = 'CONNECTING',
CONNECTED = 'CONNECTED' CONNECTED = 'CONNECTED',
} }
/** /**
@ -53,7 +53,7 @@ export class MessageTransporter extends EventEmitter2<MessageEventPayloadMap> {
if (this.transportAdapter === undefined) { if (this.transportAdapter === undefined) {
console.debug( console.debug(
"Can't send message without transport adapter. Message that couldn't be sent was", "Can't send message without transport adapter. Message that couldn't be sent was",
content content,
) )
return return
} }
@ -62,7 +62,7 @@ export class MessageTransporter extends EventEmitter2<MessageEventPayloadMap> {
this.onDisconnecting() this.onDisconnecting()
console.debug( console.debug(
"Can't send message over closed connection. Triggering onDisconencted event. Message that couldn't be sent was", "Can't send message over closed connection. Triggering onDisconencted event. Message that couldn't be sent was",
content content,
) )
return return
} }
@ -105,7 +105,7 @@ export class MessageTransporter extends EventEmitter2<MessageEventPayloadMap> {
this.onConnected() this.onConnected()
} else { } else {
this.destroyOnConnectedEventHandler = websocket.bindOnConnectedEvent( this.destroyOnConnectedEventHandler = websocket.bindOnConnectedEvent(
this.onConnected.bind(this) this.onConnected.bind(this),
) )
} }
} }
@ -167,13 +167,13 @@ export class MessageTransporter extends EventEmitter2<MessageEventPayloadMap> {
private bindWebsocketEvents(transportAdapter: TransportAdapter) { private bindWebsocketEvents(transportAdapter: TransportAdapter) {
this.destroyOnErrorEventHandler = transportAdapter.bindOnErrorEvent( this.destroyOnErrorEventHandler = transportAdapter.bindOnErrorEvent(
this.onDisconnecting.bind(this) this.onDisconnecting.bind(this),
) )
this.destroyOnCloseEventHandler = transportAdapter.bindOnCloseEvent( this.destroyOnCloseEventHandler = transportAdapter.bindOnCloseEvent(
this.onDisconnecting.bind(this) this.onDisconnecting.bind(this),
) )
this.destroyOnMessageEventHandler = transportAdapter.bindOnMessageEvent( this.destroyOnMessageEventHandler = transportAdapter.bindOnMessageEvent(
this.receiveMessage.bind(this) this.receiveMessage.bind(this),
) )
} }
@ -221,7 +221,7 @@ export class MessageTransporter extends EventEmitter2<MessageEventPayloadMap> {
callback() callback()
} }
return this.on('ready', callback, { return this.on('ready', callback, {
objectify: true objectify: true,
}) as Listener }) as Listener
} }
@ -237,7 +237,7 @@ export class MessageTransporter extends EventEmitter2<MessageEventPayloadMap> {
callback() callback()
} }
return this.on('connected', callback, { return this.on('connected', callback, {
objectify: true objectify: true,
}) as Listener }) as Listener
} }
@ -253,11 +253,11 @@ export class MessageTransporter extends EventEmitter2<MessageEventPayloadMap> {
protected startSendingOfReadyRequests(): void { protected startSendingOfReadyRequests(): void {
this.readyInterval = setInterval(() => { this.readyInterval = setInterval(() => {
this.sendMessage({ this.sendMessage({
type: MessageType.READY_REQUEST type: MessageType.READY_REQUEST,
}) })
}, 400) }, 400)
this.sendMessage({ this.sendMessage({
type: MessageType.READY_REQUEST type: MessageType.READY_REQUEST,
}) })
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -19,13 +19,13 @@ export enum MessageType {
REALTIME_USER_SET_ACTIVITY = 'REALTIME_USER_SET_ACTIVITY', REALTIME_USER_SET_ACTIVITY = 'REALTIME_USER_SET_ACTIVITY',
READY_REQUEST = 'READY_REQUEST', READY_REQUEST = 'READY_REQUEST',
READY_ANSWER = 'READY_ANSWER' READY_ANSWER = 'READY_ANSWER',
} }
export enum ConnectionStateEvent { export enum ConnectionStateEvent {
READY = 'ready', READY = 'ready',
CONNECTED = 'connected', CONNECTED = 'connected',
DISCONNECTED = 'disconnected' DISCONNECTED = 'disconnected',
} }
export interface MessagePayloads { export interface MessagePayloads {

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -46,7 +46,7 @@ export class MockedBackendTransportAdapter implements TransportAdapter {
} }
bindOnMessageEvent( bindOnMessageEvent(
handler: (value: Message<MessageType>) => void handler: (value: Message<MessageType>) => void,
): () => void { ): () => void {
this.messageHandler = handler this.messageHandler = handler
return () => { return () => {
@ -74,17 +74,17 @@ export class MockedBackendTransportAdapter implements TransportAdapter {
() => () =>
this.messageHandler?.({ this.messageHandler?.({
type: MessageType.NOTE_CONTENT_UPDATE, type: MessageType.NOTE_CONTENT_UPDATE,
payload: this.doc.encodeStateAsUpdate(value.payload) payload: this.doc.encodeStateAsUpdate(value.payload),
}), }),
0 0,
) )
} else if (value.type === MessageType.READY_REQUEST) { } else if (value.type === MessageType.READY_REQUEST) {
setTimeout( setTimeout(
() => () =>
this.messageHandler?.({ this.messageHandler?.({
type: MessageType.READY_ANSWER type: MessageType.READY_ANSWER,
}), }),
0 0,
) )
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -7,7 +7,7 @@ import {
NoteFrontmatter, NoteFrontmatter,
NoteTextDirection, NoteTextDirection,
NoteType, NoteType,
OpenGraph OpenGraph,
} from '../note-frontmatter/frontmatter.js' } from '../note-frontmatter/frontmatter.js'
import { SlideOptions } from '../note-frontmatter/slide-show-options.js' import { SlideOptions } from '../note-frontmatter/slide-show-options.js'
import { convertRawFrontmatterToNoteFrontmatter } from './convert-raw-frontmatter-to-note-frontmatter.js' import { convertRawFrontmatterToNoteFrontmatter } from './convert-raw-frontmatter-to-note-frontmatter.js'
@ -31,8 +31,8 @@ describe('convertRawFrontmatterToNoteFrontmatter', () => {
breaks: breaks, breaks: breaks,
opengraph: opengraph, opengraph: opengraph,
slideOptions: slideOptions, slideOptions: slideOptions,
tags: 'tags' tags: 'tags',
}) }),
).toStrictEqual({ ).toStrictEqual({
title: 'title', title: 'title',
description: 'description', description: 'description',
@ -44,8 +44,8 @@ describe('convertRawFrontmatterToNoteFrontmatter', () => {
opengraph: opengraph, opengraph: opengraph,
slideOptions: slideOptions, slideOptions: slideOptions,
license: 'license', license: 'license',
tags: ['tags'] tags: ['tags'],
} as NoteFrontmatter) } as NoteFrontmatter)
} },
) )
}) })

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -12,7 +12,7 @@ import { RawNoteFrontmatter } from './types.js'
* @param rawData A {@link RawNoteFrontmatter} object containing the properties of the parsed yaml frontmatter. * @param rawData A {@link RawNoteFrontmatter} object containing the properties of the parsed yaml frontmatter.
*/ */
export const convertRawFrontmatterToNoteFrontmatter = ( export const convertRawFrontmatterToNoteFrontmatter = (
rawData: RawNoteFrontmatter rawData: RawNoteFrontmatter,
): NoteFrontmatter => { ): NoteFrontmatter => {
return { return {
title: rawData.title, title: rawData.title,
@ -25,6 +25,6 @@ export const convertRawFrontmatterToNoteFrontmatter = (
opengraph: rawData.opengraph, opengraph: rawData.opengraph,
slideOptions: rawData.slideOptions, slideOptions: rawData.slideOptions,
license: rawData.license, license: rawData.license,
tags: parseTags(rawData.tags) tags: parseTags(rawData.tags),
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -32,7 +32,7 @@ describe('yaml frontmatter', () => {
it('should parse the tag inline-list syntax', () => { it('should parse the tag inline-list syntax', () => {
const noteFrontmatter = parseRawFrontmatterFromYaml( const noteFrontmatter = parseRawFrontmatterFromYaml(
"tags: ['test123', 'abc']" "tags: ['test123', 'abc']",
) )
expect(noteFrontmatter.value?.tags).toEqual(['test123', 'abc']) expect(noteFrontmatter.value?.tags).toEqual(['test123', 'abc'])
}) })
@ -57,7 +57,7 @@ describe('yaml frontmatter', () => {
`) `)
expect(noteFrontmatter.value?.opengraph.title).toEqual('Testtitle') expect(noteFrontmatter.value?.opengraph.title).toEqual('Testtitle')
expect(noteFrontmatter.value?.opengraph.image).toEqual( expect(noteFrontmatter.value?.opengraph.image).toEqual(
'https://dummyimage.com/48.png' 'https://dummyimage.com/48.png',
) )
expect(noteFrontmatter.value?.opengraph['image:type']).toEqual('image/png') expect(noteFrontmatter.value?.opengraph['image:type']).toEqual('image/png')
}) })

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -7,7 +7,7 @@ import { defaultNoteFrontmatter } from '../note-frontmatter/index.js'
import { import {
NoteTextDirection, NoteTextDirection,
NoteType, NoteType,
OpenGraph OpenGraph,
} from '../note-frontmatter/index.js' } from '../note-frontmatter/index.js'
import { SlideOptions } from '../note-frontmatter/index.js' import { SlideOptions } from '../note-frontmatter/index.js'
import { ISO6391 } from '../note-frontmatter/iso6391.js' import { ISO6391 } from '../note-frontmatter/iso6391.js'
@ -24,7 +24,7 @@ const schema = Joi.object<RawNoteFrontmatter>({
tags: Joi.alternatives( tags: Joi.alternatives(
Joi.array().items(Joi.string()), Joi.array().items(Joi.string()),
Joi.string(), Joi.string(),
Joi.number().cast('string') Joi.number().cast('string'),
) )
.optional() .optional()
.default(defaultNoteFrontmatter.tags), .default(defaultNoteFrontmatter.tags),
@ -51,17 +51,17 @@ const schema = Joi.object<RawNoteFrontmatter>({
transition: Joi.string().optional(), transition: Joi.string().optional(),
backgroundTransition: Joi.string().optional(), backgroundTransition: Joi.string().optional(),
autoSlideStoppable: Joi.boolean().optional(), autoSlideStoppable: Joi.boolean().optional(),
slideNumber: Joi.boolean().optional() slideNumber: Joi.boolean().optional(),
}) })
.optional() .optional()
.default(defaultNoteFrontmatter.slideOptions), .default(defaultNoteFrontmatter.slideOptions),
opengraph: Joi.object<OpenGraph>({ opengraph: Joi.object<OpenGraph>({
title: Joi.string().optional(), title: Joi.string().optional(),
image: Joi.string().uri().optional() image: Joi.string().uri().optional(),
}) })
.unknown(true) .unknown(true)
.optional() .optional()
.default(defaultNoteFrontmatter.opengraph) .default(defaultNoteFrontmatter.opengraph),
}) })
.default(defaultNoteFrontmatter) .default(defaultNoteFrontmatter)
.unknown(true) .unknown(true)

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -14,7 +14,7 @@ describe('parse tags', () => {
'c', 'c',
'd', 'd',
'e', 'e',
'f' 'f',
]) ])
}) })
@ -25,7 +25,7 @@ describe('parse tags', () => {
'c', 'c',
'd', 'd',
'e', 'e',
'f' 'f',
]) ])
}) })
}) })

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -7,7 +7,7 @@ import {
Iso6391Language, Iso6391Language,
NoteTextDirection, NoteTextDirection,
NoteType, NoteType,
OpenGraph OpenGraph,
} from '../note-frontmatter/index.js' } from '../note-frontmatter/index.js'
import { SlideOptions } from '../note-frontmatter/index.js' import { SlideOptions } from '../note-frontmatter/index.js'

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -11,7 +11,7 @@ export const defaultSlideOptions: SlideOptions = {
autoSlide: 0, autoSlide: 0,
autoSlideStoppable: true, autoSlideStoppable: true,
backgroundTransition: 'fade', backgroundTransition: 'fade',
slideNumber: false slideNumber: false,
} }
export const defaultNoteFrontmatter: NoteFrontmatter = { export const defaultNoteFrontmatter: NoteFrontmatter = {
@ -25,5 +25,5 @@ export const defaultNoteFrontmatter: NoteFrontmatter = {
license: '', license: '',
type: NoteType.DOCUMENT, type: NoteType.DOCUMENT,
opengraph: {}, opengraph: {},
slideOptions: defaultSlideOptions slideOptions: defaultSlideOptions,
} }

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -12,12 +12,12 @@ export type OpenGraph = Record<string, string>
export enum NoteTextDirection { export enum NoteTextDirection {
LTR = 'ltr', LTR = 'ltr',
RTL = 'rtl' RTL = 'rtl',
} }
export enum NoteType { export enum NoteType {
DOCUMENT = 'document', DOCUMENT = 'document',
SLIDE = 'slide' SLIDE = 'slide',
} }
export interface NoteFrontmatter { export interface NoteFrontmatter {
title: string title: string

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -187,5 +187,5 @@ export const ISO6391 = [
'yo', 'yo',
'za', 'za',
'zh', 'zh',
'zu' 'zu',
] as const ] as const

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -15,12 +15,12 @@ describe('validate url', () => {
describe('protocols', () => { describe('protocols', () => {
it('works with http', () => { it('works with http', () => {
expect(parseUrl('http://example.org').get().toString()).toEqual( expect(parseUrl('http://example.org').get().toString()).toEqual(
'http://example.org/' 'http://example.org/',
) )
}) })
it('works with https', () => { it('works with https', () => {
expect(parseUrl('https://example.org').get().toString()).toEqual( expect(parseUrl('https://example.org').get().toString()).toEqual(
'https://example.org/' 'https://example.org/',
) )
}) })
it("doesn't work without protocol", () => { it("doesn't work without protocol", () => {
@ -28,7 +28,7 @@ describe('validate url', () => {
}) })
it("doesn't work any other protocol", () => { it("doesn't work any other protocol", () => {
expect(() => parseUrl('git://example.org').get()).toThrowError( expect(() => parseUrl('git://example.org').get()).toThrowError(
WrongProtocolError WrongProtocolError,
) )
}) })
}) })
@ -36,22 +36,22 @@ describe('validate url', () => {
describe('trailing slash', () => { describe('trailing slash', () => {
it('accepts urls with just domain with trailing slash', () => { it('accepts urls with just domain with trailing slash', () => {
expect(parseUrl('http://example.org/').get().toString()).toEqual( expect(parseUrl('http://example.org/').get().toString()).toEqual(
'http://example.org/' 'http://example.org/',
) )
}) })
it('accepts urls with just domain without trailing slash', () => { it('accepts urls with just domain without trailing slash', () => {
expect(parseUrl('http://example.org').get().toString()).toEqual( expect(parseUrl('http://example.org').get().toString()).toEqual(
'http://example.org/' 'http://example.org/',
) )
}) })
it('declines urls with with subpath and trailing slash', () => { it('declines urls with with subpath and trailing slash', () => {
expect(() => expect(() =>
parseUrl('http://example.org/asd/').get().toString() parseUrl('http://example.org/asd/').get().toString(),
).toThrow(NoSubdirectoryAllowedError) ).toThrow(NoSubdirectoryAllowedError)
}) })
it('declines urls with with subpath and without trailing slash', () => { it('declines urls with with subpath and without trailing slash', () => {
expect(() => parseUrl('http://example.org/asd').get().toString()).toThrow( expect(() => parseUrl('http://example.org/asd').get().toString()).toThrow(
NoSubdirectoryAllowedError NoSubdirectoryAllowedError,
) )
}) })
}) })

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -18,11 +18,11 @@ export function parseUrl(url: string | undefined): Optional<URL> {
return createOptionalUrl(url) return createOptionalUrl(url)
.guard( .guard(
(value) => value.protocol === 'https:' || value.protocol === 'http:', (value) => value.protocol === 'https:' || value.protocol === 'http:',
() => new WrongProtocolError() () => new WrongProtocolError(),
) )
.guard( .guard(
(value) => value.pathname === '/', (value) => value.pathname === '/',
() => new NoSubdirectoryAllowedError() () => new NoSubdirectoryAllowedError(),
) )
} }

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -13,19 +13,19 @@ describe('Permissions', () => {
sharedToUsers: [ sharedToUsers: [
{ {
username: 'logged_in', username: 'logged_in',
canEdit: true canEdit: true,
} },
], ],
sharedToGroups: [ sharedToGroups: [
{ {
groupName: SpecialGroup.EVERYONE, groupName: SpecialGroup.EVERYONE,
canEdit: true canEdit: true,
}, },
{ {
groupName: SpecialGroup.LOGGED_IN, groupName: SpecialGroup.LOGGED_IN,
canEdit: true canEdit: true,
} },
] ],
} }
describe('userIsOwner', () => { describe('userIsOwner', () => {
it('returns true, if user is owner', () => { it('returns true, if user is owner', () => {
@ -45,25 +45,25 @@ describe('Permissions', () => {
}) })
it('returns true, if user is logged in and this is user specifically may edit', () => { it('returns true, if user is logged in and this is user specifically may edit', () => {
expect( expect(
userCanEdit({ ...testPermissions, sharedToGroups: [] }, 'logged_in') userCanEdit({ ...testPermissions, sharedToGroups: [] }, 'logged_in'),
).toBeTruthy() ).toBeTruthy()
}) })
it('returns true, if user is logged in and loggedIn users may edit', () => { it('returns true, if user is logged in and loggedIn users may edit', () => {
expect( expect(
userCanEdit({ ...testPermissions, sharedToUsers: [] }, 'logged_in') userCanEdit({ ...testPermissions, sharedToUsers: [] }, 'logged_in'),
).toBeTruthy() ).toBeTruthy()
}) })
it('returns true, if user is guest and guests are allowed to edit', () => { it('returns true, if user is guest and guests are allowed to edit', () => {
expect( expect(
userCanEdit({ ...testPermissions, sharedToUsers: [] }, undefined) userCanEdit({ ...testPermissions, sharedToUsers: [] }, undefined),
).toBeTruthy() ).toBeTruthy()
}) })
it('returns false, if user is logged in and loggedIn users may not edit', () => { it('returns false, if user is logged in and loggedIn users may not edit', () => {
expect( expect(
userCanEdit( userCanEdit(
{ ...testPermissions, sharedToUsers: [], sharedToGroups: [] }, { ...testPermissions, sharedToUsers: [], sharedToGroups: [] },
'logged_in' 'logged_in',
) ),
).toBeFalsy() ).toBeFalsy()
}) })
it('returns false, if user is guest and guests are not allowed to edit', () => { it('returns false, if user is guest and guests are not allowed to edit', () => {
@ -75,12 +75,12 @@ describe('Permissions', () => {
sharedToGroups: [ sharedToGroups: [
{ {
groupName: SpecialGroup.LOGGED_IN, groupName: SpecialGroup.LOGGED_IN,
canEdit: true canEdit: true,
} },
] ],
}, },
undefined undefined,
) ),
).toBeFalsy() ).toBeFalsy()
}) })
}) })

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -14,7 +14,7 @@ import { NotePermissions, SpecialGroup } from './permissions.types.js'
*/ */
export const userIsOwner = ( export const userIsOwner = (
permissions: NotePermissions, permissions: NotePermissions,
user?: string user?: string,
): boolean => { ): boolean => {
return !!user && permissions.owner === user return !!user && permissions.owner === user
} }
@ -28,21 +28,21 @@ export const userIsOwner = (
*/ */
export const userCanEdit = ( export const userCanEdit = (
permissions: NotePermissions, permissions: NotePermissions,
user?: string user?: string,
): boolean => { ): boolean => {
const isOwner = userIsOwner(permissions, user) const isOwner = userIsOwner(permissions, user)
const mayWriteViaUserPermission = permissions.sharedToUsers.some( const mayWriteViaUserPermission = permissions.sharedToUsers.some(
(value) => value.canEdit && value.username === user (value) => value.canEdit && value.username === user,
) )
const mayWriteViaGroupPermission = const mayWriteViaGroupPermission =
!!user && !!user &&
permissions.sharedToGroups.some( permissions.sharedToGroups.some(
(value) => (value) =>
value.groupName === (SpecialGroup.LOGGED_IN as string) && value.canEdit value.groupName === (SpecialGroup.LOGGED_IN as string) && value.canEdit,
) )
const everyoneMayWriteViaGroupPermission = permissions.sharedToGroups.some( const everyoneMayWriteViaGroupPermission = permissions.sharedToGroups.some(
(value) => (value) =>
value.groupName === (SpecialGroup.EVERYONE as string) && value.canEdit value.groupName === (SpecialGroup.EVERYONE as string) && value.canEdit,
) )
return ( return (
isOwner || isOwner ||

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -22,10 +22,10 @@ export interface NoteGroupPermissionEntry {
export enum AccessLevel { export enum AccessLevel {
NONE, NONE,
READ_ONLY, READ_ONLY,
WRITEABLE WRITEABLE,
} }
export enum SpecialGroup { export enum SpecialGroup {
EVERYONE = '_EVERYONE', EVERYONE = '_EVERYONE',
LOGGED_IN = '_LOGGED_IN' LOGGED_IN = '_LOGGED_IN',
} }

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -19,8 +19,8 @@ describe('extract first heading', () => {
it("doesn't extract heading-anchor", () => { it("doesn't extract heading-anchor", () => {
const headline = new Element(`h${headlineIndex}`, {}, [ const headline = new Element(`h${headlineIndex}`, {}, [
new Element('a', { class: 'class1 heading-anchor class2' }, [ new Element('a', { class: 'class1 heading-anchor class2' }, [
new Text('invalid link content') new Text('invalid link content'),
]) ]),
]) ])
const document = new Document([headline]) const document = new Document([headline])
expect(extractFirstHeading(document)).toBe('') expect(extractFirstHeading(document)).toBe('')
@ -31,8 +31,8 @@ describe('extract first heading', () => {
new Element('a', {}, [ new Element('a', {}, [
new Text('Valid'), new Text('Valid'),
new Element('div', {}, [new Text('Text')]), new Element('div', {}, [new Text('Text')]),
new Text(`${headlineIndex}`) new Text(`${headlineIndex}`),
]) ]),
]) ])
const document = new Document([headline]) const document = new Document([headline])
expect(extractFirstHeading(document)).toBe(`ValidText${headlineIndex}`) expect(extractFirstHeading(document)).toBe(`ValidText${headlineIndex}`)
@ -40,7 +40,7 @@ describe('extract first heading', () => {
it('extracts image alt texts', () => { it('extracts image alt texts', () => {
const headline = new Element(`h${headlineIndex}`, {}, [ const headline = new Element(`h${headlineIndex}`, {}, [
new Element('img', { alt: 'Image Alt' }) new Element('img', { alt: 'Image Alt' }),
]) ])
const document = new Document([headline]) const document = new Document([headline])
expect(extractFirstHeading(document)).toBe('Image Alt') expect(extractFirstHeading(document)).toBe('Image Alt')
@ -48,10 +48,10 @@ describe('extract first heading', () => {
it('extracts only the first found headline', () => { it('extracts only the first found headline', () => {
const headline1 = new Element(`h${headlineIndex}`, {}, [ const headline1 = new Element(`h${headlineIndex}`, {}, [
new Text(`headline${headlineIndex}`) new Text(`headline${headlineIndex}`),
]) ])
const headline2 = new Element(`h${headlineIndex}`, {}, [ const headline2 = new Element(`h${headlineIndex}`, {}, [
new Text('headline1') new Text('headline1'),
]) ])
const document = new Document([headline1, headline2]) const document = new Document([headline1, headline2])
expect(extractFirstHeading(document)).toBe(`headline${headlineIndex}`) expect(extractFirstHeading(document)).toBe(`headline${headlineIndex}`)

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -14,7 +14,7 @@ const headlineTagRegex = /^h[1-6]$/gi
* @return the plain text representation of the first headline. {@code undefined} if no headline has been found. * @return the plain text representation of the first headline. {@code undefined} if no headline has been found.
*/ */
export function extractFirstHeading( export function extractFirstHeading(
nodes: NodeWithChildren nodes: NodeWithChildren,
): string | undefined { ): string | undefined {
const foundHeadlineNode = checkNodesForHeadline(nodes.children) const foundHeadlineNode = checkNodesForHeadline(nodes.children)
if (!foundHeadlineNode) { if (!foundHeadlineNode) {

View file

@ -1,12 +1,12 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import { import {
NoteFrontmatter, NoteFrontmatter,
NoteTextDirection, NoteTextDirection,
NoteType NoteType,
} from '../note-frontmatter/frontmatter.js' } from '../note-frontmatter/frontmatter.js'
import { generateNoteTitle } from './generate-note-title.js' import { generateNoteTitle } from './generate-note-title.js'
import { describe, expect, it } from '@jest/globals' import { describe, expect, it } from '@jest/globals'
@ -27,8 +27,8 @@ const testFrontmatter: NoteFrontmatter = {
autoSlide: 0, autoSlide: 0,
autoSlideStoppable: true, autoSlideStoppable: true,
backgroundTransition: 'fade', backgroundTransition: 'fade',
slideNumber: false slideNumber: false,
} },
} }
describe('generate note title', () => { describe('generate note title', () => {
@ -37,9 +37,9 @@ describe('generate note title', () => {
{ {
...testFrontmatter, ...testFrontmatter,
title: 'frontmatter', title: 'frontmatter',
opengraph: { title: 'opengraph' } opengraph: { title: 'opengraph' },
}, },
() => 'first-heading' () => 'first-heading',
) )
expect(actual).toEqual('frontmatter') expect(actual).toEqual('frontmatter')
}) })
@ -47,7 +47,7 @@ describe('generate note title', () => {
it('will choose the opengraph title second', () => { it('will choose the opengraph title second', () => {
const actual = generateNoteTitle( const actual = generateNoteTitle(
{ ...testFrontmatter, opengraph: { title: 'opengraph' } }, { ...testFrontmatter, opengraph: { title: 'opengraph' } },
() => 'first-heading' () => 'first-heading',
) )
expect(actual).toEqual('opengraph') expect(actual).toEqual('opengraph')
}) })
@ -55,7 +55,7 @@ describe('generate note title', () => {
it('will choose the first heading third', () => { it('will choose the first heading third', () => {
const actual = generateNoteTitle( const actual = generateNoteTitle(
{ ...testFrontmatter }, { ...testFrontmatter },
() => 'first-heading' () => 'first-heading',
) )
expect(actual).toEqual('first-heading') expect(actual).toEqual('first-heading')
}) })

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -14,7 +14,7 @@ import type { NoteFrontmatter } from '../note-frontmatter/frontmatter.js'
*/ */
export const generateNoteTitle = ( export const generateNoteTitle = (
frontmatter: NoteFrontmatter | undefined, frontmatter: NoteFrontmatter | undefined,
firstHeadingProvider: () => string | undefined firstHeadingProvider: () => string | undefined,
): string => { ): string => {
if (frontmatter?.title) { if (frontmatter?.title) {
return frontmatter.title.trim() return frontmatter.title.trim()

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -42,7 +42,7 @@ export class InMemoryConnectionTransportAdapter implements TransportAdapter {
} }
bindOnMessageEvent( bindOnMessageEvent(
handler: (value: Message<MessageType>) => void handler: (value: Message<MessageType>) => void,
): () => void { ): () => void {
this.onMessageHandler = handler this.onMessageHandler = handler
return () => (this.onMessageHandler = undefined) return () => (this.onMessageHandler = undefined)

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -25,12 +25,12 @@ describe('realtime doc', () => {
1, 1, 221, 208, 165, 230, 3, 0, 4, 1, 15, 109, 97, 114, 107, 100, 111, 1, 1, 221, 208, 165, 230, 3, 0, 4, 1, 15, 109, 97, 114, 107, 100, 111,
119, 110, 67, 111, 110, 116, 101, 110, 116, 32, 116, 101, 120, 116, 67, 119, 110, 67, 111, 110, 116, 101, 110, 116, 32, 116, 101, 120, 116, 67,
111, 110, 116, 101, 110, 116, 70, 114, 111, 109, 83, 116, 97, 116, 101, 111, 110, 116, 101, 110, 116, 70, 114, 111, 109, 83, 116, 97, 116, 101,
86, 101, 99, 116, 111, 114, 85, 112, 100, 97, 116, 101, 0 86, 101, 99, 116, 111, 114, 85, 112, 100, 97, 116, 101, 0,
] ],
) )
expect(realtimeDoc.getCurrentContent()).toBe( expect(realtimeDoc.getCurrentContent()).toBe(
'textContentFromStateVectorUpdate' 'textContentFromStateVectorUpdate',
) )
}) })
}) })

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -10,7 +10,7 @@ import {
Doc, Doc,
encodeStateAsUpdate, encodeStateAsUpdate,
encodeStateVector, encodeStateVector,
Text as YText Text as YText,
} from 'yjs' } from 'yjs'
const MARKDOWN_CONTENT_CHANNEL_NAME = 'markdownContent' const MARKDOWN_CONTENT_CHANNEL_NAME = 'markdownContent'
@ -26,7 +26,7 @@ export class RealtimeDoc extends EventEmitter2<RealtimeDocEvents> {
private doc: Doc = new Doc() private doc: Doc = new Doc()
private readonly docUpdateListener: ( private readonly docUpdateListener: (
update: Uint8Array, update: Uint8Array,
origin: unknown origin: unknown,
) => void ) => void
/** /**

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -30,28 +30,28 @@ describe('y-doc-sync-adapter', () => {
textServer.observe(() => textServer.observe(() =>
// eslint-disable-next-line @typescript-eslint/no-base-to-string // eslint-disable-next-line @typescript-eslint/no-base-to-string
console.log('textServer', new Date(), textServer.toString()) console.log('textServer', new Date(), textServer.toString()),
) )
textClient1.observe(() => textClient1.observe(() =>
// eslint-disable-next-line @typescript-eslint/no-base-to-string // eslint-disable-next-line @typescript-eslint/no-base-to-string
console.log('textClient1', new Date(), textClient1.toString()) console.log('textClient1', new Date(), textClient1.toString()),
) )
textClient2.observe(() => textClient2.observe(() =>
// eslint-disable-next-line @typescript-eslint/no-base-to-string // eslint-disable-next-line @typescript-eslint/no-base-to-string
console.log('textClient2', new Date(), textClient2.toString()) console.log('textClient2', new Date(), textClient2.toString()),
) )
const transporterAdapterServerTo1 = new InMemoryConnectionTransportAdapter( const transporterAdapterServerTo1 = new InMemoryConnectionTransportAdapter(
's>1' 's>1',
) )
const transporterAdapterServerTo2 = new InMemoryConnectionTransportAdapter( const transporterAdapterServerTo2 = new InMemoryConnectionTransportAdapter(
's>2' 's>2',
) )
const transporterAdapterClient1 = new InMemoryConnectionTransportAdapter( const transporterAdapterClient1 = new InMemoryConnectionTransportAdapter(
'1>s' '1>s',
) )
const transporterAdapterClient2 = new InMemoryConnectionTransportAdapter( const transporterAdapterClient2 = new InMemoryConnectionTransportAdapter(
'2>s' '2>s',
) )
const messageTransporterServerTo1 = new MessageTransporter() const messageTransporterServerTo1 = new MessageTransporter()
@ -60,54 +60,54 @@ describe('y-doc-sync-adapter', () => {
const messageTransporterClient2 = new MessageTransporter() const messageTransporterClient2 = new MessageTransporter()
messageTransporterServerTo1.on(MessageType.NOTE_CONTENT_UPDATE, () => messageTransporterServerTo1.on(MessageType.NOTE_CONTENT_UPDATE, () =>
console.log('Received NOTE_CONTENT_UPDATE from client 1 to server') console.log('Received NOTE_CONTENT_UPDATE from client 1 to server'),
) )
messageTransporterServerTo2.on(MessageType.NOTE_CONTENT_UPDATE, () => messageTransporterServerTo2.on(MessageType.NOTE_CONTENT_UPDATE, () =>
console.log('Received NOTE_CONTENT_UPDATE from client 2 to server') console.log('Received NOTE_CONTENT_UPDATE from client 2 to server'),
) )
messageTransporterClient1.on(MessageType.NOTE_CONTENT_UPDATE, () => messageTransporterClient1.on(MessageType.NOTE_CONTENT_UPDATE, () =>
console.log('Received NOTE_CONTENT_UPDATE from server to client 1') console.log('Received NOTE_CONTENT_UPDATE from server to client 1'),
) )
messageTransporterClient2.on(MessageType.NOTE_CONTENT_UPDATE, () => messageTransporterClient2.on(MessageType.NOTE_CONTENT_UPDATE, () =>
console.log('Received NOTE_CONTENT_UPDATE from server to client 2') console.log('Received NOTE_CONTENT_UPDATE from server to client 2'),
) )
messageTransporterServerTo1.on(MessageType.NOTE_CONTENT_STATE_REQUEST, () => messageTransporterServerTo1.on(MessageType.NOTE_CONTENT_STATE_REQUEST, () =>
console.log('Received NOTE_CONTENT_REQUEST from client 1 to server') console.log('Received NOTE_CONTENT_REQUEST from client 1 to server'),
) )
messageTransporterServerTo2.on(MessageType.NOTE_CONTENT_STATE_REQUEST, () => messageTransporterServerTo2.on(MessageType.NOTE_CONTENT_STATE_REQUEST, () =>
console.log('Received NOTE_CONTENT_REQUEST from client 2 to server') console.log('Received NOTE_CONTENT_REQUEST from client 2 to server'),
) )
messageTransporterClient1.on(MessageType.NOTE_CONTENT_STATE_REQUEST, () => messageTransporterClient1.on(MessageType.NOTE_CONTENT_STATE_REQUEST, () =>
console.log('Received NOTE_CONTENT_REQUEST from server to client 1') console.log('Received NOTE_CONTENT_REQUEST from server to client 1'),
) )
messageTransporterClient2.on(MessageType.NOTE_CONTENT_STATE_REQUEST, () => messageTransporterClient2.on(MessageType.NOTE_CONTENT_STATE_REQUEST, () =>
console.log('Received NOTE_CONTENT_REQUEST from server to client 2') console.log('Received NOTE_CONTENT_REQUEST from server to client 2'),
) )
messageTransporterClient1.doAsSoonAsConnected(() => messageTransporterClient1.doAsSoonAsConnected(() =>
console.log('1>s is connected') console.log('1>s is connected'),
) )
messageTransporterClient2.doAsSoonAsConnected(() => messageTransporterClient2.doAsSoonAsConnected(() =>
console.log('2>s is connected') console.log('2>s is connected'),
) )
messageTransporterServerTo1.doAsSoonAsConnected(() => messageTransporterServerTo1.doAsSoonAsConnected(() =>
console.log('s>1 is connected') console.log('s>1 is connected'),
) )
messageTransporterServerTo2.doAsSoonAsConnected(() => messageTransporterServerTo2.doAsSoonAsConnected(() =>
console.log('s>2 is connected') console.log('s>2 is connected'),
) )
messageTransporterClient1.doAsSoonAsReady(() => console.log('1>s is ready')) messageTransporterClient1.doAsSoonAsReady(() => console.log('1>s is ready'))
messageTransporterClient2.doAsSoonAsReady(() => console.log('2>s is ready')) messageTransporterClient2.doAsSoonAsReady(() => console.log('2>s is ready'))
messageTransporterServerTo1.doAsSoonAsReady(() => messageTransporterServerTo1.doAsSoonAsReady(() =>
console.log('s>1 is connected') console.log('s>1 is connected'),
) )
messageTransporterServerTo2.doAsSoonAsReady(() => messageTransporterServerTo2.doAsSoonAsReady(() =>
console.log('s>2 is connected') console.log('s>2 is connected'),
) )
docServer.on('update', (update: number[], origin: unknown) => { docServer.on('update', (update: number[], origin: unknown) => {
const message: Message<MessageType.NOTE_CONTENT_UPDATE> = { const message: Message<MessageType.NOTE_CONTENT_UPDATE> = {
type: MessageType.NOTE_CONTENT_UPDATE, type: MessageType.NOTE_CONTENT_UPDATE,
payload: update payload: update,
} }
if (origin !== messageTransporterServerTo1) { if (origin !== messageTransporterServerTo1) {
console.log('YDoc on Server updated. Sending to Client 1') console.log('YDoc on Server updated. Sending to Client 1')
@ -131,23 +131,23 @@ describe('y-doc-sync-adapter', () => {
const yDocSyncAdapter1 = new YDocSyncClientAdapter( const yDocSyncAdapter1 = new YDocSyncClientAdapter(
messageTransporterClient1, messageTransporterClient1,
docClient1 docClient1,
) )
const yDocSyncAdapter2 = new YDocSyncClientAdapter( const yDocSyncAdapter2 = new YDocSyncClientAdapter(
messageTransporterClient2, messageTransporterClient2,
docClient2 docClient2,
) )
const yDocSyncAdapterServerTo1 = new YDocSyncServerAdapter( const yDocSyncAdapterServerTo1 = new YDocSyncServerAdapter(
messageTransporterServerTo1, messageTransporterServerTo1,
docServer, docServer,
() => true () => true,
) )
const yDocSyncAdapterServerTo2 = new YDocSyncServerAdapter( const yDocSyncAdapterServerTo2 = new YDocSyncServerAdapter(
messageTransporterServerTo2, messageTransporterServerTo2,
docServer, docServer,
() => true () => true,
) )
const waitForClient1Sync = new Promise<void>((resolve) => { const waitForClient1Sync = new Promise<void>((resolve) => {
@ -202,7 +202,7 @@ describe('y-doc-sync-adapter', () => {
waitForClient1Sync, waitForClient1Sync,
waitForClient2Sync, waitForClient2Sync,
waitForServerTo11Sync, waitForServerTo11Sync,
waitForServerTo21Sync waitForServerTo21Sync,
]) ])
textClient1.insert(0, 'test2') textClient1.insert(0, 'test2')

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -23,7 +23,7 @@ export abstract class YDocSyncAdapter {
constructor( constructor(
protected readonly messageTransporter: MessageTransporter, protected readonly messageTransporter: MessageTransporter,
protected readonly doc: RealtimeDoc protected readonly doc: RealtimeDoc,
) { ) {
this.yDocUpdateListener = doc.on( this.yDocUpdateListener = doc.on(
'update', 'update',
@ -31,8 +31,8 @@ export abstract class YDocSyncAdapter {
this.distributeDocUpdate(update, origin) this.distributeDocUpdate(update, origin)
}, },
{ {
objectify: true objectify: true,
} },
) as Listener ) as Listener
this.destroyEventListenerCallback = this.bindDocumentSyncMessageEvents() this.destroyEventListenerCallback = this.bindDocumentSyncMessageEvents()
@ -50,7 +50,7 @@ export abstract class YDocSyncAdapter {
callback() callback()
} }
return this.eventEmitter.on('synced', callback, { return this.eventEmitter.on('synced', callback, {
objectify: true objectify: true,
}) as Listener }) as Listener
} }
@ -69,10 +69,10 @@ export abstract class YDocSyncAdapter {
(payload) => { (payload) => {
this.messageTransporter.sendMessage({ this.messageTransporter.sendMessage({
type: MessageType.NOTE_CONTENT_UPDATE, type: MessageType.NOTE_CONTENT_UPDATE,
payload: this.doc.encodeStateAsUpdate(payload.payload) payload: this.doc.encodeStateAsUpdate(payload.payload),
}) })
}, },
{ objectify: true } { objectify: true },
) as Listener ) as Listener
const disconnectedListener = this.messageTransporter.on( const disconnectedListener = this.messageTransporter.on(
@ -81,13 +81,13 @@ export abstract class YDocSyncAdapter {
this.synced = false this.synced = false
this.eventEmitter.emit('desynced') this.eventEmitter.emit('desynced')
}, },
{ objectify: true } { objectify: true },
) as Listener ) as Listener
const noteContentUpdateListener = this.messageTransporter.on( const noteContentUpdateListener = this.messageTransporter.on(
MessageType.NOTE_CONTENT_UPDATE, MessageType.NOTE_CONTENT_UPDATE,
(payload) => this.applyIncomingUpdatePayload(payload.payload), (payload) => this.applyIncomingUpdatePayload(payload.payload),
{ objectify: true } { objectify: true },
) as Listener ) as Listener
return () => { return () => {
@ -107,7 +107,7 @@ export abstract class YDocSyncAdapter {
} }
const message: Message<MessageType.NOTE_CONTENT_UPDATE> = { const message: Message<MessageType.NOTE_CONTENT_UPDATE> = {
type: MessageType.NOTE_CONTENT_UPDATE, type: MessageType.NOTE_CONTENT_UPDATE,
payload: update payload: update,
} }
this.messageTransporter.sendMessage(message) this.messageTransporter.sendMessage(message)
@ -124,7 +124,7 @@ export abstract class YDocSyncAdapter {
public requestDocumentState(): void { public requestDocumentState(): void {
this.messageTransporter.sendMessage({ this.messageTransporter.sendMessage({
type: MessageType.NOTE_CONTENT_STATE_REQUEST, type: MessageType.NOTE_CONTENT_STATE_REQUEST,
payload: this.doc.encodeStateVector() payload: this.doc.encodeStateVector(),
}) })
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -16,7 +16,7 @@ export class YDocSyncClientAdapter extends YDocSyncAdapter {
() => { () => {
this.markAsSynced() this.markAsSynced()
}, },
{ objectify: true } { objectify: true },
) as Listener ) as Listener
return () => { return () => {

View file

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2025 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -11,7 +11,7 @@ export class YDocSyncServerAdapter extends YDocSyncAdapter {
constructor( constructor(
readonly messageTransporter: MessageTransporter, readonly messageTransporter: MessageTransporter,
readonly doc: RealtimeDoc, readonly doc: RealtimeDoc,
private readonly acceptEditsProvider: () => boolean private readonly acceptEditsProvider: () => boolean,
) { ) {
super(messageTransporter, doc) super(messageTransporter, doc)
this.markAsSynced() this.markAsSynced()