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

Merge remote-tracking branch 'origin/master'

Yuki Takei 1 день назад
Родитель
Сommit
528ae048ac
25 измененных файлов с 198 добавлено и 242 удалено
  1. 2 2
      apps/app/src/client/components/Admin/G2GDataTransferExportForm.tsx
  2. 5 8
      apps/app/src/client/components/LoginForm/LoginForm.tsx
  3. 2 2
      apps/app/src/client/components/PageRenameModal/PageRenameModal.tsx
  4. 42 46
      apps/app/src/client/util/watch-rendering-and-rescroll.spec.tsx
  5. 1 1
      apps/app/src/components/utils/use-lazy-loader.ts
  6. 8 7
      apps/app/src/features/openai/server/services/client-delegator/get-client.ts
  7. 1 4
      apps/app/src/pages/admin/_shared/layout.tsx
  8. 1 3
      apps/app/src/server/routes/apiv3/page-listing.ts
  9. 3 9
      apps/app/src/server/routes/apiv3/share-links.js
  10. 16 13
      apps/app/src/server/service/file-uploader/multipart-uploader.spec.ts
  11. 10 9
      apps/app/src/server/service/search-delegator/elasticsearch-client-delegator/get-client.ts
  12. 9 10
      apps/app/src/server/util/is-simple-request.spec.ts
  13. 1 0
      apps/app/src/server/util/safe-path-utils.ts
  14. 2 3
      apps/app/src/services/renderer/recommended-whitelist.ts
  15. 3 3
      apps/app/src/states/ui/sidebar/sidebar.ts
  16. 6 17
      biome.json
  17. 1 1
      package.json
  18. 1 8
      packages/core/src/models/serializers/user-serializer.ts
  19. 9 9
      packages/core/src/utils/objectid-utils.spec.ts
  20. 6 7
      packages/core/src/utils/page-path-utils/generate-children-regexp.spec.ts
  21. 29 41
      packages/core/src/utils/page-path-utils/index.spec.ts
  22. 1 0
      packages/remark-growi-directive/src/index.js
  23. 1 1
      packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/factory-attributes.js
  24. 1 1
      packages/remark-growi-directive/src/micromark-extension-growi-directive/lib/factory-label.js
  25. 37 37
      pnpm-lock.yaml

+ 2 - 2
apps/app/src/client/components/Admin/G2GDataTransferExportForm.tsx

