Просмотр исходного кода

Merge branch 'imprv/148445-upgrade-remark-growi-directive' into imprv/148445-150048-vitest-reamrk-growi-directive

reiji-h 1 год назад
Родитель
Сommit
be7b7f5c48
50 измененных файлов с 746 добавлено и 492 удалено
  1. 8 0
      apps/app/next.config.js
  2. 17 17
      apps/app/package.json
  3. 2 0
      apps/app/src/client/components/Page/DisplaySwitcher.tsx
  4. 18 10
      apps/app/src/client/components/PageEditor/PageEditor.tsx
  5. 6 6
      apps/app/src/client/components/PageEditor/ScrollSyncHelper.tsx
  6. 9 2
      apps/app/src/client/components/ReactMarkdownComponents/Header.tsx
  7. 6 4
      apps/app/src/features/questionnaire/server/service/questionnaire.ts
  8. 1 1
      apps/app/src/migrations/20180927102719-init-serverurl.js
  9. 1 1
      apps/app/src/migrations/20190618055300-abolish-crowi-classic-auth.js
  10. 1 1
      apps/app/src/migrations/20190618104011-add-config-app-installed.js
  11. 1 1
      apps/app/src/migrations/20200420160390-remove-crowi-layout.js
  12. 1 1
      apps/app/src/migrations/20200512005851-remove-behavior-type.js
  13. 1 1
      apps/app/src/migrations/20200514001356-update-theme-color-for-dark.js
  14. 1 1
      apps/app/src/migrations/20200620203632-normalize-locale-id.js
  15. 1 1
      apps/app/src/migrations/20200827045151-remove-layout-setting.js
  16. 1 1
      apps/app/src/migrations/20200828024025-copy-aws-setting.js
  17. 1 1
      apps/app/src/migrations/20200901034313-update-mail-transmission.js
  18. 1 1
      apps/app/src/migrations/20200903080025-remove-timeline-type.js.js
  19. 1 1
      apps/app/src/migrations/20200915035234-rename-s3-config.js
  20. 1 1
      apps/app/src/migrations/20210830074539-update-configs-for-slackbot.js
  21. 1 1
      apps/app/src/migrations/20211005131430-config-without-proxy-command-permission-for-renaming.js
  22. 2 3
      apps/app/src/migrations/20220311011114-convert-page-delete-config.js
  23. 1 1
      apps/app/src/migrations/20221014130200-remove-customize-is-saved-states-of-tab-changes.js
  24. 1 1
      apps/app/src/migrations/20221219011829-remove-basic-auth-related-config.js
  25. 1 1
      apps/app/src/migrations/20230213090921-remove-presentation-configurations.js
  26. 1 3
      apps/app/src/migrations/20230731075753-add_installed_date_to_config.js
  27. 3 3
      apps/app/src/server/models/config.ts
  28. 12 7
      apps/app/src/server/routes/apiv3/healthcheck.ts
  29. 4 3
      apps/app/src/server/service/config-loader.ts
  30. 5 5
      apps/app/src/server/service/config-manager.spec.ts
  31. 3 3
      apps/app/src/server/service/config-manager.ts
  32. 8 0
      apps/app/src/stores-universal/context.tsx
  33. 32 10
      apps/app/src/stores/editor.tsx
  34. 56 9
      packages/editor/src/client/services/use-codemirror-editor/utils/set-caret-line.ts
  35. 12 12
      packages/presentation/package.json
  36. 1 1
      packages/presentation/src/client/components/GrowiSlides.tsx
  37. 4 4
      packages/remark-attachment-refs/package.json
  38. 3 3
      packages/remark-drawio/package.json
  39. 15 16
      packages/remark-growi-directive/package.json
  40. 12 14
      packages/remark-growi-directive/src/mdast-util-growi-directive/index.js
  41. 1 2
      packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/directive-leaf.js
  42. 1 2
      packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/directive-text.js
  43. 1 2
      packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/factory-attributes.js
  44. 1 3
      packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/factory-label.js
  45. 1 1
      packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/factory-name.js
  46. 1 1
      packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/syntax.js
  47. 1 1
      packages/remark-growi-directive/src/micromark-factory-attributes-devider/index.js
  48. 25 27
      packages/remark-growi-directive/test/mdast-util-growi-directive.test.js
  49. 4 4
      packages/remark-lsx/package.json
  50. 454 297
      yarn.lock

+ 8 - 0
apps/app/next.config.js

@@ -48,6 +48,14 @@ const getTranspilePackages = () => {
     'emoticon',
     'emoticon',
     'direction', // for hast-util-select
     'direction', // for hast-util-select
     'bcp-47-match', // for hast-util-select
     'bcp-47-match', // for hast-util-select
+    'parse-entities',
+    'character-reference-invalid',
+    'is-hexadecimal',
+    'is-alphabetical',
+    'is-alphanumerical',
+    'github-slugger',
+    'html-url-attributes',
+    'estree-util-is-identifier-name',
     ...listPrefixedPackages(['remark-', 'rehype-', 'hast-', 'mdast-', 'micromark-', 'unist-']),
     ...listPrefixedPackages(['remark-', 'rehype-', 'hast-', 'mdast-', 'micromark-', 'unist-']),
   ];
   ];
 
 

+ 17 - 17
apps/app/package.json

@@ -121,7 +121,7 @@
     "extensible-custom-error": "^0.0.7",
     "extensible-custom-error": "^0.0.7",
     "form-data": "^4.0.0",
     "form-data": "^4.0.0",
     "graceful-fs": "^4.1.11",
     "graceful-fs": "^4.1.11",
-    "hast-util-select": "^5.0.5",
+    "hast-util-select": "^6.0.2",
     "helmet": "^4.6.0",
     "helmet": "^4.6.0",
     "http-errors": "^2.0.0",
     "http-errors": "^2.0.0",
     "i18next": "^23.10.1",
     "i18next": "^23.10.1",
@@ -148,9 +148,9 @@
     "next-i18next": "^15.2.0",
     "next-i18next": "^15.2.0",
     "next-superjson": "^0.0.4",
     "next-superjson": "^0.0.4",
     "next-themes": "^0.2.1",
     "next-themes": "^0.2.1",
-    "nocache": "^3.0.1",
+    "nocache": "^4.0.0",
     "node-cron": "^3.0.2",
     "node-cron": "^3.0.2",
-    "nodemailer": "^6.6.2",
+    "nodemailer": "^6.9.14",
     "nodemailer-ses-transport": "~1.5.0",
     "nodemailer-ses-transport": "~1.5.0",
     "openid-client": "^5.4.0",
     "openid-client": "^5.4.0",
     "p-retry": "^4.0.0",
     "p-retry": "^4.0.0",
@@ -171,7 +171,7 @@
     "react-error-boundary": "^3.1.4",
     "react-error-boundary": "^3.1.4",
     "react-i18next": "^14.1.0",
     "react-i18next": "^14.1.0",
     "react-image-crop": "^8.3.0",
     "react-image-crop": "^8.3.0",
-    "react-markdown": "^8.0.7",
+    "react-markdown": "^9.0.1",
     "react-multiline-clamp": "^2.0.0",
     "react-multiline-clamp": "^2.0.0",
     "react-scroll": "^1.8.7",
     "react-scroll": "^1.8.7",
     "react-stickynode": "^4.1.1",
     "react-stickynode": "^4.1.1",
@@ -180,18 +180,18 @@
     "reactstrap": "^9.2.2",
     "reactstrap": "^9.2.2",
     "reconnecting-websocket": "^4.4.0",
     "reconnecting-websocket": "^4.4.0",
     "redis": "^3.0.2",
     "redis": "^3.0.2",
-    "rehype-katex": "^6.0.2",
-    "rehype-raw": "^6.1.1",
-    "rehype-sanitize": "^5.0.1",
-    "rehype-slug": "^5.0.1",
+    "rehype-katex": "^7.0.0",
+    "rehype-raw": "^7.0.0",
+    "rehype-sanitize": "^6.0.0",
+    "rehype-slug": "^6.0.0",
     "rehype-toc": "^3.0.2",
     "rehype-toc": "^3.0.2",