@@ -110,8 +110,8 @@ const WarnForGroups = ({ errors }: WarnForGroupsProps): JSX.Element => {
   return (
     <div className="alert alert-warning">
       <ul>
-        {errors.map((error, index) => {
-          return <li key={`${error.message}-${index}`}>{error.message}</li>;
+        {errors.map((error) => {
+          return <li key={error.message}>{error.message}</li>;
         })}
       </ul>
     </div>

+ 5 - 8
apps/app/src/client/components/LoginForm/LoginForm.tsx

@@ -147,10 +147,10 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
       if (errors == null || errors.length === 0) return <></>;
       return (
         <div className="alert alert-danger">
-          {errors.map((err, index) => {
+          {errors.map((err) => {
             return (
               <small
-                key={`${err.code}-${index}`}
+                key={err.code}
                 // biome-ignore lint/security/noDangerouslySetInnerHtml: rendered HTML from translations
                 dangerouslySetInnerHTML={{
                   __html: tWithOpt(err.message, err.args),
@@ -171,10 +171,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
       return (
         <ul className="alert alert-danger">
           {errors.map((err, index) => (
-            <small
-              key={`${err.message}-${index}`}
-              className={index > 0 ? 'mt-1' : ''}
-            >
+            <small key={err.message} className={index > 0 ? 'mt-1' : ''}>
               {tWithOpt(err.message, err.args)}
             </small>
           ))}
@@ -394,8 +391,8 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
 
         {registerErrors != null && registerErrors.length > 0 && (
           <p className="alert alert-danger">
-            {registerErrors.map((err, index) => (
-              <span key={`${err.message}-${index}`}>
+            {registerErrors.map((err) => (
+              <span key={err.message}>
                 {tWithOpt(err.message, err.args)}
                 <br />
               </span>

+ 2 - 2
apps/app/src/client/components/PageRenameModal/PageRenameModal.tsx

@@ -57,7 +57,7 @@ const PageRenameModalSubstance: React.FC = () => {
 
   const [errs, setErrs] = useState(null);
 
-  const [subordinatedPages, setSubordinatedPages] = useState([]);
+  const [_subordinatedPages, setSubordinatedPages] = useState([]);
   const [existingPaths, setExistingPaths] = useState<string[]>([]);
   const [isRenameRecursively, setIsRenameRecursively] = useState(true);
   const [isRenameRedirect, setIsRenameRedirect] = useState(false);
@@ -201,7 +201,7 @@ const PageRenameModalSubstance: React.FC = () => {
     };
 
     return debounce(1000, checkIsPagePathRenameable);
-  }, [isUsersHomepage]);
+  }, []);
 
   useEffect(() => {
     if (isOpened && page != null && pageNameInput !== page.data.path) {

+ 42 - 46
apps/app/src/client/util/watch-rendering-and-rescroll.spec.tsx

@@ -82,29 +82,27 @@ describe('watchRenderingAndReScroll', () => {
   });
 
   // Retry absorbs rare happy-dom MO WeakRef GC drops (see file-top note).
-  it(
-    'should detect rendering elements added after initial check via observer',
-    { retry: 3 },
-    async () => {
-      const cleanup = watchRenderingAndReScroll(container, scrollToTarget);
+  it('should detect rendering elements added after initial check via observer', {
+    retry: 3,
+  }, async () => {
+    const cleanup = watchRenderingAndReScroll(container, scrollToTarget);
 
-      vi.advanceTimersByTime(3000);
-      expect(scrollToTarget).not.toHaveBeenCalled();
+    vi.advanceTimersByTime(3000);
+    expect(scrollToTarget).not.toHaveBeenCalled();
 
-      // Add a rendering element later (within 10s timeout)
-      const renderingEl = document.createElement('div');
-      renderingEl.setAttribute(GROWI_IS_CONTENT_RENDERING_ATTR, 'true');
-      container.appendChild(renderingEl);
+    // Add a rendering element later (within 10s timeout)
+    const renderingEl = document.createElement('div');
+    renderingEl.setAttribute(GROWI_IS_CONTENT_RENDERING_ATTR, 'true');
+    container.appendChild(renderingEl);
 
-      // Flush MO so it schedules the poll timer
-      await flushMutationObservers();
+    // Flush MO so it schedules the poll timer
+    await flushMutationObservers();
 
-      await vi.advanceTimersByTimeAsync(5000);
-      expect(scrollToTarget).toHaveBeenCalledTimes(1);
+    await vi.advanceTimersByTimeAsync(5000);
+    expect(scrollToTarget).toHaveBeenCalledTimes(1);
 
-      cleanup();
-    },
-  );
+    cleanup();
+  });
 
   it('should scroll once when multiple rendering elements exist simultaneously', () => {
     const renderingEl1 = document.createElement('div');
@@ -175,34 +173,32 @@ describe('watchRenderingAndReScroll', () => {
   });
 
   // Retry absorbs rare happy-dom MO WeakRef GC drops (see file-top note).
-  it(
-    'should perform a final re-scroll when rendering completes after the first poll',
-    { retry: 3 },
-    async () => {
-      const renderingEl = document.createElement('div');
-      renderingEl.setAttribute(GROWI_IS_CONTENT_RENDERING_ATTR, 'true');
-      container.appendChild(renderingEl);
-
-      const cleanup = watchRenderingAndReScroll(container, scrollToTarget);
-
-      // First timer fires at 5s — re-scroll executes
-      vi.advanceTimersByTime(5000);
-      expect(scrollToTarget).toHaveBeenCalledTimes(1);
-
-      // Rendering completes — attribute toggled to false. MO observes the
-      // transition and triggers a final re-scroll to compensate for the
-      // trailing layout shift.
-      renderingEl.setAttribute(GROWI_IS_CONTENT_RENDERING_ATTR, 'false');
-      await flushMutationObservers();
-      expect(scrollToTarget).toHaveBeenCalledTimes(2);
-
-      // No further scrolls afterward — the MO cleared the next poll timer.
-      vi.advanceTimersByTime(10000);
-      expect(scrollToTarget).toHaveBeenCalledTimes(2);
-
-      cleanup();
-    },
-  );
+  it('should perform a final re-scroll when rendering completes after the first poll', {
+    retry: 3,
+  }, async () => {
+    const renderingEl = document.createElement('div');
+    renderingEl.setAttribute(GROWI_IS_CONTENT_RENDERING_ATTR, 'true');
+    container.appendChild(renderingEl);
+
+    const cleanup = watchRenderingAndReScroll(container, scrollToTarget);
+
+    // First timer fires at 5s — re-scroll executes
+    vi.advanceTimersByTime(5000);
+    expect(scrollToTarget).toHaveBeenCalledTimes(1);
+
+    // Rendering completes — attribute toggled to false. MO observes the
+    // transition and triggers a final re-scroll to compensate for the
+    // trailing layout shift.
+    renderingEl.setAttribute(GROWI_IS_CONTENT_RENDERING_ATTR, 'false');
+    await flushMutationObservers();
+    expect(scrollToTarget).toHaveBeenCalledTimes(2);
+
+    // No further scrolls afterward — the MO cleared the next poll timer.
+    vi.advanceTimersByTime(10000);
+    expect(scrollToTarget).toHaveBeenCalledTimes(2);
+
+    cleanup();
+  });
 
   it('should scroll exactly once when rendering completes before the first timer fires', () => {
     const renderingEl = document.createElement('div');

+ 1 - 1
apps/app/src/components/utils/use-lazy-loader.ts

@@ -63,7 +63,7 @@ export const useLazyLoader = <T extends Record<string, unknown>>(
     null,
   );
 
-  const memoizedImportFn = useCallback(importFn, []);
+  const memoizedImportFn = useCallback(importFn, [importFn]);
 
   useEffect(() => {
     if (isActive && !Component) {

+ 8 - 7
apps/app/src/features/openai/server/services/client-delegator/get-client.ts

@@ -8,13 +8,14 @@ type GetDelegatorOptions = {
 };
 
 type IsAny<T> = 'dummy' extends T & 'dummy' ? true : false;
-type Delegator<Opts extends GetDelegatorOptions> = IsAny<Opts> extends true
-  ? IOpenaiClientDelegator
-  : Opts extends { openaiServiceType: 'openai' }
-    ? OpenaiClientDelegator
-    : Opts extends { openaiServiceType: 'azure-openai' }
-      ? AzureOpenaiClientDelegator
-      : IOpenaiClientDelegator;
+type Delegator<Opts extends GetDelegatorOptions> =
+  IsAny<Opts> extends true
+    ? IOpenaiClientDelegator
+    : Opts extends { openaiServiceType: 'openai' }
+      ? OpenaiClientDelegator
+      : Opts extends { openaiServiceType: 'azure-openai' }
+        ? AzureOpenaiClientDelegator
+        : IOpenaiClientDelegator;
 
 // biome-ignore lint/suspicious/noImplicitAnyLet: ignore
 let instance;

+ 1 - 4
apps/app/src/pages/admin/_shared/layout.tsx

@@ -28,10 +28,7 @@ export function createAdminPageLayout<P extends AdminCommonProps>(
           : options.title;
       const title = useCustomTitle(rawTitle);
 
-      const factories = useMemo(
-        () => options.containerFactories ?? [],
-        [options.containerFactories],
-      );
+      const factories = useMemo(() => options.containerFactories ?? [], []);
       const containers = useUnstatedContainers(factories);
 
       return (

+ 1 - 3
apps/app/src/server/routes/apiv3/page-listing.ts

@@ -45,9 +45,7 @@ const validator = {
   ),
   pageIdsOrPathRequired: [
     // type check independent of existence check
-    query('pageIds')
-      .isArray()
-      .optional(),
+    query('pageIds').isArray().optional(),
     query('path').isString().optional(),
     // existence check
     oneOf(

+ 3 - 9
apps/app/src/server/routes/apiv3/share-links.js

@@ -111,9 +111,7 @@ module.exports = (crowi) => {
 
   validator.getShareLinks = [
     // validate the page id is MongoId
-    query('relatedPage')
-      .isMongoId()
-      .withMessage('Page Id is required'),
+    query('relatedPage').isMongoId().withMessage('Page Id is required'),
   ];
 
   /**
@@ -178,9 +176,7 @@ module.exports = (crowi) => {
 
   validator.shareLinkStatus = [
     // validate the page id is MongoId
-    body('relatedPage')
-      .isMongoId()
-      .withMessage('Page Id is required'),
+    body('relatedPage').isMongoId().withMessage('Page Id is required'),
     // validate expireation date is not empty, is not before today and is date.
     body('expiredAt')
       .if((value) => value != null)
@@ -268,9 +264,7 @@ module.exports = (crowi) => {
 
   validator.deleteShareLinks = [
     // validate the page id is MongoId
-    query('relatedPage')
-      .isMongoId()
-      .withMessage('Page Id is required'),
+    query('relatedPage').isMongoId().withMessage('Page Id is required'),
   ];
 
   /**

+ 16 - 13
apps/app/src/server/service/file-uploader/multipart-uploader.spec.ts

@@ -112,20 +112,23 @@ describe('MultipartUploader', () => {
         },
       ];
 
-      describe.each(cases)(
-        'When current status is $current and desired status is $desired',
-        ({ current, desired, errorMessage }) => {
-          beforeEach(() => {
-            uploader.setCurrentStatus(current);
-          });
+      describe.each(
+        cases,
+      )('When current status is $current and desired status is $desired', ({
+        current,
+        desired,
+        errorMessage,
+      }) => {
+        beforeEach(() => {
+          uploader.setCurrentStatus(current);
+        });
 
-          it(`should throw expected error: "${errorMessage}"`, () => {
-            expect(() => uploader.testValidateUploadStatus(desired)).toThrow(
-              errorMessage,
-            );
-          });
-        },
-      );
+        it(`should throw expected error: "${errorMessage}"`, () => {
+          expect(() => uploader.testValidateUploadStatus(desired)).toThrow(
+            errorMessage,
+          );
+        });
+      });
     });
   });
 });

+ 10 - 9
apps/app/src/server/service/search-delegator/elasticsearch-client-delegator/get-client.ts

@@ -25,15 +25,16 @@ type GetDelegatorOptions =
     };
 
 type IsAny<T> = 'dummy' extends T & 'dummy' ? true : false;
-type Delegator<Opts extends GetDelegatorOptions> = IsAny<Opts> extends true
-  ? ElasticsearchClientDelegator
-  : Opts extends { version: 7 }
-    ? ES7ClientDelegator
-    : Opts extends { version: 8 }
-      ? ES8ClientDelegator
-      : Opts extends { version: 9 }
-        ? ES9ClientDelegator
-        : ElasticsearchClientDelegator;
+type Delegator<Opts extends GetDelegatorOptions> =
+  IsAny<Opts> extends true
+    ? ElasticsearchClientDelegator
+    : Opts extends { version: 7 }
+      ? ES7ClientDelegator
+      : Opts extends { version: 8 }
+        ? ES8ClientDelegator
+        : Opts extends { version: 9 }
+          ? ES9ClientDelegator
+          : ElasticsearchClientDelegator;
 
 let instance: ElasticsearchClientDelegator | null = null;
 export const getClient = async <Opts extends GetDelegatorOptions>(

+ 9 - 10
apps/app/src/server/util/is-simple-request.spec.ts

@@ -88,16 +88,15 @@ describe('isSimpleRequest', () => {
         'X-Requested-With',
         'X-CSRF-Token',
       ];
-      it.each(unsafeHeaders)(
-        'returns false for unsafe header: %s',
-        (headerName) => {
-          const reqMock = mock<Request>({
-            method: 'POST',
-            headers: { [headerName]: 'test-value' },
-          });
-          expect(isSimpleRequest(reqMock)).toBe(false);
-        },
-      );
+      it.each(
+        unsafeHeaders,
+      )('returns false for unsafe header: %s', (headerName) => {
+        const reqMock = mock<Request>({
+          method: 'POST',
+          headers: { [headerName]: 'test-value' },
+        });
+        expect(isSimpleRequest(reqMock)).toBe(false);
+      });
       // combination
       it('returns false when safe and unsafe headers are mixed', () => {
         const reqMock = mock<Request>();

+ 1 - 0
apps/app/src/server/util/safe-path-utils.ts

@@ -1,5 +1,6 @@
 import { AllLang } from '@growi/core';
 import path from 'pathe';
+
 export { AllLang as SUPPORTED_LOCALES };
 
 /**

+ 2 - 3
apps/app/src/services/renderer/recommended-whitelist.ts

@@ -3,9 +3,8 @@ import deepmerge from 'ts-deepmerge';
 
 type Attributes = typeof defaultSchema.attributes;
 
-type ExtractPropertyDefinition<T> = T extends Record<string, (infer U)[]>
-  ? U
-  : never;
+type ExtractPropertyDefinition<T> =
+  T extends Record<string, (infer U)[]> ? U : never;
 
 type PropertyDefinition = ExtractPropertyDefinition<NonNullable<Attributes>>;
 

+ 3 - 3
apps/app/src/states/ui/sidebar/sidebar.ts

@@ -66,10 +66,10 @@ export const useCurrentProductNavWidth = () => {
 
 // Export base atoms for SSR hydration
 export {
-  preferCollapsedModeAtom,
-  isCollapsedContentsOpenedAtom,
-  currentSidebarContentsAtom,
   currentProductNavWidthAtom,
+  currentSidebarContentsAtom,
+  isCollapsedContentsOpenedAtom,
+  preferCollapsedModeAtom,
 };
 
 const sidebarModeAtom = atom((get) => {

+ 6 - 17
biome.json

@@ -1,33 +1,22 @@
 {
   "$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
+  "vcs": {
+    "enabled": true,
+    "clientKind": "git",
+    "useIgnoreFile": true
+  },
   "files": {
     "includes": [
       "**",
-      "!**/.pnpm-store",
       "!**/.terraform",
-      "!**/coverage",
-      "!**/dist",
-      "!**/.next",
-      "!**/node_modules",
-      "!**/vite.*.ts.timestamp-*",
       "!**/*.grit",
       "!**/turbo.json",
       "!**/.devcontainer",
       "!**/.stylelintrc.json",
       "!**/package.json",
-      "!**/*.vendor-styles.prebuilt.*",
-      "!.turbo",
       "!.vscode",
       "!.claude",
       "!tsconfig.base.json",
-      "!apps/app/src/styles/prebuilt",
-      "!apps/app/next-env.d.ts",
-      "!apps/app/tmp",
-      "!apps/app/config/**/*.js",
-      "!apps/app/config/**/*.d.ts",
-      "!apps/app/playwright/.auth",
-      "!apps/pdf-converter/specs",
-      "!apps/slackbot-proxy/src/public/bootstrap",
       "!packages/pdf-converter-client/src/index.ts",
       "!packages/pdf-converter-client/specs"
     ]
@@ -88,7 +77,7 @@
       "correctness": {
         "useUniqueElementIds": "warn"
       },
-      "nursery": {
+      "complexity": {
         "useMaxParams": "warn"
       }
     }

+ 1 - 1
package.json

@@ -41,7 +41,7 @@
   },
   "// comments for devDependencies": {},
   "devDependencies": {
-    "@biomejs/biome": "^2.2.6",
+    "@biomejs/biome": "^2.4.12",
     "@changesets/changelog-github": "^0.5.0",
     "@changesets/cli": "^2.27.3",
     "@faker-js/faker": "^9.0.1",

+ 1 - 8
packages/core/src/models/serializers/user-serializer.ts

@@ -13,14 +13,7 @@ export const omitInsecureAttributes = <U extends IUser>(
 ): IUserSerializedSecurely<U> => {
   const leanDoc = user instanceof Document ? user.toObject<U>() : user;
 
-  const {
-    // biome-ignore lint/correctness/noUnusedVariables: ignore
-    password,
-    // biome-ignore lint/correctness/noUnusedVariables: ignore
-    apiToken,
-    email,
-    ...rest
-  } = leanDoc;
+  const { password, apiToken, email, ...rest } = leanDoc;
 
   const secureUser: IUserSerializedSecurely<U> = rest;
 

+ 9 - 9
packages/core/src/utils/objectid-utils.spec.ts

@@ -4,16 +4,16 @@ import { isValidObjectId } from './objectid-utils';
 
 describe('isValidObjectId', () => {
   describe.concurrent.each`
-    arg                                           | expected
-    ${undefined}                                  | ${false}
-    ${null}                                       | ${false}
-    ${'geeks'}                                    | ${false}
-    ${'toptoptoptop'}                             | ${false}
-    ${'geeksfogeeks'}                             | ${false}
-    ${'594ced02ed345b2b049222c5'}                 | ${true}
-    ${new ObjectId('594ced02ed345b2b049222c5')}   | ${true}
+    arg                                         | expected
+    ${undefined}                                | ${false}
+    ${null}                                     | ${false}
+    ${'geeks'}                                  | ${false}
+    ${'toptoptoptop'}                           | ${false}
+    ${'geeksfogeeks'}                           | ${false}
+    ${'594ced02ed345b2b049222c5'}               | ${true}
+    ${new ObjectId('594ced02ed345b2b049222c5')} | ${true}
   `('should return $expected', ({ arg, expected }) => {
-    test(`when the argument is '${arg}'`, async () => {
+    test(`when the argument is '${arg}'`, () => {
       // when:
       const result = isValidObjectId(arg);
 

+ 6 - 7
packages/core/src/utils/page-path-utils/generate-children-regexp.spec.ts

@@ -60,12 +60,11 @@ describe('generateChildrenRegExp', () => {
       expect(validPath).toMatch(result);
     });
 
-    test.each(invalidPaths)(
-      'should not match invalid path: %s',
-      (invalidPath) => {
-        const result = generateChildrenRegExp(path);
-        expect(invalidPath).not.toMatch(result);
-      },
-    );
+    test.each(
+      invalidPaths,
+    )('should not match invalid path: %s', (invalidPath) => {
+      const result = generateChildrenRegExp(path);
+      expect(invalidPath).not.toMatch(result);
+    });
   });
 });

+ 29 - 41
packages/core/src/utils/page-path-utils/index.spec.ts

@@ -56,17 +56,14 @@ describe.concurrent('convertToNewAffiliationPath test', () => {
     expect(result === 'parent/child').toBe(false);
   });
 
-  test.concurrent(
-    'Parent and Child path names are switched unexpectedly',
-    () => {
-      const result = convertToNewAffiliationPath(
-        'parent/',
-        'parent4/',
-        'parent/child',
-      );
-      expect(result === 'child/parent4').toBe(false);
-    },
-  );
+  test.concurrent('Parent and Child path names are switched unexpectedly', () => {
+    const result = convertToNewAffiliationPath(
+      'parent/',
+      'parent4/',
+      'parent/child',
+    );
+    expect(result === 'child/parent4').toBe(false);
+  });
 });
 
 describe.concurrent('isCreatablePage test', () => {
@@ -149,41 +146,32 @@ describe.concurrent('isCreatablePage test', () => {
       );
     });
 
-    test.concurrent(
-      'Should omit when some paths are at duplicated area',
-      () => {
-        const paths = ['/A', '/A/A', '/A/B/A', '/B', '/B/A', '/AA'];
-        const expectedPaths = ['/A', '/B', '/AA'];
+    test.concurrent('Should omit when some paths are at duplicated area', () => {
+      const paths = ['/A', '/A/A', '/A/B/A', '/B', '/B/A', '/AA'];
+      const expectedPaths = ['/A', '/B', '/AA'];
 
-        expect(omitDuplicateAreaPathFromPaths(paths)).toStrictEqual(
-          expectedPaths,
-        );
-      },
-    );
+      expect(omitDuplicateAreaPathFromPaths(paths)).toStrictEqual(
+        expectedPaths,
+      );
+    });
 
-    test.concurrent(
-      'Should omit when some long paths are at duplicated area',
-      () => {
-        const paths = ['/A/B/C', '/A/B/C/D', '/A/B/C/D/E'];
-        const expectedPaths = ['/A/B/C'];
+    test.concurrent('Should omit when some long paths are at duplicated area', () => {
+      const paths = ['/A/B/C', '/A/B/C/D', '/A/B/C/D/E'];
+      const expectedPaths = ['/A/B/C'];
 
-        expect(omitDuplicateAreaPathFromPaths(paths)).toStrictEqual(
-          expectedPaths,
-        );
-      },
-    );
+      expect(omitDuplicateAreaPathFromPaths(paths)).toStrictEqual(
+        expectedPaths,
+      );
+    });
 
-    test.concurrent(
-      'Should omit when some long paths are at duplicated area [case insensitivity]',
-      () => {
-        const paths = ['/a/B/C', '/A/b/C/D', '/A/B/c/D/E'];
-        const expectedPaths = ['/a/B/C'];
+    test.concurrent('Should omit when some long paths are at duplicated area [case insensitivity]', () => {
+      const paths = ['/a/B/C', '/A/b/C/D', '/A/B/c/D/E'];
+      const expectedPaths = ['/a/B/C'];
 
-        expect(omitDuplicateAreaPathFromPaths(paths)).toStrictEqual(
-          expectedPaths,
-        );
-      },
-    );
+      expect(omitDuplicateAreaPathFromPaths(paths)).toStrictEqual(
+        expectedPaths,
+      );
+    });
   });
 
   describe.concurrent('Test getUsernameByPath', () => {

+ 1 - 0
packages/remark-growi-directive/src/index.js

@@ -8,4 +8,5 @@ export {
   TextGrowiPluginDirectiveData,
 } from './mdast-util-growi-directive';
 
+// biome-ignore lint/style/noDefaultExport: remark plugins are conventionally consumed as default imports
 export default remarkGrowiDirectivePlugin;

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

@@ -34,7 +34,7 @@ import {
  * @param {string} attributeValueData
  * @param {boolean} [disallowEol=false]
  */
-// biome-ignore lint/nursery/useMaxParams: This module is transplanted from micromark and we want to keep the signature same.
+// biome-ignore lint/complexity/useMaxParams: This module is transplanted from micromark and we want to keep the signature same.
 export function factoryAttributes(
   effects,
   ok,

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

@@ -22,7 +22,7 @@ import { ok as assert } from 'uvu/assert';
  * @param {string} stringType
  * @param {boolean} [disallowEol=false]
  */
-// biome-ignore lint/nursery/useMaxParams: This module is transplanted from micromark and we want to keep the signature same.
+// biome-ignore lint/complexity/useMaxParams: This module is transplanted from micromark and we want to keep the signature same.
 export function factoryLabel(
   effects,
   ok,

+ 37 - 37
pnpm-lock.yaml

@@ -22,8 +22,8 @@ importers:
   .:
     devDependencies:
       '@biomejs/biome':
-        specifier: ^2.2.6
-        version: 2.2.6
+        specifier: ^2.4.12
+        version: 2.4.12
       '@changesets/changelog-github':
         specifier: ^0.5.0
         version: 0.5.0(encoding@0.1.13)
@@ -2392,59 +2392,59 @@ packages:
     resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
     engines: {node: '>=18'}
 
-  '@biomejs/biome@2.2.6':
-    resolution: {integrity: sha512-yKTCNGhek0rL5OEW1jbLeZX8LHaM8yk7+3JRGv08my+gkpmtb5dDE+54r2ZjZx0ediFEn1pYBOJSmOdDP9xtFw==}
+  '@biomejs/biome@2.4.12':
+    resolution: {integrity: sha512-Rro7adQl3NLq/zJCIL98eElXKI8eEiBtoeu5TbXF/U3qbjuSc7Jb5rjUbeHHcquDWeSf3HnGP7XI5qGrlRk/pA==}
     engines: {node: '>=14.21.3'}
     hasBin: true
 
-  '@biomejs/cli-darwin-arm64@2.2.6':
-    resolution: {integrity: sha512-UZPmn3M45CjTYulgcrFJFZv7YmK3pTxTJDrFYlNElT2FNnkkX4fsxjExTSMeWKQYoZjvekpH5cvrYZZlWu3yfA==}
+  '@biomejs/cli-darwin-arm64@2.4.12':
+    resolution: {integrity: sha512-BnMU4Pc3ciEVteVpZ0BK33MLr7X57F5w1dwDLDn+/iy/yTrA4Q/N2yftidFtsA4vrDh0FMXDpacNV/Tl3fbmng==}
     engines: {node: '>=14.21.3'}
     cpu: [arm64]
     os: [darwin]
 
-  '@biomejs/cli-darwin-x64@2.2.6':
-    resolution: {integrity: sha512-HOUIquhHVgh/jvxyClpwlpl/oeMqntlteL89YqjuFDiZ091P0vhHccwz+8muu3nTyHWM5FQslt+4Jdcd67+xWQ==}
+  '@biomejs/cli-darwin-x64@2.4.12':
+    resolution: {integrity: sha512-x9uJ0bI1rJsWICp3VH8w/5PnAVD3A7SqzDpbrfoUQX1QyWrK5jSU4fRLo/wSgGeplCivbxBRKmt5Xq4/nWvq8A==}
     engines: {node: '>=14.21.3'}
     cpu: [x64]
     os: [darwin]
 
-  '@biomejs/cli-linux-arm64-musl@2.2.6':
-    resolution: {integrity: sha512-TjCenQq3N6g1C+5UT3jE1bIiJb5MWQvulpUngTIpFsL4StVAUXucWD0SL9MCW89Tm6awWfeXBbZBAhJwjyFbRQ==}
+  '@biomejs/cli-linux-arm64-musl@2.4.12':
+    resolution: {integrity: sha512-FhfpkAAlKL6kwvcVap0Hgp4AhZmtd3YImg0kK1jd7C/aSoh4SfsB2f++yG1rU0lr8Y5MCFJrcSkmssiL9Xnnig==}
     engines: {node: '>=14.21.3'}
     cpu: [arm64]
     os: [linux]
     libc: [musl]
 
-  '@biomejs/cli-linux-arm64@2.2.6':
-    resolution: {integrity: sha512-BpGtuMJGN+o8pQjvYsUKZ+4JEErxdSmcRD/JG3mXoWc6zrcA7OkuyGFN1mDggO0Q1n7qXxo/PcupHk8gzijt5g==}
+  '@biomejs/cli-linux-arm64@2.4.12':
+    resolution: {integrity: sha512-tOwuCuZZtKi1jVzbk/5nXmIsziOB6yqN8c9r9QM0EJYPU6DpQWf11uBOSCfFKKM4H3d9ZoarvlgMfbcuD051Pw==}
     engines: {node: '>=14.21.3'}
     cpu: [arm64]
     os: [linux]
     libc: [glibc]
 
-  '@biomejs/cli-linux-x64-musl@2.2.6':
-    resolution: {integrity: sha512-1ZcBux8zVM3JhWN2ZCPaYf0+ogxXG316uaoXJdgoPZcdK/rmRcRY7PqHdAos2ExzvjIdvhQp72UcveI98hgOog==}
+  '@biomejs/cli-linux-x64-musl@2.4.12':
+    resolution: {integrity: sha512-dwTIgZrGutzhkQCuvHynCkyW6hJxUuyZqKKO0YNfaS2GUoRO+tOvxXZqZB6SkWAOdfZTzwaw8IEdUnIkHKHoew==}
     engines: {node: '>=14.21.3'}
     cpu: [x64]
     os: [linux]
     libc: [musl]
 
-  '@biomejs/cli-linux-x64@2.2.6':
-    resolution: {integrity: sha512-1HaM/dpI/1Z68zp8ZdT6EiBq+/O/z97a2AiHMl+VAdv5/ELckFt9EvRb8hDHpk8hUMoz03gXkC7VPXOVtU7faA==}
+  '@biomejs/cli-linux-x64@2.4.12':
+    resolution: {integrity: sha512-8pFeAnLU9QdW9jCIslB/v82bI0lhBmz2ZAKc8pVMFPO0t0wAHsoEkrUQUbMkIorTRIjbqyNZHA3lEXavsPWYSw==}
     engines: {node: '>=14.21.3'}
     cpu: [x64]
     os: [linux]
     libc: [glibc]
 
-  '@biomejs/cli-win32-arm64@2.2.6':
-    resolution: {integrity: sha512-h3A88G8PGM1ryTeZyLlSdfC/gz3e95EJw9BZmA6Po412DRqwqPBa2Y9U+4ZSGUAXCsnSQE00jLV8Pyrh0d+jQw==}
+  '@biomejs/cli-win32-arm64@2.4.12':
+    resolution: {integrity: sha512-B0DLnx0vA9ya/3v7XyCaP+/lCpnbWbMOfUFFve+xb5OxyYvdHaS55YsSddr228Y+JAFk58agCuZTsqNiw2a6ig==}
     engines: {node: '>=14.21.3'}
     cpu: [arm64]
     os: [win32]
 
-  '@biomejs/cli-win32-x64@2.2.6':
-    resolution: {integrity: sha512-yx0CqeOhPjYQ5ZXgPfu8QYkgBhVJyvWe36as7jRuPrKPO5ylVDfwVtPQ+K/mooNTADW0IhxOZm3aPu16dP8yNQ==}
+  '@biomejs/cli-win32-x64@2.4.12':
+    resolution: {integrity: sha512-yMckRzTyZ83hkk8iDFWswqSdU8tvZxspJKnYNh7JZr/zhZNOlzH13k4ecboU6MurKExCe2HUkH75pGI/O2JwGA==}
     engines: {node: '>=14.21.3'}
     cpu: [x64]
     os: [win32]
@@ -15419,39 +15419,39 @@ snapshots:
 
   '@bcoe/v8-coverage@1.0.2': {}
 
-  '@biomejs/biome@2.2.6':
+  '@biomejs/biome@2.4.12':
     optionalDependencies:
-      '@biomejs/cli-darwin-arm64': 2.2.6
-      '@biomejs/cli-darwin-x64': 2.2.6
-      '@biomejs/cli-linux-arm64': 2.2.6
-      '@biomejs/cli-linux-arm64-musl': 2.2.6
-      '@biomejs/cli-linux-x64': 2.2.6
-      '@biomejs/cli-linux-x64-musl': 2.2.6
-      '@biomejs/cli-win32-arm64': 2.2.6
-      '@biomejs/cli-win32-x64': 2.2.6
+      '@biomejs/cli-darwin-arm64': 2.4.12
+      '@biomejs/cli-darwin-x64': 2.4.12
+      '@biomejs/cli-linux-arm64': 2.4.12
+      '@biomejs/cli-linux-arm64-musl': 2.4.12
+      '@biomejs/cli-linux-x64': 2.4.12
+      '@biomejs/cli-linux-x64-musl': 2.4.12
+      '@biomejs/cli-win32-arm64': 2.4.12
+      '@biomejs/cli-win32-x64': 2.4.12
 
-  '@biomejs/cli-darwin-arm64@2.2.6':
+  '@biomejs/cli-darwin-arm64@2.4.12':
     optional: true
 
-  '@biomejs/cli-darwin-x64@2.2.6':
+  '@biomejs/cli-darwin-x64@2.4.12':
     optional: true
 
-  '@biomejs/cli-linux-arm64-musl@2.2.6':
+  '@biomejs/cli-linux-arm64-musl@2.4.12':
     optional: true
 
-  '@biomejs/cli-linux-arm64@2.2.6':
+  '@biomejs/cli-linux-arm64@2.4.12':
     optional: true
 
-  '@biomejs/cli-linux-x64-musl@2.2.6':
+  '@biomejs/cli-linux-x64-musl@2.4.12':
     optional: true
 
-  '@biomejs/cli-linux-x64@2.2.6':
+  '@biomejs/cli-linux-x64@2.4.12':
     optional: true
 
-  '@biomejs/cli-win32-arm64@2.2.6':
+  '@biomejs/cli-win32-arm64@2.4.12':
     optional: true
 
-  '@biomejs/cli-win32-x64@2.2.6':
+  '@biomejs/cli-win32-x64@2.4.12':
     optional: true
 
   '@braintree/sanitize-url@7.1.0': {}