-    "remark-breaks": "^3.0.2",
-    "remark-emoji": "^3.0.2",
-    "remark-frontmatter": "^4.0.1",
-    "remark-gfm": "^3.0.1",
-    "remark-math": "^5.1.1",
-    "remark-toc": "^8.0.1",
-    "remark-wiki-link": "^1.0.4",
+    "remark-breaks": "^4.0.0",
+    "remark-emoji": "^5.0.0",
+    "remark-frontmatter": "^5.0.0",
+    "remark-gfm": "^4.0.0",
+    "remark-math": "^6.0.0",
+    "remark-toc": "^9.0.0",
+    "remark-wiki-link": "^2.0.1",
     "sanitize-filename": "^1.6.3",
     "sanitize-filename": "^1.6.3",
     "socket.io": "^4.7.5",
     "socket.io": "^4.7.5",
     "stream-to-promise": "^3.0.0",
     "stream-to-promise": "^3.0.0",
@@ -230,7 +230,7 @@
     "@swc/jest": "^0.2.36",
     "@swc/jest": "^0.2.36",
     "@testing-library/react": "^14.1.2",
     "@testing-library/react": "^14.1.2",
     "@testing-library/user-event": "^14.5.2",
     "@testing-library/user-event": "^14.5.2",
-    "@types/express": "^4.17.11",
+    "@types/express": "^4.17.21",
     "@types/jest": "^29.5.2",
     "@types/jest": "^29.5.2",
     "@types/react-input-autosize": "^2.2.4",
     "@types/react-input-autosize": "^2.2.4",
     "@types/react-scroll": "^1.8.4",
     "@types/react-scroll": "^1.8.4",
@@ -273,7 +273,7 @@
     "react-hotkeys": "^2.0.0",
     "react-hotkeys": "^2.0.0",
     "react-input-autosize": "^3.0.0",
     "react-input-autosize": "^3.0.0",
     "react-toastify": "^9.1.3",
     "react-toastify": "^9.1.3",
-    "rehype-rewrite": "^3.0.6",
+    "rehype-rewrite": "^4.0.2",
     "replacestream": "^4.0.3",
     "replacestream": "^4.0.3",
     "sass": "^1.53.0",
     "sass": "^1.53.0",
     "simple-load-script": "^1.0.2",
     "simple-load-script": "^1.0.2",

+ 2 - 0
apps/app/src/client/components/Page/DisplaySwitcher.tsx

@@ -3,6 +3,7 @@ import dynamic from 'next/dynamic';
 import { useHashChangedEffect } from '~/client/services/side-effects/hash-changed';
 import { useHashChangedEffect } from '~/client/services/side-effects/hash-changed';
 import { useIsEditable } from '~/stores-universal/context';
 import { useIsEditable } from '~/stores-universal/context';
 import { EditorMode, useEditorMode } from '~/stores-universal/ui';
 import { EditorMode, useEditorMode } from '~/stores-universal/ui';
+import { useReservedNextCaretLine } from '~/stores/editor';
 import { useIsLatestRevision } from '~/stores/page';
 import { useIsLatestRevision } from '~/stores/page';
 
 
 import { LazyRenderer } from '../Common/LazyRenderer';
 import { LazyRenderer } from '../Common/LazyRenderer';
@@ -18,6 +19,7 @@ export const DisplaySwitcher = (): JSX.Element => {
   const { data: isLatestRevision } = useIsLatestRevision();
   const { data: isLatestRevision } = useIsLatestRevision();
 
 
   useHashChangedEffect();
   useHashChangedEffect();
+  useReservedNextCaretLine();
 
 
   return (
   return (
     <LazyRenderer shouldRender={isEditable === true && editorMode === EditorMode.Editor}>
     <LazyRenderer shouldRender={isEditable === true && editorMode === EditorMode.Editor}>

+ 18 - 10
apps/app/src/client/components/PageEditor/PageEditor.tsx

@@ -32,6 +32,7 @@ import {
 import { EditorMode, useEditorMode } from '~/stores-universal/ui';
 import { EditorMode, useEditorMode } from '~/stores-universal/ui';
 import { useNextThemes } from '~/stores-universal/use-next-themes';
 import { useNextThemes } from '~/stores-universal/use-next-themes';
 import {
 import {
+  useReservedNextCaretLine,
   useEditorSettings,
   useEditorSettings,
   useCurrentIndentSize,
   useCurrentIndentSize,
   useEditingMarkdown,
   useEditingMarkdown,
@@ -109,6 +110,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   const { data: user } = useCurrentUser();
   const { data: user } = useCurrentUser();
   const { onEditorsUpdated } = useEditingUsers();
   const { onEditorsUpdated } = useEditingUsers();
   const onConflict = useConflictResolver();
   const onConflict = useConflictResolver();
+  const { data: reservedNextCaretLine, mutate: mutateReservedNextCaretLine } = useReservedNextCaretLine();
 
 
   const { data: rendererOptions } = usePreviewOptions();
   const { data: rendererOptions } = usePreviewOptions();
 
 
@@ -298,19 +300,25 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     }
     }
   }, [initialValue, isIndentSizeForced, mutateCurrentIndentSize]);
   }, [initialValue, isIndentSizeForced, mutateCurrentIndentSize]);
 
 
-  // set handler to set caret line
+
+  // set caret line if the edit button next to Header is clicked.
   useEffect(() => {
   useEffect(() => {
-    const handler = (lineNumber?: number) => {
-      codeMirrorEditor?.setCaretLine(lineNumber);
+    if (codeMirrorEditor?.setCaretLine == null) {
+      return;
+    }
+    if (editorMode === EditorMode.Editor) {
+      codeMirrorEditor.setCaretLine(reservedNextCaretLine ?? 0, true);
+    }
 
 
-      // TODO: scroll to the caret line
-    };
-    globalEmitter.on('setCaretLine', handler);
+  }, [codeMirrorEditor, editorMode, reservedNextCaretLine]);
+
+  // reset caret line if returning to the View.
+  useEffect(() => {
+    if (editorMode === EditorMode.View) {
+      mutateReservedNextCaretLine(0);
+    }
+  }, [editorMode, mutateReservedNextCaretLine]);
 
 
-    return function cleanup() {
-      globalEmitter.removeListener('setCaretLine', handler);
-    };
-  }, [codeMirrorEditor]);
 
 
   // TODO: Check the reproduction conditions that made this code necessary and confirm reproduction
   // TODO: Check the reproduction conditions that made this code necessary and confirm reproduction
   // // when transitioning to a different page, if the initialValue is the same,
   // // when transitioning to a different page, if the initialValue is the same,

+ 6 - 6
apps/app/src/client/components/PageEditor/ScrollSyncHelper.tsx

@@ -121,12 +121,12 @@ const scrollEditor = (editorRootElement: HTMLElement, previewRootElement: HTMLEl
   newScrollTop += calcScrollElementToTop(previewElements[topPreviewElementIndex]);
   newScrollTop += calcScrollElementToTop(previewElements[topPreviewElementIndex]);
   newScrollTop += calcScorllElementByRatio(
   newScrollTop += calcScorllElementByRatio(
     {
     {
-      start: editorElements[startEditorElementIndex].getBoundingClientRect(),
-      top: editorElements[topEditorElementIndex].getBoundingClientRect(),
+      start: editorElements[startEditorElementIndex]?.getBoundingClientRect(),
+      top: editorElements[topEditorElementIndex]?.getBoundingClientRect(),
       next: editorElements[nextEditorElementIndex]?.getBoundingClientRect(),
       next: editorElements[nextEditorElementIndex]?.getBoundingClientRect(),
     },
     },
     {
     {
-      start: previewElements[topPreviewElementIndex].getBoundingClientRect(),
+      start: previewElements[topPreviewElementIndex]?.getBoundingClientRect(),
       next: previewElements[topPreviewElementIndex + 1]?.getBoundingClientRect(),
       next: previewElements[topPreviewElementIndex + 1]?.getBoundingClientRect(),
     },
     },
   );
   );
@@ -156,12 +156,12 @@ const scrollPreview = (editorRootElement: HTMLElement, previewRootElement: HTMLE
   newScrollTop += calcScrollElementToTop(editorElements[startEditorElementIndex]);
   newScrollTop += calcScrollElementToTop(editorElements[startEditorElementIndex]);
   newScrollTop += calcScorllElementByRatio(
   newScrollTop += calcScorllElementByRatio(
     {
     {
-      start: previewElements[topPreviewElementIndex].getBoundingClientRect(),
-      top: previewElements[topPreviewElementIndex].getBoundingClientRect(),
+      start: previewElements[topPreviewElementIndex]?.getBoundingClientRect(),
+      top: previewElements[topPreviewElementIndex]?.getBoundingClientRect(),
       next: previewElements[topPreviewElementIndex + 1]?.getBoundingClientRect(),
       next: previewElements[topPreviewElementIndex + 1]?.getBoundingClientRect(),
     },
     },
     {
     {
-      start: editorElements[startEditorElementIndex].getBoundingClientRect(),
+      start: editorElements[startEditorElementIndex]?.getBoundingClientRect(),
       next: editorElements[nextEditorElementIndex]?.getBoundingClientRect(),
       next: editorElements[nextEditorElementIndex]?.getBoundingClientRect(),
     },
     },
   );
   );

+ 9 - 2
apps/app/src/client/components/ReactMarkdownComponents/Header.tsx

@@ -9,6 +9,7 @@ import { NextLink } from '~/components/ReactMarkdownComponents/NextLink';
 import {
 import {
   useIsGuestUser, useIsReadOnlyUser, useIsSharedUser, useShareLinkId,
   useIsGuestUser, useIsReadOnlyUser, useIsSharedUser, useShareLinkId,
 } from '~/stores-universal/context';
 } from '~/stores-universal/context';
+import { useCurrentPageYjsData } from '~/stores/yjs';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
 
 
@@ -26,7 +27,7 @@ declare global {
 
 
 function setCaretLine(line?: number): void {
 function setCaretLine(line?: number): void {
   if (line != null) {
   if (line != null) {
-    globalEmitter.emit('setCaretLine', line);
+    globalEmitter.emit('reservedNextCaretLine', line);
   }
   }
 }
 }
 
 
@@ -66,6 +67,7 @@ export const Header = (props: HeaderProps): JSX.Element => {
   const { data: isReadOnlyUser } = useIsReadOnlyUser();
   const { data: isReadOnlyUser } = useIsReadOnlyUser();
   const { data: isSharedUser } = useIsSharedUser();
   const { data: isSharedUser } = useIsSharedUser();
   const { data: shareLinkId } = useShareLinkId();
   const { data: shareLinkId } = useShareLinkId();
+  const { data: currentPageYjsData } = useCurrentPageYjsData();
 
 
   const router = useRouter();
   const router = useRouter();
 
 
@@ -111,7 +113,12 @@ export const Header = (props: HeaderProps): JSX.Element => {
     };
     };
   }, [activateByHash, router.events]);
   }, [activateByHash, router.events]);
 
 
-  const showEditButton = !isGuestUser && !isReadOnlyUser && !isSharedUser && shareLinkId == null;
+  // TODO: currentPageYjsData?.hasYdocsNewerThanLatestRevision === false make to hide the edit button when a Yjs draft exists
+  // This is because the current conditional logic cannot handle cases where the draft is an empty string.
+  // It will be possible to address this TODO ySyncAnnotation become available for import.
+  // Ref: https://github.com/yjs/y-codemirror.next/pull/30
+  const showEditButton = !isGuestUser && !isReadOnlyUser && !isSharedUser && shareLinkId == null
+                            && currentPageYjsData?.hasYdocsNewerThanLatestRevision === false;
 
 
   return (
   return (
     <>
     <>

+ 6 - 4
apps/app/src/features/questionnaire/server/service/questionnaire.ts

@@ -3,19 +3,21 @@ import * as os from 'node:os';
 
 
 import type { IUserHasId } from '@growi/core';
 import type { IUserHasId } from '@growi/core';
 
 
-import { ObjectIdLike } from '~/server/interfaces/mongoose-utils';
+import type { ObjectIdLike } from '~/server/interfaces/mongoose-utils';
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { aclService } from '~/server/service/acl';
 import { aclService } from '~/server/service/acl';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
+import type { IGrowiInfo } from '../../interfaces/growi-info';
 import {
 import {
-  GrowiWikiType, GrowiExternalAuthProviderType, IGrowiInfo, GrowiServiceType, GrowiAttachmentType, GrowiDeploymentType,
+  GrowiWikiType, GrowiExternalAuthProviderType, GrowiServiceType, GrowiAttachmentType, GrowiDeploymentType,
 } from '../../interfaces/growi-info';
 } from '../../interfaces/growi-info';
 import { StatusType } from '../../interfaces/questionnaire-answer-status';
 import { StatusType } from '../../interfaces/questionnaire-answer-status';
 import { type IUserInfo, UserType } from '../../interfaces/user-info';
 import { type IUserInfo, UserType } from '../../interfaces/user-info';
 import QuestionnaireAnswerStatus from '../models/questionnaire-answer-status';
 import QuestionnaireAnswerStatus from '../models/questionnaire-answer-status';
-import QuestionnaireOrder, { QuestionnaireOrderDocument } from '../models/questionnaire-order';
+import type { QuestionnaireOrderDocument } from '../models/questionnaire-order';
+import QuestionnaireOrder from '../models/questionnaire-order';
 import { isShowableCondition } from '../util/condition';
 import { isShowableCondition } from '../util/condition';
 
 
 
 

+ 1 - 1
apps/app/src/migrations/20180927102719-init-serverurl.js

@@ -1,7 +1,7 @@
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20190618055300-abolish-crowi-classic-auth.js

@@ -1,7 +1,7 @@
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20190618104011-add-config-app-installed.js

@@ -1,7 +1,7 @@
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getModelSafely, getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getModelSafely, getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20200420160390-remove-crowi-layout.js

@@ -1,7 +1,7 @@
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20200512005851-remove-behavior-type.js

@@ -1,7 +1,7 @@
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20200514001356-update-theme-color-for-dark.js

@@ -1,7 +1,7 @@
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20200620203632-normalize-locale-id.js

@@ -1,7 +1,7 @@
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getModelSafely, getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getModelSafely, getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20200827045151-remove-layout-setting.js

@@ -1,7 +1,7 @@
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20200828024025-copy-aws-setting.js

@@ -1,7 +1,7 @@
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20200901034313-update-mail-transmission.js

@@ -1,7 +1,7 @@
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20200903080025-remove-timeline-type.js.js

@@ -1,5 +1,5 @@
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20200915035234-rename-s3-config.js

@@ -1,5 +1,5 @@
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20210830074539-update-configs-for-slackbot.js

@@ -1,7 +1,7 @@
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20211005131430-config-without-proxy-command-permission-for-renaming.js

@@ -1,7 +1,7 @@
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 2 - 3
apps/app/src/migrations/20220311011114-convert-page-delete-config.js

@@ -3,8 +3,8 @@ import mongoose from 'mongoose';
 import {
 import {
   PageRecursiveDeleteConfigValue, PageRecursiveDeleteCompConfigValue,
   PageRecursiveDeleteConfigValue, PageRecursiveDeleteCompConfigValue,
 } from '~/interfaces/page-delete-config';
 } from '~/interfaces/page-delete-config';
-import ConfigModel from '~/server/models/config';
-import { getModelSafely, getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
+import { Config } from '~/server/models/config';
+import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
 const logger = loggerFactory('growi:migrate:convert-page-delete-config');
 const logger = loggerFactory('growi:migrate:convert-page-delete-config');
@@ -13,7 +13,6 @@ const logger = loggerFactory('growi:migrate:convert-page-delete-config');
 module.exports = {
 module.exports = {
   async up(db, client) {
   async up(db, client) {
     mongoose.connect(getMongoUri(), mongoOptions);
     mongoose.connect(getMongoUri(), mongoOptions);
-    const Config = getModelSafely('Config') || ConfigModel;
 
 
     const isNewConfigExists = await Config.count({
     const isNewConfigExists = await Config.count({
       ns: 'crowi',
       ns: 'crowi',

+ 1 - 1
apps/app/src/migrations/20221014130200-remove-customize-is-saved-states-of-tab-changes.js

@@ -1,5 +1,5 @@
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20221219011829-remove-basic-auth-related-config.js

@@ -1,5 +1,5 @@
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 1
apps/app/src/migrations/20230213090921-remove-presentation-configurations.js

@@ -1,5 +1,5 @@
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import Config from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 

+ 1 - 3
apps/app/src/migrations/20230731075753-add_installed_date_to_config.js

@@ -1,5 +1,5 @@
 // eslint-disable-next-line import/no-named-as-default
 // eslint-disable-next-line import/no-named-as-default
-import ConfigModel from '~/server/models/config';
+import { Config } from '~/server/models/config';
 import { getModelSafely, getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import { getModelSafely, getMongoUri, mongoOptions } from '~/server/util/mongoose-utils';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
@@ -12,7 +12,6 @@ module.exports = {
   async up() {
   async up() {
     logger.info('Apply migration');
     logger.info('Apply migration');
     mongoose.connect(getMongoUri(), mongoOptions);
     mongoose.connect(getMongoUri(), mongoOptions);
-    const Config = getModelSafely('Config') || ConfigModel;
     const User = getModelSafely('User') || require('~/server/models/user')();
     const User = getModelSafely('User') || require('~/server/models/user')();
 
 
     const appInstalled = await Config.findOne({ key: 'app:installed' });
     const appInstalled = await Config.findOne({ key: 'app:installed' });
@@ -39,7 +38,6 @@ module.exports = {
   async down() {
   async down() {
     logger.info('Rollback migration');
     logger.info('Rollback migration');
     mongoose.connect(getMongoUri(), mongoOptions);
     mongoose.connect(getMongoUri(), mongoOptions);
-    const Config = getModelSafely('Config') || ConfigModel;
 
 
     const appInstalled = await Config.findOne({ key: 'app:installed' });
     const appInstalled = await Config.findOne({ key: 'app:installed' });
     if (appInstalled != null) {
     if (appInstalled != null) {

+ 3 - 3
apps/app/src/server/models/config.ts

@@ -7,7 +7,7 @@ import { RehypeSanitizeType } from '~/interfaces/services/rehype-sanitize';
 import { getOrCreateModel } from '../util/mongoose-utils';
 import { getOrCreateModel } from '../util/mongoose-utils';
 
 
 
 
-export interface Config {
+export interface IConfig {
   _id: Types.ObjectId;
   _id: Types.ObjectId;
   ns: string;
   ns: string;
   key: string;
   key: string;
@@ -21,7 +21,7 @@ export interface Config {
 interface ModelMethods { any }
 interface ModelMethods { any }
 
 
 
 
-const schema = new Schema<Config>({
+const schema = new Schema<IConfig>({
   ns: { type: String, required: true },
   ns: { type: String, required: true },
   key: { type: String, required: true },
   key: { type: String, required: true },
   value: { type: String, required: true },
   value: { type: String, required: true },
@@ -176,4 +176,4 @@ export const defaultNotificationConfigs: { [key: string]: any } = {
   'slack:token': undefined,
   'slack:token': undefined,
 };
 };
 
 
-export default getOrCreateModel<Config, ModelMethods>('Config', schema);
+export const Config = getOrCreateModel<IConfig, ModelMethods>('Config', schema);

+ 12 - 7
apps/app/src/server/routes/apiv3/healthcheck.js → apps/app/src/server/routes/apiv3/healthcheck.ts

@@ -1,14 +1,17 @@
 import { ErrorV3 } from '@growi/core/dist/models';
 import { ErrorV3 } from '@growi/core/dist/models';
+import express from 'express';
+import nocache from 'nocache';
 
 
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
-const logger = loggerFactory('growi:routes:apiv3:healthcheck'); // eslint-disable-line no-unused-vars
+import { Config } from '../../models/config';
 
 
-const express = require('express');
+import type { ApiV3Response } from './interfaces/apiv3-response';
 
 
-const router = express.Router();
 
 
-const noCache = require('nocache');
+const logger = loggerFactory('growi:routes:apiv3:healthcheck');
+
+const router = express.Router();
 
 
 /**
 /**
  * @swagger
  * @swagger
@@ -52,7 +55,6 @@ module.exports = (crowi) => {
 
 
   async function checkMongo(errors, info) {
   async function checkMongo(errors, info) {
     try {
     try {
-      const Config = crowi.models.Config;
       await Config.findOne({});
       await Config.findOne({});
 
 
       info.mongo = 'OK';
       info.mongo = 'OK';
@@ -123,8 +125,11 @@ module.exports = (crowi) => {
    *                  info:
    *                  info:
    *                    $ref: '#/components/schemas/HealthcheckInfo'
    *                    $ref: '#/components/schemas/HealthcheckInfo'
    */
    */
-  router.get('/', noCache(), async(req, res) => {
-    let checkServices = req.query.checkServices || [];
+  router.get('/', nocache(), async(req, res: ApiV3Response) => {
+    let checkServices = (() => {
+      if (req.query.checkServices == null) return [];
+      return Array.isArray(req.query.checkServices) ? req.query.checkServices : [req.query.checkServices];
+    })();
     let isStrictly = req.query.strictly != null;
     let isStrictly = req.query.strictly != null;
 
 
     // for backward compatibility
     // for backward compatibility

+ 4 - 3
apps/app/src/server/service/config-loader.ts

@@ -4,8 +4,9 @@ import { parseISO } from 'date-fns/parseISO';
 import { GrowiServiceType } from '~/features/questionnaire/interfaces/growi-info';
 import { GrowiServiceType } from '~/features/questionnaire/interfaces/growi-info';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
-import type { Config } from '../models/config';
-import ConfigModel, { defaultCrowiConfigs, defaultMarkdownConfigs, defaultNotificationConfigs } from '../models/config';
+import {
+  Config, defaultCrowiConfigs, defaultMarkdownConfigs, defaultNotificationConfigs,
+} from '../models/config';
 
 
 
 
 const logger = loggerFactory('growi:service:ConfigLoader');
 const logger = loggerFactory('growi:service:ConfigLoader');
@@ -790,7 +791,7 @@ export default class ConfigLoader {
 
 
   async loadFromDB(): Promise<any> {
   async loadFromDB(): Promise<any> {
     const config = {};
     const config = {};
-    const docs: Config[] = await ConfigModel.find().exec();
+    const docs = await Config.find().exec();
 
 
     for (const doc of docs) {
     for (const doc of docs) {
       if (!config[doc.ns]) {
       if (!config[doc.ns]) {

+ 5 - 5
apps/app/src/server/service/config-manager.spec.ts

@@ -1,6 +1,6 @@
 import { mock } from 'vitest-mock-extended';
 import { mock } from 'vitest-mock-extended';
 
 
-import ConfigModel from '../models/config';
+import { Config } from '../models/config';
 
 
 import { configManager } from './config-manager';
 import { configManager } from './config-manager';
 import type { S2sMessagingService } from './s2s-messaging/base';
 import type { S2sMessagingService } from './s2s-messaging/base';
@@ -19,7 +19,7 @@ describe('ConfigManager test', () => {
 
 
     test('invoke publishUpdateMessage()', async() => {
     test('invoke publishUpdateMessage()', async() => {
       // setup
       // setup
-      ConfigModel.bulkWrite = vi.fn();
+      Config.bulkWrite = vi.fn();
       configManager.loadConfigs = vi.fn();
       configManager.loadConfigs = vi.fn();
       configManager.publishUpdateMessage = vi.fn();
       configManager.publishUpdateMessage = vi.fn();
 
 
@@ -28,14 +28,14 @@ describe('ConfigManager test', () => {
       await configManager.updateConfigsInTheSameNamespace('dummyNs', dummyConfig);
       await configManager.updateConfigsInTheSameNamespace('dummyNs', dummyConfig);
 
 
       // then
       // then
-      expect(ConfigModel.bulkWrite).toHaveBeenCalledTimes(1);
+      expect(Config.bulkWrite).toHaveBeenCalledTimes(1);
       expect(configManager.loadConfigs).toHaveBeenCalledTimes(1);
       expect(configManager.loadConfigs).toHaveBeenCalledTimes(1);
       expect(configManager.publishUpdateMessage).toHaveBeenCalledTimes(1);
       expect(configManager.publishUpdateMessage).toHaveBeenCalledTimes(1);
     });
     });
 
 
     test('does not invoke publishUpdateMessage()', async() => {
     test('does not invoke publishUpdateMessage()', async() => {
       // setup
       // setup
-      ConfigModel.bulkWrite = vi.fn();
+      Config.bulkWrite = vi.fn();
       configManager.loadConfigs = vi.fn();
       configManager.loadConfigs = vi.fn();
       configManager.publishUpdateMessage = vi.fn();
       configManager.publishUpdateMessage = vi.fn();
 
 
@@ -44,7 +44,7 @@ describe('ConfigManager test', () => {
       await configManager.updateConfigsInTheSameNamespace('dummyNs', dummyConfig, true);
       await configManager.updateConfigsInTheSameNamespace('dummyNs', dummyConfig, true);
 
 
       // then
       // then
-      expect(ConfigModel.bulkWrite).toHaveBeenCalledTimes(1);
+      expect(Config.bulkWrite).toHaveBeenCalledTimes(1);
       expect(configManager.loadConfigs).toHaveBeenCalledTimes(1);
       expect(configManager.loadConfigs).toHaveBeenCalledTimes(1);
       expect(configManager.publishUpdateMessage).not.toHaveBeenCalled();
       expect(configManager.publishUpdateMessage).not.toHaveBeenCalled();
     });
     });

+ 3 - 3
apps/app/src/server/service/config-manager.ts

@@ -2,7 +2,7 @@ import { parseISO } from 'date-fns/parseISO';
 
 
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
-import ConfigModel from '../models/config';
+import { Config } from '../models/config';
 import S2sMessage from '../models/vo/s2s-message';
 import S2sMessage from '../models/vo/s2s-message';
 
 
 import type { ConfigObject } from './config-loader';
 import type { ConfigObject } from './config-loader';
@@ -204,7 +204,7 @@ class ConfigManagerImpl implements ConfigManager, S2sMessageHandlable {
         },
         },
       });
       });
     }
     }
-    await ConfigModel.bulkWrite(queries);
+    await Config.bulkWrite(queries);
 
 
     await this.loadConfigs();
     await this.loadConfigs();
 
 
@@ -223,7 +223,7 @@ class ConfigManagerImpl implements ConfigManager, S2sMessageHandlable {
         },
         },
       });
       });
     }
     }
-    await ConfigModel.bulkWrite(queries);
+    await Config.bulkWrite(queries);
 
 
     await this.loadConfigs();
     await this.loadConfigs();
 
 

+ 8 - 0
apps/app/src/stores-universal/context.tsx

@@ -1,3 +1,7 @@
+import { useCallback, useEffect } from 'react';
+
+import type EventEmitter from 'events';
+
 import { AcceptedUploadFileType } from '@growi/core';
 import { AcceptedUploadFileType } from '@growi/core';
 import type { ColorScheme, IUserHasId } from '@growi/core';
 import type { ColorScheme, IUserHasId } from '@growi/core';
 import { useSWRStatic } from '@growi/core/dist/swr';
 import { useSWRStatic } from '@growi/core/dist/swr';
@@ -12,6 +16,10 @@ import type { TargetAndAncestors } from '../interfaces/page-listing-results';
 
 
 import { useContextSWR } from './use-context-swr';
 import { useContextSWR } from './use-context-swr';
 
 
+declare global {
+  // eslint-disable-next-line vars-on-top, no-var
+  var globalEmitter: EventEmitter;
+}
 
 
 type Nullable<T> = T | null;
 type Nullable<T> = T | null;
 
 

+ 32 - 10
apps/app/src/stores/editor.tsx

@@ -1,7 +1,7 @@
-import { useCallback } from 'react';
+import { useCallback, useEffect } from 'react';
 
 
 import { type Nullable } from '@growi/core';
 import { type Nullable } from '@growi/core';
-import { withUtils, type SWRResponseWithUtils } from '@growi/core/dist/swr';
+import { withUtils, type SWRResponseWithUtils, useSWRStatic } from '@growi/core/dist/swr';
 import type { EditorSettings } from '@growi/editor';
 import type { EditorSettings } from '@growi/editor';
 import useSWR, { type SWRResponse } from 'swr';
 import useSWR, { type SWRResponse } from 'swr';
 import useSWRImmutable from 'swr/immutable';
 import useSWRImmutable from 'swr/immutable';
@@ -9,22 +9,21 @@ import useSWRImmutable from 'swr/immutable';
 import { apiGet } from '~/client/util/apiv1-client';
 import { apiGet } from '~/client/util/apiv1-client';
 import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
 import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
 import type { SlackChannels } from '~/interfaces/user-trigger-notification';
 import type { SlackChannels } from '~/interfaces/user-trigger-notification';
-
 import {
 import {
   useCurrentUser, useDefaultIndentSize, useIsGuestUser, useIsReadOnlyUser,
   useCurrentUser, useDefaultIndentSize, useIsGuestUser, useIsReadOnlyUser,
 } from '~/stores-universal/context';
 } from '~/stores-universal/context';
+
 // import { localStorageMiddleware } from './middlewares/sync-to-storage';
 // import { localStorageMiddleware } from './middlewares/sync-to-storage';
 import { useSWRxTagsInfo } from './page';
 import { useSWRxTagsInfo } from './page';
-import { useStaticSWR } from './use-static-swr';
 
 
 
 
 export const useWaitingSaveProcessing = (): SWRResponse<boolean, Error> => {
 export const useWaitingSaveProcessing = (): SWRResponse<boolean, Error> => {
-  return useStaticSWR('waitingSaveProcessing', undefined, { fallbackData: false });
+  return useSWRStatic('waitingSaveProcessing', undefined, { fallbackData: false });
 };
 };
 
 
 
 
 export const useEditingMarkdown = (initialData?: string): SWRResponse<string, Error> => {
 export const useEditingMarkdown = (initialData?: string): SWRResponse<string, Error> => {
-  return useStaticSWR('editingMarkdown', initialData);
+  return useSWRStatic('editingMarkdown', initialData);
 };
 };
 
 
 
 
@@ -69,7 +68,7 @@ export const useEditorSettings = (): SWRResponseWithUtils<EditorSettingsOperatio
 
 
 export const useCurrentIndentSize = (): SWRResponse<number, Error> => {
 export const useCurrentIndentSize = (): SWRResponse<number, Error> => {
   const { data: defaultIndentSize } = useDefaultIndentSize();
   const { data: defaultIndentSize } = useDefaultIndentSize();
-  return useStaticSWR<number, Error>(
+  return useSWRStatic<number, Error>(
     defaultIndentSize == null ? null : 'currentIndentSize',
     defaultIndentSize == null ? null : 'currentIndentSize',
     undefined,
     undefined,
     { fallbackData: defaultIndentSize },
     { fallbackData: defaultIndentSize },
@@ -92,7 +91,7 @@ export const useSWRxSlackChannels = (currentPagePath: Nullable<string>): SWRResp
 };
 };
 
 
 export const useIsSlackEnabled = (): SWRResponse<boolean, Error> => {
 export const useIsSlackEnabled = (): SWRResponse<boolean, Error> => {
-  return useStaticSWR(
+  return useSWRStatic(
     'isSlackEnabled',
     'isSlackEnabled',
     undefined,
     undefined,
     { fallbackData: false },
     { fallbackData: false },
@@ -105,7 +104,7 @@ export type IPageTagsForEditorsOption = {
 
 
 export const usePageTagsForEditors = (pageId: Nullable<string>): SWRResponse<string[], Error> & IPageTagsForEditorsOption => {
 export const usePageTagsForEditors = (pageId: Nullable<string>): SWRResponse<string[], Error> & IPageTagsForEditorsOption => {
   const { data: tagsInfoData } = useSWRxTagsInfo(pageId);
   const { data: tagsInfoData } = useSWRxTagsInfo(pageId);
-  const swrResult = useStaticSWR<string[], Error>('pageTags', undefined);
+  const swrResult = useSWRStatic<string[], Error>('pageTags', undefined);
   const { mutate } = swrResult;
   const { mutate } = swrResult;
   const sync = useCallback((): void => {
   const sync = useCallback((): void => {
     mutate(tagsInfoData?.tags || [], false);
     mutate(tagsInfoData?.tags || [], false);
@@ -118,5 +117,28 @@ export const usePageTagsForEditors = (pageId: Nullable<string>): SWRResponse<str
 };
 };
 
 
 export const useIsEnabledUnsavedWarning = (): SWRResponse<boolean, Error> => {
 export const useIsEnabledUnsavedWarning = (): SWRResponse<boolean, Error> => {
-  return useStaticSWR<boolean, Error>('isEnabledUnsavedWarning');
+  return useSWRStatic<boolean, Error>('isEnabledUnsavedWarning');
+};
+
+
+export const useReservedNextCaretLine = (initialData?: number): SWRResponse<number> => {
+
+  const swrResponse = useSWRStatic('saveNextCaretLine', initialData, { fallbackData: 0 });
+  const { mutate } = swrResponse;
+
+  useEffect(() => {
+    const handler = (lineNumber: number) => {
+      mutate(lineNumber);
+    };
+
+    globalEmitter.on('reservedNextCaretLine', handler);
+
+    return function cleanup() {
+      globalEmitter.removeListener('reservedNextCaretLine', handler);
+    };
+  }, [mutate]);
+
+  return {
+    ...swrResponse,
+  };
 };
 };

+ 56 - 9
packages/editor/src/client/services/use-codemirror-editor/utils/set-caret-line.ts

@@ -1,27 +1,74 @@
 import { useCallback } from 'react';
 import { useCallback } from 'react';
 
 
-import type { EditorView } from '@codemirror/view';
+import { Compartment, StateEffect } from '@codemirror/state';
+import { EditorView } from '@codemirror/view';
+import type { ViewUpdate } from '@codemirror/view';
 
 
-export type SetCaretLine = (lineNumber?: number) => void;
+export type SetCaretLine = (lineNumber?: number, schedule?: boolean) => void;
 
 
-export const useSetCaretLine = (view?: EditorView): SetCaretLine => {
-
-  return useCallback((lineNumber) => {
-    const doc = view?.state.doc;
+const setCaretLine = (view?: EditorView, lineNumber?: number): void => {
+  const doc = view?.state.doc;
 
 
-    if (doc == null) {
-      return;
-    }
+  if (doc == null) {
+    return;
+  }
 
 
+  try {
     const posOfLineEnd = doc.line(lineNumber ?? 1).to;
     const posOfLineEnd = doc.line(lineNumber ?? 1).to;
     view?.dispatch({
     view?.dispatch({
       selection: {
       selection: {
         anchor: posOfLineEnd,
         anchor: posOfLineEnd,
         head: posOfLineEnd,
         head: posOfLineEnd,
       },
       },
+      scrollIntoView: true,
+      effects: EditorView.scrollIntoView(posOfLineEnd, { x: 'end', y: 'center' }),
     });
     });
     // focus
     // focus
     view?.focus();
     view?.focus();
+  }
+  catch (_: unknown) {
+    // if posOfLineEnd is not found.
+  }
+
+};
+
+const setCaretLineScheduleForYjs = (view?: EditorView, lineNumber?: number): void => {
+
+  const compartment = new Compartment();
+
+  const setCaretLineOnceExtension = EditorView.updateListener.of((v: ViewUpdate) => {
+
+    // TODO: use ySyncAnnotation for if statement and remove "currentPageYjsData?.hasRevisionBodyDiff === false" in Header.tsx
+    // Ref: https://github.com/yjs/y-codemirror.next/pull/30
+    if (v.docChanged && v.changes.desc.length === 0) {
+
+      setCaretLine(view, lineNumber);
+
+      // setCaretLineOnceExtension, which setCaretLineScheduleForYjs added, will remove itself from view.
+      view?.dispatch({
+        effects: compartment.reconfigure([]),
+      });
+    }
+  });
+
+  view?.dispatch({
+    effects: StateEffect.appendConfig.of(
+      compartment.of(setCaretLineOnceExtension),
+    ),
+  });
+};
+
+export const useSetCaretLine = (view?: EditorView): SetCaretLine => {
+
+  return useCallback((lineNumber?: number, schedule?: boolean) => {
+
+    if (schedule) {
+      setCaretLineScheduleForYjs(view, lineNumber);
+    }
+    else {
+      setCaretLine(view, lineNumber);
+    }
+
   }, [view]);
   }, [view]);
 
 
 };
 };

+ 12 - 12
packages/presentation/package.json

@@ -46,19 +46,19 @@
     "@marp-team/marpit": "^2.6.1",
     "@marp-team/marpit": "^2.6.1",
     "@types/reveal.js": "^4.4.1",
     "@types/reveal.js": "^4.4.1",
     "eslint-plugin-regex": "^1.8.0",
     "eslint-plugin-regex": "^1.8.0",
-    "hast-util-sanitize": "^4.1.0",
-    "hast-util-select": "^5.0.5",
-    "mdast-util-frontmatter": "^1.0.0",
-    "mdast-util-gfm": "^2.0.1",
-    "mdast-util-to-markdown": "^1.3.0",
-    "react-markdown": "^8.0.7",
-    "remark-frontmatter": "^4.0.1",
-    "remark-parse": "^10.0.0",
-    "remark-stringify": "^10.0.0",
+    "hast-util-sanitize": "^5.0.1",
+    "hast-util-select": "^6.0.2",
+    "mdast-util-frontmatter": "^2.0.1",
+    "mdast-util-gfm": "^3.0.0",
+    "mdast-util-to-markdown": "^2.1.0",
+    "react-markdown": "^9.0.1",
+    "remark-frontmatter": "^5.0.0",
+    "remark-parse": "^11.0.0",
+    "remark-stringify": "^11.0.0",
     "reveal.js": "^4.4.0",
     "reveal.js": "^4.4.0",
-    "unified": "^10.1.2",
-    "unist-util-find-after": "^4.0.0",
-    "unist-util-visit": "^4.0.0"
+    "unified": "^11.0.0",
+    "unist-util-find-after": "^5.0.0",
+    "unist-util-visit": "^5.0.0"
   },
   },
   "peerDependencies": {
   "peerDependencies": {
     "next": "^14",
     "next": "^14",

+ 1 - 1
packages/presentation/src/client/components/GrowiSlides.tsx

@@ -1,5 +1,5 @@
 import Head from 'next/head';
 import Head from 'next/head';
-import { ReactMarkdown } from 'react-markdown/lib/react-markdown';
+import ReactMarkdown from 'react-markdown';
 
 
 import type { PresentationOptions } from '../consts';
 import type { PresentationOptions } from '../consts';
 import { MARP_CONTAINER_CLASS_NAME, presentationMarpit, slideMarpit } from '../services/growi-marpit';
 import { MARP_CONTAINER_CLASS_NAME, presentationMarpit, slideMarpit } from '../services/growi-marpit';

+ 4 - 4
packages/remark-attachment-refs/package.json

@@ -49,7 +49,7 @@
     "@growi/ui": "link:../ui",
     "@growi/ui": "link:../ui",
     "axios": "^0.24.0",
     "axios": "^0.24.0",
     "bunyan": "^1.8.15",
     "bunyan": "^1.8.15",
-    "hast-util-select": "^5.0.5",
+    "hast-util-select": "^6.0.2",
     "mongoose": "^6.11.3",
     "mongoose": "^6.11.3",
     "swr": "^2.0.3",
     "swr": "^2.0.3",
     "universal-bunyan": "^0.9.2"
     "universal-bunyan": "^0.9.2"
@@ -57,11 +57,11 @@
   "devDependencies": {
   "devDependencies": {
     "csstype": "^3.0.2",
     "csstype": "^3.0.2",
     "eslint-plugin-regex": "^1.8.0",
     "eslint-plugin-regex": "^1.8.0",
-    "hast-util-sanitize": "^4.1.0",
+    "hast-util-sanitize": "^5.0.1",
     "hast-util-select": "^5.0.5",
     "hast-util-select": "^5.0.5",
     "npm-run-all": "^4.1.5",
     "npm-run-all": "^4.1.5",
-    "unified": "^10.1.2",
-    "unist-util-visit": "^4.0.0"
+    "unified": "^11.0.0",
+    "unist-util-visit": "^5.0.0"
   },
   },
   "peerDependencies": {
   "peerDependencies": {
     "react": "^18.2.0",
     "react": "^18.2.0",

+ 3 - 3
packages/remark-drawio/package.json

@@ -33,11 +33,11 @@
   "dependencies": {},
   "dependencies": {},
   "devDependencies": {
   "devDependencies": {
     "eslint-plugin-regex": "^1.8.0",
     "eslint-plugin-regex": "^1.8.0",
-    "hast-util-sanitize": "^4.1.0",
+    "hast-util-sanitize": "^5.0.1",
     "pako": "^2.1.0",
     "pako": "^2.1.0",
     "throttle-debounce": "^5.0.0",
     "throttle-debounce": "^5.0.0",
-    "unified": "^10.1.2",
-    "unist-util-visit": "^4.0.0"
+    "unified": "^11.0.0",
+    "unist-util-visit": "^5.0.0"
   },
   },
   "peerDependencies": {
   "peerDependencies": {
     "react": "^18.2.0",
     "react": "^18.2.0",

+ 15 - 16
packages/remark-growi-directive/package.json

@@ -1,4 +1,3 @@
-{
   "name": "@growi/remark-growi-directive",
   "name": "@growi/remark-growi-directive",
   "version": "0.9.0",
   "version": "0.9.0",
   "description": "Remark plugin to support GROWI original directive (forked from remark-directive@2.0.1)",
   "description": "Remark plugin to support GROWI original directive (forked from remark-directive@2.0.1)",
@@ -28,31 +27,31 @@
     "lint:fix": "yarn eslint \"**/*.{cjs, js,jsx,ts,tsx}\" --fix"
     "lint:fix": "yarn eslint \"**/*.{cjs, js,jsx,ts,tsx}\" --fix"
   },
   },
   "dependencies": {
   "dependencies": {
-    "@types/mdast": "^3.0.0",
-    "@types/unist": "^2.0.0",
-    "mdast-util-to-markdown": "^1.3.0",
-    "micromark-factory-space": "^1.0.0",
-    "micromark-factory-whitespace": "^1.0.0",
-    "micromark-util-character": "^1.0.0",
-    "micromark-util-symbol": "^1.0.0",
-    "micromark-util-types": "^1.0.0",
+    "@types/mdast": "^4.0.0",
+    "@types/unist": "^3.0.0",
+    "mdast-util-to-markdown": "^2.1.0",
+    "micromark-factory-space": "^2.0.0",
+    "micromark-factory-whitespace": "^2.0.0",
+    "micromark-util-character": "^2.1.0",
+    "micromark-util-symbol": "^2.0.0",
+    "micromark-util-types": "^2.0.0",
     "parse-entities": "^4.0.0",
     "parse-entities": "^4.0.0",
     "stringify-entities": "^4.0.0",
     "stringify-entities": "^4.0.0",
-    "unified": "^10.0.0",
-    "unist-util-visit-parents": "^5.0.0",
+    "unified": "^11.0.0",
+    "unist-util-visit-parents": "^6.0.0",
     "uvu": "^0.5.0"
     "uvu": "^0.5.0"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "c8": "^7.0.0",
+    "c8": "^8.0.0",
     "html-void-elements": "^2.0.0",
     "html-void-elements": "^2.0.0",
     "is-hidden": "^2.0.0",
     "is-hidden": "^2.0.0",
-    "mdast-util-from-markdown": "^1.0.0",
-    "micromark": "^3.0.0",
-    "remark": "^14.0.0",
+    "mdast-util-from-markdown": "^2.0.1",
+    "micromark": "^4.0.0",
+    "remark": "^15.0.1",
     "rimraf": "^3.0.0",
     "rimraf": "^3.0.0",
     "to-vfile": "^7.0.0",
     "to-vfile": "^7.0.0",
     "type-coverage": "^2.0.0",
     "type-coverage": "^2.0.0",
-    "unist-util-remove-position": "^4.0.0"
+    "unist-util-remove-position": "^5.0.0"
   },
   },
   "typeCoverage": {
   "typeCoverage": {
     "atLeast": 100,
     "atLeast": 100,

+ 12 - 14
packages/remark-growi-directive/src/mdast-util-growi-directive/index.js

@@ -6,17 +6,15 @@
  * @typedef {import('mdast-util-from-markdown').Extension} FromMarkdownExtension
  * @typedef {import('mdast-util-from-markdown').Extension} FromMarkdownExtension
  * @typedef {import('mdast-util-from-markdown').CompileContext} CompileContext
  * @typedef {import('mdast-util-from-markdown').CompileContext} CompileContext
  * @typedef {import('mdast-util-from-markdown').Token} Token
  * @typedef {import('mdast-util-from-markdown').Token} Token
- * @typedef {import('mdast-util-to-markdown/lib/types.js').Handle} ToMarkdownHandle
- * @typedef {import('mdast-util-to-markdown/lib/types.js').Context} Context
- * @typedef {import('mdast-util-to-markdown/lib/types.js').Options} ToMarkdownExtension
+ * @typedef {import('mdast-util-to-markdown').Handle} ToMarkdownHandle
+ * @typedef {import('mdast-util-to-markdown').Context} Context
+ * @typedef {import('mdast-util-to-markdown').Options} ToMarkdownExtension
+ *
  * @typedef {import('./complex-types').LeafDirective} LeafDirective
  * @typedef {import('./complex-types').LeafDirective} LeafDirective
  * @typedef {import('./complex-types').TextDirective} TextDirective
  * @typedef {import('./complex-types').TextDirective} TextDirective
  * @typedef {LeafDirective|TextDirective} Directive
  * @typedef {LeafDirective|TextDirective} Directive
  */
  */
 
 
-import { checkQuote } from 'mdast-util-to-markdown/lib/util/check-quote.js';
-import { containerPhrasing } from 'mdast-util-to-markdown/lib/util/container-phrasing.js';
-import { track } from 'mdast-util-to-markdown/lib/util/track.js';
 import { parseEntities } from 'parse-entities';
 import { parseEntities } from 'parse-entities';
 import { stringifyEntitiesLight } from 'stringify-entities';
 import { stringifyEntitiesLight } from 'stringify-entities';
 
 
@@ -110,14 +108,14 @@ function exitName(token) {
 
 
 /** @type {FromMarkdownHandle} */
 /** @type {FromMarkdownHandle} */
 function enterAttributes() {
 function enterAttributes() {
-  this.setData('directiveAttributes', []);
+  this.data.directiveAttributes = [];
   this.buffer(); // Capture EOLs
   this.buffer(); // Capture EOLs
 }
 }
 
 
 /** @type {FromMarkdownHandle} */
 /** @type {FromMarkdownHandle} */
 function exitAttributeValue(token) {
 function exitAttributeValue(token) {
   const list = /** @type {Array.<[string, string]>} */ (
   const list = /** @type {Array.<[string, string]>} */ (
-    this.getData('directiveAttributes')
+    this.data.directiveAttributes
   );
   );
   list[list.length - 1][1] = parseEntities(this.sliceSerialize(token));
   list[list.length - 1][1] = parseEntities(this.sliceSerialize(token));
 }
 }
@@ -125,7 +123,7 @@ function exitAttributeValue(token) {
 /** @type {FromMarkdownHandle} */
 /** @type {FromMarkdownHandle} */
 function exitAttributeName(token) {
 function exitAttributeName(token) {
   const list = /** @type {Array.<[string, string]>} */ (
   const list = /** @type {Array.<[string, string]>} */ (
-    this.getData('directiveAttributes')
+    this.data.directiveAttributes
   );
   );
 
 
   // Attribute names in CommonMark are significantly limited, so character
   // Attribute names in CommonMark are significantly limited, so character
@@ -136,7 +134,7 @@ function exitAttributeName(token) {
 /** @type {FromMarkdownHandle} */
 /** @type {FromMarkdownHandle} */
 function exitAttributes() {
 function exitAttributes() {
   const list = /** @type {Array.<[string, string]>} */ (
   const list = /** @type {Array.<[string, string]>} */ (
-    this.getData('directiveAttributes')
+    this.data.directiveAttributes
   );
   );
   /** @type {Record.<string, string>} */
   /** @type {Record.<string, string>} */
   const cleaned = {};
   const cleaned = {};
@@ -148,7 +146,7 @@ function exitAttributes() {
     cleaned[attribute[0]] = attribute[1];
     cleaned[attribute[0]] = attribute[1];
   }
   }
 
 
-  this.setData('directiveAttributes');
+  this.data.directiveAttributes = [];
   this.resume(); // Drop EOLs
   this.resume(); // Drop EOLs
   const node = /** @type {Directive} */ (this.stack[this.stack.length - 1]);
   const node = /** @type {Directive} */ (this.stack[this.stack.length - 1]);
   node.attributes = cleaned;
   node.attributes = cleaned;
@@ -164,7 +162,7 @@ function exit(token) {
  * @param {Directive} node
  * @param {Directive} node
  */
  */
 function handleDirective(node, _, context, safeOptions) {
 function handleDirective(node, _, context, safeOptions) {
-  const tracker = track(safeOptions);
+  const tracker = context.createTracker(safeOptions);
   const sequence = fence(node);
   const sequence = fence(node);
   const exit = context.enter(node.type);
   const exit = context.enter(node.type);
   let value = tracker.move(sequence + (node.name || ''));
   let value = tracker.move(sequence + (node.name || ''));
@@ -176,7 +174,7 @@ function handleDirective(node, _, context, safeOptions) {
     const subexit = context.enter(`${node.type}Label`);
     const subexit = context.enter(`${node.type}Label`);
     value += tracker.move('[');
     value += tracker.move('[');
     value += tracker.move(
     value += tracker.move(
-      containerPhrasing(label, context, {
+      context.containerPhrasing(label, {
         ...tracker.current(),
         ...tracker.current(),
         before: value,
         before: value,
         after: ']',
         after: ']',
@@ -204,7 +202,7 @@ function peekDirective() {
  * @returns {string}
  * @returns {string}
  */
  */
 function attributes(node, context) {
 function attributes(node, context) {
-  const quote = checkQuote(context);
+  const quote = context.options.quote || '"';
   const subset = node.type === DirectiveType.Text ? [quote] : [quote, '\n', '\r'];
   const subset = node.type === DirectiveType.Text ? [quote] : [quote, '\n', '\r'];
   const attrs = node.attributes || {};
   const attrs = node.attributes || {};
   /** @type {Array.<string>} */
   /** @type {Array.<string>} */

+ 1 - 2
packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/directive-leaf.js

@@ -6,8 +6,7 @@
 
 
 import { factorySpace } from 'micromark-factory-space';
 import { factorySpace } from 'micromark-factory-space';
 import { markdownLineEnding } from 'micromark-util-character';
 import { markdownLineEnding } from 'micromark-util-character';
-import { codes } from 'micromark-util-symbol/codes.js';
-import { types } from 'micromark-util-symbol/types.js';
+import { codes, types } from 'micromark-util-symbol';
 import { ok as assert } from 'uvu/assert';
 import { ok as assert } from 'uvu/assert';
 
 
 import { factoryAttributes } from './factory-attributes.js';
 import { factoryAttributes } from './factory-attributes.js';

+ 1 - 2
packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/directive-text.js

@@ -5,8 +5,7 @@
  * @typedef {import('micromark-util-types').State} State
  * @typedef {import('micromark-util-types').State} State
  */
  */
 
 
-import { codes } from 'micromark-util-symbol/codes.js';
-import { types } from 'micromark-util-symbol/types.js';
+import { codes, types } from 'micromark-util-symbol';
 import { ok as assert } from 'uvu/assert';
 import { ok as assert } from 'uvu/assert';
 
 
 import { factoryAttributes } from './factory-attributes.js';
 import { factoryAttributes } from './factory-attributes.js';

+ 1 - 2
packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/factory-attributes.js

@@ -11,8 +11,7 @@ import {
   markdownLineEndingOrSpace,
   markdownLineEndingOrSpace,
   markdownSpace,
   markdownSpace,
 } from 'micromark-util-character';
 } from 'micromark-util-character';
-import { codes } from 'micromark-util-symbol/codes.js';
-import { types } from 'micromark-util-symbol/types.js';
+import { codes, types } from 'micromark-util-symbol';
 import { ok as assert } from 'uvu/assert';
 import { ok as assert } from 'uvu/assert';
 
 
 import { markdownLineEndingOrSpaceOrComma, factoryAttributesDevider } from '../../micromark-factory-attributes-devider/index.js';
 import { markdownLineEndingOrSpaceOrComma, factoryAttributesDevider } from '../../micromark-factory-attributes-devider/index.js';

+ 1 - 3
packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/factory-label.js

@@ -5,9 +5,7 @@
  */
  */
 
 
 import { markdownLineEnding } from 'micromark-util-character';
 import { markdownLineEnding } from 'micromark-util-character';
-import { codes } from 'micromark-util-symbol/codes.js';
-import { constants } from 'micromark-util-symbol/constants.js';
-import { types } from 'micromark-util-symbol/types.js';
+import { codes, constants, types } from 'micromark-util-symbol';
 import { ok as assert } from 'uvu/assert';
 import { ok as assert } from 'uvu/assert';
 
 
 // This is a fork of:
 // This is a fork of:

+ 1 - 1
packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/factory-name.js

@@ -5,7 +5,7 @@
  */
  */
 
 
 import { asciiAlpha, asciiAlphanumeric } from 'micromark-util-character';
 import { asciiAlpha, asciiAlphanumeric } from 'micromark-util-character';
-import { codes } from 'micromark-util-symbol/codes.js';
+import { codes } from 'micromark-util-symbol';
 
 
 /**
 /**
  * @this {TokenizeContext}
  * @this {TokenizeContext}

+ 1 - 1
packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/syntax.js

@@ -2,7 +2,7 @@
  * @typedef {import('micromark-util-types').Extension} Extension
  * @typedef {import('micromark-util-types').Extension} Extension
  */
  */
 
 
-import { codes } from 'micromark-util-symbol/codes.js';
+import { codes } from 'micromark-util-symbol';
 
 
 import { directiveLeaf } from './directive-leaf.js';
 import { directiveLeaf } from './directive-leaf.js';
 import { directiveText } from './directive-text.js';
 import { directiveText } from './directive-text.js';

+ 1 - 1
packages/remark-growi-directive/src/micromark-factory-attributes-devider/index.js

@@ -4,7 +4,7 @@
  */
  */
 import { factorySpace } from 'micromark-factory-space';
 import { factorySpace } from 'micromark-factory-space';
 import { markdownLineEnding, markdownSpace } from 'micromark-util-character';
 import { markdownLineEnding, markdownSpace } from 'micromark-util-character';
-import { codes } from 'micromark-util-symbol/codes.js';
+import { codes } from 'micromark-util-symbol';
 
 
 export function markdownLineEndingOrSpaceOrComma(code) {
 export function markdownLineEndingOrSpaceOrComma(code) {
   return code !== null && (code < codes.nul || code === codes.space || code === codes.comma);
   return code !== null && (code < codes.nul || code === codes.space || code === codes.comma);

+ 25 - 27
packages/remark-growi-directive/test/mdast-util-growi-directive.test.js

@@ -88,16 +88,16 @@ describe('markdown -> mdast', () => {
     });
     });
   });
   });
 
 
+  let tree = fromMarkdown('x $a[b *c*\nd]', {
+    extensions: [directive()],
+    mdastExtensions: [directiveFromMarkdown],
+  });
+
+  removePosition(tree, { force: true });
+
   it('should support content in a label', () => {
   it('should support content in a label', () => {
-    expect(
-      removePosition(
-        fromMarkdown('x $a[b *c*\nd]', {
-          extensions: [directive()],
-          mdastExtensions: [directiveFromMarkdown],
-        }),
-        true,
-      ),
-    ).toEqual({
+    expect(tree).toEqual(
+    {
       type: 'root',
       type: 'root',
       children: [
       children: [
         {
         {
@@ -120,16 +120,15 @@ describe('markdown -> mdast', () => {
     });
     });
   });
   });
 
 
+  tree = fromMarkdown('x $a(#b.c.d e=f g="h&amp;i&unknown;j")', {
+    extensions: [directive()],
+    mdastExtensions: [directiveFromMarkdown],
+  });
+
+  removePosition(tree, { force: true });
+
   it('should support attributes', () => {
   it('should support attributes', () => {
-    expect(
-      removePosition(
-        fromMarkdown('x $a(#b.c.d e=f g="h&amp;i&unknown;j")', {
-          extensions: [directive()],
-          mdastExtensions: [directiveFromMarkdown],
-        }),
-        true,
-      ),
-    ).toEqual({
+    expect(tree).toEqual({
       type: 'root',
       type: 'root',
       children: [
       children: [
         {
         {
@@ -150,16 +149,15 @@ describe('markdown -> mdast', () => {
     });
     });
   });
   });
 
 
+  tree = fromMarkdown('$a(b\nc="d\ne")', {
+    extensions: [directive()],
+    mdastExtensions: [directiveFromMarkdown],
+  });
+
+  removePosition(tree, { force: true });
+
   it('should support EOLs in attributes', () => {
   it('should support EOLs in attributes', () => {
-    expect(
-      removePosition(
-        fromMarkdown('$a(b\nc="d\ne")', {
-          extensions: [directive()],
-          mdastExtensions: [directiveFromMarkdown],
-        }),
-        true,
-      ),
-    ).toEqual({
+    expect(tree).toEqual({
       type: 'root',
       type: 'root',
       children: [
       children: [
         {
         {

+ 4 - 4
packages/remark-lsx/package.json

@@ -44,10 +44,10 @@
   },
   },
   "devDependencies": {
   "devDependencies": {
     "eslint-plugin-regex": "^1.8.0",
     "eslint-plugin-regex": "^1.8.0",
-    "hast-util-sanitize": "^4.1.0",
-    "hast-util-select": "^5.0.5",
-    "unified": "^10.1.2",
-    "unist-util-visit": "^4.0.0"
+    "hast-util-sanitize": "^5.0.1",
+    "hast-util-select": "^6.0.2",
+    "unified": "^11.0.0",
+    "unist-util-visit": "^5.0.0"
   },
   },
   "peerDependencies": {
   "peerDependencies": {
     "next": "^14",
     "next": "^14",

Разница между файлами не показана из-за своего большого размера
+ 454 - 297
yarn.lock


Некоторые файлы не были показаны из-за большого количества измененных файлов