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

biome autofix remark-lsx errors

Futa Arai 10 месяцев назад
Родитель
Сommit
4092becbd6
26 измененных файлов с 561 добавлено и 412 удалено
  1. 147 120
      packages/remark-lsx/src/client/components/Lsx.tsx
  2. 12 13
      packages/remark-lsx/src/client/components/LsxPageList/LsxListView.tsx
  3. 21 14
      packages/remark-lsx/src/client/components/LsxPageList/LsxPage.tsx
  4. 9 7
      packages/remark-lsx/src/client/components/lsx-context.ts
  5. 67 44
      packages/remark-lsx/src/client/services/renderer/lsx.ts
  6. 36 17
      packages/remark-lsx/src/client/stores/lsx/lsx.ts
  7. 10 11
      packages/remark-lsx/src/client/stores/lsx/parse-num-option.spec.ts
  8. 12 5
      packages/remark-lsx/src/client/stores/lsx/parse-num-option.ts
  9. 23 17
      packages/remark-lsx/src/client/utils/page-node.spec.ts
  10. 26 10
      packages/remark-lsx/src/client/utils/page-node.ts
  11. 16 16
      packages/remark-lsx/src/interfaces/api.ts
  12. 4 4
      packages/remark-lsx/src/interfaces/page-node.ts
  13. 15 5
      packages/remark-lsx/src/server/index.ts
  14. 8 7
      packages/remark-lsx/src/server/routes/list-pages/add-depth-condition.spec.ts
  15. 13 4
      packages/remark-lsx/src/server/routes/list-pages/add-depth-condition.ts
  16. 52 51
      packages/remark-lsx/src/server/routes/list-pages/add-num-condition.spec.ts
  17. 5 3
      packages/remark-lsx/src/server/routes/list-pages/add-num-condition.ts
  18. 14 3
      packages/remark-lsx/src/server/routes/list-pages/add-sort-condition.ts
  19. 10 4
      packages/remark-lsx/src/server/routes/list-pages/generate-base-query.ts
  20. 2 4
      packages/remark-lsx/src/server/routes/list-pages/get-toppage-viewers-count.ts
  21. 20 15
      packages/remark-lsx/src/server/routes/list-pages/index.spec.ts
  22. 35 24
      packages/remark-lsx/src/server/routes/list-pages/index.ts
  23. 0 2
      packages/remark-lsx/src/utils/depth-utils.spec.ts
  24. 2 6
      packages/remark-lsx/tsconfig.json
  25. 1 3
      packages/remark-lsx/vite.server.config.ts
  26. 1 3
      packages/remark-lsx/vitest.config.ts

+ 147 - 120
packages/remark-lsx/src/client/components/Lsx.tsx

@@ -11,136 +11,161 @@ import { LsxContext } from './lsx-context';
 import styles from './Lsx.module.scss';
 import styles from './Lsx.module.scss';
 
 
 type Props = {
 type Props = {
-  children: React.ReactNode,
-  className?: string,
-
-  prefix: string,
-  num?: string,
-  depth?: string,
-  sort?: string,
-  reverse?: string,
-  filter?: string,
-  except?: string,
-
-  isImmutable?: boolean,
-  isSharedPage?: boolean,
+  children: React.ReactNode;
+  className?: string;
+
+  prefix: string;
+  num?: string;
+  depth?: string;
+  sort?: string;
+  reverse?: string;
+  filter?: string;
+  except?: string;
+
+  isImmutable?: boolean;
+  isSharedPage?: boolean;
 };
 };
 
 
-const LsxSubstance = React.memo(({
-  prefix,
-  num, depth, sort, reverse, filter, except,
-  isImmutable,
-}: Props): JSX.Element => {
-
-  const lsxContext = useMemo(() => {
-    const options = {
-      num, depth, sort, reverse, filter, except,
-    };
-    return new LsxContext(prefix, options);
-  }, [depth, filter, num, prefix, reverse, sort, except]);
-
-  const {
-    data, error, isLoading, setSize,
-  } = useSWRxLsx(lsxContext.pagePath, lsxContext.options, isImmutable);
-
-  const hasError = error != null;
-  const errorMessage = error?.message;
-
-  const Error = useCallback((): JSX.Element => {
-    if (!hasError) {
-      return <></>;
-    }
-
-    return (
-      <details>
-        <summary className="text-warning">
-          <span className="material-symbols-outlined me-1">warning</span> {lsxContext.toString()}
-        </summary>
-        <small className="ms-3 text-muted">{errorMessage}</small>
-      </details>
+const LsxSubstance = React.memo(
+  ({
+    prefix,
+    num,
+    depth,
+    sort,
+    reverse,
+    filter,
+    except,
+    isImmutable,
+  }: Props): JSX.Element => {
+    const lsxContext = useMemo(() => {
+      const options = {
+        num,
+        depth,
+        sort,
+        reverse,
+        filter,
+        except,
+      };
+      return new LsxContext(prefix, options);
+    }, [depth, filter, num, prefix, reverse, sort, except]);
+
+    const { data, error, isLoading, setSize } = useSWRxLsx(
+      lsxContext.pagePath,
+      lsxContext.options,
+      isImmutable,
     );
     );
-  }, [errorMessage, hasError, lsxContext]);
-
-  const Loading = useCallback((): JSX.Element => {
-    if (hasError) {
-      return <></>;
-    }
-    if (!isLoading) {
-      return <></>;
-    }
-
-    return (
-      <div className={`text-muted ${isLoading ? 'lsx-blink' : ''}`}>
-        <small>
-          <LoadingSpinner className="me-1" />
-          {lsxContext.toString()}
-        </small>
-      </div>
-    );
-  }, [hasError, isLoading, lsxContext]);
-
-  const contents = useMemo(() => {
-    if (data == null) {
-      return <></>;
-    }
-
-    const depthRange = lsxContext.getOptDepth();
-
-    const nodeTree = generatePageNodeTree(prefix, data.flatMap(d => d.pages), depthRange);
-    const basisViewersCount = data.at(-1)?.toppageViewersCount;
-
-    return <LsxListView nodeTree={nodeTree} lsxContext={lsxContext} basisViewersCount={basisViewersCount} />;
-  }, [data, lsxContext, prefix]);
 
 
-
-  const LoadMore = useCallback(() => {
-    const lastResult = data?.at(-1);
-
-    if (lastResult == null) {
-      return <></>;
-    }
-
-    const { cursor, total } = lastResult;
-    const leftItemsNum = total - cursor;
-
-    if (leftItemsNum === 0) {
-      return <></>;
-    }
+    const hasError = error != null;
+    const errorMessage = error?.message;
+
+    const Error = useCallback((): JSX.Element => {
+      if (!hasError) {
+        return <></>;
+      }
+
+      return (
+        <details>
+          <summary className="text-warning">
+            <span className="material-symbols-outlined me-1">warning</span>{' '}
+            {lsxContext.toString()}
+          </summary>
+          <small className="ms-3 text-muted">{errorMessage}</small>
+        </details>
+      );
+    }, [errorMessage, hasError, lsxContext]);
+
+    const Loading = useCallback((): JSX.Element => {
+      if (hasError) {
+        return <></>;
+      }
+      if (!isLoading) {
+        return <></>;
+      }
+
+      return (
+        <div className={`text-muted ${isLoading ? 'lsx-blink' : ''}`}>
+          <small>
+            <LoadingSpinner className="me-1" />
+            {lsxContext.toString()}
+          </small>
+        </div>
+      );
+    }, [hasError, isLoading, lsxContext]);
+
+    const contents = useMemo(() => {
+      if (data == null) {
+        return <></>;
+      }
+
+      const depthRange = lsxContext.getOptDepth();
+
+      const nodeTree = generatePageNodeTree(
+        prefix,
+        data.flatMap((d) => d.pages),
+        depthRange,
+      );
+      const basisViewersCount = data.at(-1)?.toppageViewersCount;
+
+      return (
+        <LsxListView
+          nodeTree={nodeTree}
+          lsxContext={lsxContext}
+          basisViewersCount={basisViewersCount}
+        />
+      );
+    }, [data, lsxContext, prefix]);
+
+    const LoadMore = useCallback(() => {
+      const lastResult = data?.at(-1);
+
+      if (lastResult == null) {
+        return <></>;
+      }
+
+      const { cursor, total } = lastResult;
+      const leftItemsNum = total - cursor;
+
+      if (leftItemsNum === 0) {
+        return <></>;
+      }
+
+      return (
+        <div className="row justify-content-center lsx-load-more-row">
+          <div className="col-12 col-sm-8 d-flex flex-column align-items-center lsx-load-more-container">
+            <button
+              type="button"
+              className="btn btn btn-outline-secondary btn-load-more"
+              onClick={() => setSize((size) => size + 1)}
+            >
+              Load more
+              <br />
+              <span className="text-muted small start-items-label">
+                {leftItemsNum} pages left
+              </span>
+            </button>
+          </div>
+        </div>
+      );
+    }, [data, setSize]);
 
 
     return (
     return (
-      <div className="row justify-content-center lsx-load-more-row">
-        <div className="col-12 col-sm-8 d-flex flex-column align-items-center lsx-load-more-container">
-          <button
-            type="button"
-            className="btn btn btn-outline-secondary btn-load-more"
-            onClick={() => setSize(size => size + 1)}
-          >
-            Load more<br />
-            <span className="text-muted small start-items-label">
-              {leftItemsNum} pages left
-            </span>
-          </button>
-        </div>
+      <div className={`lsx ${styles.lsx}`}>
+        <Error />
+        <Loading />
+        {contents}
+        <LoadMore />
       </div>
       </div>
     );
     );
-  }, [data, setSize]);
-
-
-  return (
-    <div className={`lsx ${styles.lsx}`}>
-      <Error />
-      <Loading />
-      {contents}
-      <LoadMore />
-    </div>
-  );
-});
+  },
+);
 LsxSubstance.displayName = 'LsxSubstance';
 LsxSubstance.displayName = 'LsxSubstance';
 
 
 const LsxDisabled = React.memo((): JSX.Element => {
 const LsxDisabled = React.memo((): JSX.Element => {
   return (
   return (
     <div className="text-muted">
     <div className="text-muted">
-      <span className="material-symbols-outlined fs-5 me-1" aria-hidden="true">info</span>
+      <span className="material-symbols-outlined fs-5 me-1" aria-hidden="true">
+        info
+      </span>
       <small>lsx is not available on the share link page</small>
       <small>lsx is not available on the share link page</small>
     </div>
     </div>
   );
   );
@@ -156,7 +181,9 @@ export const Lsx = React.memo((props: Props): JSX.Element => {
 });
 });
 Lsx.displayName = 'Lsx';
 Lsx.displayName = 'Lsx';
 
 
-export const LsxImmutable = React.memo((props: Omit<Props, 'isImmutable'>): JSX.Element => {
-  return <Lsx {...props} isImmutable />;
-});
+export const LsxImmutable = React.memo(
+  (props: Omit<Props, 'isImmutable'>): JSX.Element => {
+    return <Lsx {...props} isImmutable />;
+  },
+);
 LsxImmutable.displayName = 'LsxImmutable';
 LsxImmutable.displayName = 'LsxImmutable';

+ 12 - 13
packages/remark-lsx/src/client/components/LsxPageList/LsxListView.tsx

@@ -5,19 +5,15 @@ import type { LsxContext } from '../lsx-context';
 
 
 import { LsxPage } from './LsxPage';
 import { LsxPage } from './LsxPage';
 
 
-
 import styles from './LsxListView.module.scss';
 import styles from './LsxListView.module.scss';
 
 
-
 type Props = {
 type Props = {
-  nodeTree?: PageNode[],
-  lsxContext: LsxContext,
-  basisViewersCount?: number,
+  nodeTree?: PageNode[];
+  lsxContext: LsxContext;
+  basisViewersCount?: number;
 };
 };
 
 
-
 export const LsxListView = React.memo((props: Props): JSX.Element => {
 export const LsxListView = React.memo((props: Props): JSX.Element => {
-
   const { nodeTree, lsxContext, basisViewersCount } = props;
   const { nodeTree, lsxContext, basisViewersCount } = props;
 
 
   const isEmpty = nodeTree == null || nodeTree.length === 0;
   const isEmpty = nodeTree == null || nodeTree.length === 0;
@@ -27,8 +23,14 @@ export const LsxListView = React.memo((props: Props): JSX.Element => {
       return (
       return (
         <div className="text-muted">
         <div className="text-muted">
           <small>
           <small>
-            <span className="material-symbols-outlined fs-5 me-1" aria-hidden="true">info</span>
-            $lsx(<a href={lsxContext.pagePath}>{lsxContext.pagePath}</a>) has no contents
+            <span
+              className="material-symbols-outlined fs-5 me-1"
+              aria-hidden="true"
+            >
+              info
+            </span>
+            $lsx(<a href={lsxContext.pagePath}>{lsxContext.pagePath}</a>) has no
+            contents
           </small>
           </small>
         </div>
         </div>
       );
       );
@@ -49,11 +51,8 @@ export const LsxListView = React.memo((props: Props): JSX.Element => {
 
 
   return (
   return (
     <div className={`page-list ${styles['page-list']}`}>
     <div className={`page-list ${styles['page-list']}`}>
-      <ul className="page-list-ul">
-        {contents}
-      </ul>
+      <ul className="page-list-ul">{contents}</ul>
     </div>
     </div>
   );
   );
-
 });
 });
 LsxListView.displayName = 'LsxListView';
 LsxListView.displayName = 'LsxListView';

+ 21 - 14
packages/remark-lsx/src/client/components/LsxPageList/LsxPage.tsx

@@ -7,21 +7,17 @@ import Link from 'next/link';
 import type { PageNode } from '../../../interfaces/page-node';
 import type { PageNode } from '../../../interfaces/page-node';
 import type { LsxContext } from '../lsx-context';
 import type { LsxContext } from '../lsx-context';
 
 
-
 import styles from './LsxPage.module.scss';
 import styles from './LsxPage.module.scss';
 
 
-
 type Props = {
 type Props = {
-  pageNode: PageNode,
-  lsxContext: LsxContext,
-  depth: number,
-  basisViewersCount?: number,
+  pageNode: PageNode;
+  lsxContext: LsxContext;
+  depth: number;
+  basisViewersCount?: number;
 };
 };
 
 
 export const LsxPage = React.memo((props: Props): JSX.Element => {
 export const LsxPage = React.memo((props: Props): JSX.Element => {
-  const {
-    pageNode, lsxContext, depth, basisViewersCount,
-  } = props;
+  const { pageNode, lsxContext, depth, basisViewersCount } = props;
 
 
   const pageId = pageNode.page?._id;
   const pageId = pageNode.page?._id;
   const pagePath = pageNode.pagePath;
   const pagePath = pageNode.pagePath;
@@ -64,9 +60,15 @@ export const LsxPage = React.memo((props: Props): JSX.Element => {
 
 
   const iconElement: JSX.Element = useMemo(() => {
   const iconElement: JSX.Element = useMemo(() => {
     const isExists = pageId != null;
     const isExists = pageId != null;
-    return (isExists)
-      ? <span className="material-symbols-outlined fs-5 me-1" aria-hidden="true">description</span>
-      : <span className="material-symbols-outlined fs-5 me-1" aria-hidden="true">draft</span>;
+    return isExists ? (
+      <span className="material-symbols-outlined fs-5 me-1" aria-hidden="true">
+        description
+      </span>
+    ) : (
+      <span className="material-symbols-outlined fs-5 me-1" aria-hidden="true">
+        draft
+      </span>
+    );
   }, [pageId]);
   }, [pageId]);
 
 
   const pagePathElement: JSX.Element = useMemo(() => {
   const pagePathElement: JSX.Element = useMemo(() => {
@@ -78,7 +80,13 @@ export const LsxPage = React.memo((props: Props): JSX.Element => {
     }
     }
 
 
     // create PagePath element
     // create PagePath element
-    let pagePathNode = <PagePathLabel path={pagePath} isLatterOnly additionalClassNames={classNames} />;
+    let pagePathNode = (
+      <PagePathLabel
+        path={pagePath}
+        isLatterOnly
+        additionalClassNames={classNames}
+      />
+    );
     if (isLinkable) {
     if (isLinkable) {
       const href = isExists
       const href = isExists
         ? `/${pageId}`
         ? `/${pageId}`
@@ -118,6 +126,5 @@ export const LsxPage = React.memo((props: Props): JSX.Element => {
       {childrenElements}
       {childrenElements}
     </li>
     </li>
   );
   );
-
 });
 });
 LsxPage.displayName = 'LsxPage';
 LsxPage.displayName = 'LsxPage';

+ 9 - 7
packages/remark-lsx/src/client/components/lsx-context.ts

@@ -1,17 +1,20 @@
-import { OptionParser, type ParseRangeResult } from '@growi/core/dist/remark-plugins';
-
+import {
+  OptionParser,
+  type ParseRangeResult,
+} from '@growi/core/dist/remark-plugins';
 
 
 export class LsxContext {
 export class LsxContext {
-
   pagePath: string;
   pagePath: string;
 
 
-  options?: Record<string, string|undefined>;
+  options?: Record<string, string | undefined>;
 
 
-  constructor(pagePath: string, options: Record<string, string|undefined>) {
+  constructor(pagePath: string, options: Record<string, string | undefined>) {
     this.pagePath = pagePath;
     this.pagePath = pagePath;
 
 
     // remove undefined keys
     // remove undefined keys
-    Object.keys(options).forEach(key => options[key] === undefined && delete options[key]);
+    Object.keys(options).forEach(
+      (key) => options[key] === undefined && delete options[key],
+    );
 
 
     this.options = options;
     this.options = options;
   }
   }
@@ -42,5 +45,4 @@ export class LsxContext {
   toString(): string {
   toString(): string {
     return `$lsx(${this.getStringifiedAttributes()})`;
     return `$lsx(${this.getStringifiedAttributes()})`;
   }
   }
-
 }
 }

+ 67 - 44
packages/remark-lsx/src/client/services/renderer/lsx.ts

@@ -1,7 +1,14 @@
 import assert from 'assert';
 import assert from 'assert';
 
 
-import { hasHeadingSlash, removeTrailingSlash, addTrailingSlash } from '@growi/core/dist/utils/path-utils';
-import type { TextGrowiPluginDirective, LeafGrowiPluginDirective } from '@growi/remark-growi-directive';
+import {
+  addTrailingSlash,
+  hasHeadingSlash,
+  removeTrailingSlash,
+} from '@growi/core/dist/utils/path-utils';
+import type {
+  LeafGrowiPluginDirective,
+  TextGrowiPluginDirective,
+} from '@growi/remark-growi-directive';
 import { remarkGrowiDirectivePluginType } from '@growi/remark-growi-directive';
 import { remarkGrowiDirectivePluginType } from '@growi/remark-growi-directive';
 import type { Nodes as HastNode } from 'hast';
 import type { Nodes as HastNode } from 'hast';
 import type { Schema as SanitizeOption } from 'hast-util-sanitize';
 import type { Schema as SanitizeOption } from 'hast-util-sanitize';
@@ -11,54 +18,66 @@ import type { Plugin } from 'unified';
 import { visit } from 'unist-util-visit';
 import { visit } from 'unist-util-visit';
 
 
 const NODE_NAME_PATTERN = new RegExp(/ls|lsx/);
 const NODE_NAME_PATTERN = new RegExp(/ls|lsx/);
-const SUPPORTED_ATTRIBUTES = ['prefix', 'num', 'depth', 'sort', 'reverse', 'filter', 'except', 'isSharedPage'];
-
-type DirectiveAttributes = Record<string, string>
-type GrowiPluginDirective = TextGrowiPluginDirective | LeafGrowiPluginDirective
-
-export const remarkPlugin: Plugin = function() {
-  return (tree) => {
-    visit(tree, (node: GrowiPluginDirective) => {
-      if (node.type === remarkGrowiDirectivePluginType.Leaf || node.type === remarkGrowiDirectivePluginType.Text) {
-
-        if (typeof node.name !== 'string') {
-          return;
-        }
-        if (!NODE_NAME_PATTERN.test(node.name)) {
-          return;
-        }
-
-        const data = node.data ?? (node.data = {});
-        const attributes = node.attributes as DirectiveAttributes || {};
-
-        // set 'prefix' attribute if the first attribute is only value
-        // e.g.
-        //   case 1: lsx(prefix=/path..., ...)    => prefix="/path"
-        //   case 2: lsx(/path, ...)              => prefix="/path"
-        //   case 3: lsx(/foo, prefix=/bar ...)   => prefix="/bar"
-        if (attributes.prefix == null) {
-          const attrEntries = Object.entries(attributes);
-
-          if (attrEntries.length > 0) {
-            const [firstAttrKey, firstAttrValue] = attrEntries[0];
+const SUPPORTED_ATTRIBUTES = [
+  'prefix',
+  'num',
+  'depth',
+  'sort',
+  'reverse',
+  'filter',
+  'except',
+  'isSharedPage',
+];
+
+type DirectiveAttributes = Record<string, string>;
+type GrowiPluginDirective = TextGrowiPluginDirective | LeafGrowiPluginDirective;
+
+export const remarkPlugin: Plugin = () => (tree) => {
+  visit(tree, (node: GrowiPluginDirective) => {
+    if (
+      node.type === remarkGrowiDirectivePluginType.Leaf ||
+      node.type === remarkGrowiDirectivePluginType.Text
+    ) {
+      if (typeof node.name !== 'string') {
+        return;
+      }
+      if (!NODE_NAME_PATTERN.test(node.name)) {
+        return;
+      }
 
 
-            if (firstAttrValue === '' && !SUPPORTED_ATTRIBUTES.includes(firstAttrValue)) {
-              attributes.prefix = firstAttrKey;
-            }
+      const data = node.data ?? (node.data = {});
+      const attributes = (node.attributes as DirectiveAttributes) || {};
+
+      // set 'prefix' attribute if the first attribute is only value
+      // e.g.
+      //   case 1: lsx(prefix=/path..., ...)    => prefix="/path"
+      //   case 2: lsx(/path, ...)              => prefix="/path"
+      //   case 3: lsx(/foo, prefix=/bar ...)   => prefix="/bar"
+      if (attributes.prefix == null) {
+        const attrEntries = Object.entries(attributes);
+
+        if (attrEntries.length > 0) {
+          const [firstAttrKey, firstAttrValue] = attrEntries[0];
+
+          if (
+            firstAttrValue === '' &&
+            !SUPPORTED_ATTRIBUTES.includes(firstAttrValue)
+          ) {
+            attributes.prefix = firstAttrKey;
           }
           }
         }
         }
-
-        data.hName = 'lsx';
-        data.hProperties = attributes;
       }
       }
-    });
-  };
+
+      data.hName = 'lsx';
+      data.hProperties = attributes;
+    }
+  });
 };
 };
 
 
 export type LsxRehypePluginParams = {
 export type LsxRehypePluginParams = {
-  pagePath?: string,
-  isSharedPage?: boolean,
-}
+  pagePath?: string;
+  isSharedPage?: boolean;
+};
 
 
 const pathResolver = (href: string, basePath: string): string => {
 const pathResolver = (href: string, basePath: string): string => {
   // exclude absolute URL
   // exclude absolute URL
@@ -75,7 +94,11 @@ const pathResolver = (href: string, basePath: string): string => {
 };
 };
 
 
 export const rehypePlugin: Plugin<[LsxRehypePluginParams]> = (options = {}) => {
 export const rehypePlugin: Plugin<[LsxRehypePluginParams]> = (options = {}) => {
-  assert.notStrictEqual(options.pagePath, null, 'lsx rehype plugin requires \'pagePath\' option');
+  assert.notStrictEqual(
+    options.pagePath,
+    null,
+    "lsx rehype plugin requires 'pagePath' option",
+  );
 
 
   return (tree) => {
   return (tree) => {
     if (options.pagePath == null) {
     if (options.pagePath == null) {

+ 36 - 17
packages/remark-lsx/src/client/stores/lsx/lsx.ts

@@ -1,51 +1,71 @@
 import axios from 'axios';
 import axios from 'axios';
 import useSWRInfinite, { type SWRInfiniteResponse } from 'swr/infinite';
 import useSWRInfinite, { type SWRInfiniteResponse } from 'swr/infinite';
 
 
-import type { LsxApiOptions, LsxApiParams, LsxApiResponseData } from '../../../interfaces/api';
+import type {
+  LsxApiOptions,
+  LsxApiParams,
+  LsxApiResponseData,
+} from '../../../interfaces/api';
 
 
 import { type ParseNumOptionResult, parseNumOption } from './parse-num-option';
 import { type ParseNumOptionResult, parseNumOption } from './parse-num-option';
 
 
-
 const LOADMORE_PAGES_NUM = 10;
 const LOADMORE_PAGES_NUM = 10;
 
 
-
 export const useSWRxLsx = (
 export const useSWRxLsx = (
-    pagePath: string, options?: Record<string, string|undefined>, isImmutable?: boolean,
+  pagePath: string,
+  options?: Record<string, string | undefined>,
+  isImmutable?: boolean,
 ): SWRInfiniteResponse<LsxApiResponseData, Error> => {
 ): SWRInfiniteResponse<LsxApiResponseData, Error> => {
-
   return useSWRInfinite(
   return useSWRInfinite(
     // key generator
     // key generator
     (pageIndex, previousPageData) => {
     (pageIndex, previousPageData) => {
-      if (previousPageData != null && previousPageData.pages.length === 0) return null;
+      if (previousPageData != null && previousPageData.pages.length === 0)
+        return null;
 
 
       // parse num option
       // parse num option
       let initialOffsetAndLimit: ParseNumOptionResult | null = null;
       let initialOffsetAndLimit: ParseNumOptionResult | null = null;
       let parseError: Error | undefined;
       let parseError: Error | undefined;
       try {
       try {
-        initialOffsetAndLimit = options?.num != null
-          ? parseNumOption(options.num)
-          : null;
-      }
-      catch (err) {
+        initialOffsetAndLimit =
+          options?.num != null ? parseNumOption(options.num) : null;
+      } catch (err) {
         parseError = err as Error;
         parseError = err as Error;
       }
       }
 
 
       // the first loading
       // the first loading
       if (pageIndex === 0 || previousPageData == null) {
       if (pageIndex === 0 || previousPageData == null) {
-        return ['/_api/lsx', pagePath, options, initialOffsetAndLimit?.offset, initialOffsetAndLimit?.limit, parseError?.message, isImmutable];
+        return [
+          '/_api/lsx',
+          pagePath,
+          options,
+          initialOffsetAndLimit?.offset,
+          initialOffsetAndLimit?.limit,
+          parseError?.message,
+          isImmutable,
+        ];
       }
       }
 
 
       // loading more
       // loading more
-      return ['/_api/lsx', pagePath, options, previousPageData.cursor, LOADMORE_PAGES_NUM, parseError?.message, isImmutable];
+      return [
+        '/_api/lsx',
+        pagePath,
+        options,
+        previousPageData.cursor,
+        LOADMORE_PAGES_NUM,
+        parseError?.message,
+        isImmutable,
+      ];
     },
     },
 
 
     // fetcher
     // fetcher
-    async([endpoint, pagePath, options, offset, limit, parseErrorMessage]) => {
+    async ([endpoint, pagePath, options, offset, limit, parseErrorMessage]) => {
       if (parseErrorMessage != null) {
       if (parseErrorMessage != null) {
         throw new Error(parseErrorMessage);
         throw new Error(parseErrorMessage);
       }
       }
 
 
-      const apiOptions = Object.assign({}, options, { num: undefined }) as LsxApiOptions;
+      const apiOptions = Object.assign({}, options, {
+        num: undefined,
+      }) as LsxApiOptions;
       const params: LsxApiParams = {
       const params: LsxApiParams = {
         pagePath,
         pagePath,
         offset,
         offset,
@@ -55,8 +75,7 @@ export const useSWRxLsx = (
       try {
       try {
         const res = await axios.get<LsxApiResponseData>(endpoint, { params });
         const res = await axios.get<LsxApiResponseData>(endpoint, { params });
         return res.data;
         return res.data;
-      }
-      catch (err) {
+      } catch (err) {
         if (axios.isAxiosError(err)) {
         if (axios.isAxiosError(err)) {
           throw new Error(err.response?.data.message);
           throw new Error(err.response?.data.message);
         }
         }

+ 10 - 11
packages/remark-lsx/src/client/stores/lsx/parse-num-option.spec.ts

@@ -3,7 +3,6 @@ import { OptionParser } from '@growi/core/dist/remark-plugins';
 import { parseNumOption } from './parse-num-option';
 import { parseNumOption } from './parse-num-option';
 
 
 describe('addNumCondition()', () => {
 describe('addNumCondition()', () => {
-
   it('set limit with the specified number', () => {
   it('set limit with the specified number', () => {
     // setup
     // setup
     const parseRangeSpy = vi.spyOn(OptionParser, 'parseRange');
     const parseRangeSpy = vi.spyOn(OptionParser, 'parseRange');
@@ -36,7 +35,9 @@ describe('addNumCondition()', () => {
     const caller = () => parseNumOption('-1:10');
     const caller = () => parseNumOption('-1:10');
 
 
     // then
     // then
-    expect(caller).toThrowError("The specified option 'num' is { start: -1, end: 10 } : the start must be larger or equal than 1");
+    expect(caller).toThrowError(
+      "The specified option 'num' is { start: -1, end: 10 } : the start must be larger or equal than 1",
+    );
     expect(parseRangeSpy).toHaveBeenCalledWith('-1:10');
     expect(parseRangeSpy).toHaveBeenCalledWith('-1:10');
   });
   });
 
 
@@ -48,20 +49,19 @@ describe('addNumCondition()', () => {
     const caller = () => parseNumOption('3:2');
     const caller = () => parseNumOption('3:2');
 
 
     // then
     // then
-    expect(caller).toThrowError("The specified option 'num' is { start: 3, end: 2 } : the end must be larger or equal than the start");
+    expect(caller).toThrowError(
+      "The specified option 'num' is { start: 3, end: 2 } : the end must be larger or equal than the start",
+    );
     expect(parseRangeSpy).toHaveBeenCalledWith('3:2');
     expect(parseRangeSpy).toHaveBeenCalledWith('3:2');
   });
   });
-
 });
 });
 
 
-
 describe('addNumCondition() set skip and limit with the range string', () => {
 describe('addNumCondition() set skip and limit with the range string', () => {
-
   it.concurrent.each`
   it.concurrent.each`
-    optionsNum    | expected
-    ${'1:10'}     | ${{ offset: 0, limit: 10 }}
-    ${'2:2'}      | ${{ offset: 1, limit: 1 }}
-    ${'3:'}       | ${{ offset: 2, limit: -1 }}
+    optionsNum | expected
+    ${'1:10'}  | ${{ offset: 0, limit: 10 }}
+    ${'2:2'}   | ${{ offset: 1, limit: 1 }}
+    ${'3:'}    | ${{ offset: 2, limit: -1 }}
   `("'$optionsNum", ({ optionsNum, expected }) => {
   `("'$optionsNum", ({ optionsNum, expected }) => {
     // setup
     // setup
     const parseRangeSpy = vi.spyOn(OptionParser, 'parseRange');
     const parseRangeSpy = vi.spyOn(OptionParser, 'parseRange');
@@ -73,5 +73,4 @@ describe('addNumCondition() set skip and limit with the range string', () => {
     expect(parseRangeSpy).toHaveBeenCalledWith(optionsNum);
     expect(parseRangeSpy).toHaveBeenCalledWith(optionsNum);
     expect(result).toEqual(expected);
     expect(result).toEqual(expected);
   });
   });
-
 });
 });

+ 12 - 5
packages/remark-lsx/src/client/stores/lsx/parse-num-option.ts

@@ -1,12 +1,15 @@
 import { OptionParser } from '@growi/core/dist/remark-plugins';
 import { OptionParser } from '@growi/core/dist/remark-plugins';
 
 
-export type ParseNumOptionResult = { offset: number, limit?: number } | { offset?: number, limit: number };
+export type ParseNumOptionResult =
+  | { offset: number; limit?: number }
+  | { offset?: number; limit: number };
 
 
 /**
 /**
  * add num condition that limit fetched pages
  * add num condition that limit fetched pages
  */
  */
-export const parseNumOption = (optionsNum: string): ParseNumOptionResult | null => {
-
+export const parseNumOption = (
+  optionsNum: string,
+): ParseNumOptionResult | null => {
   if (Number.isInteger(Number(optionsNum))) {
   if (Number.isInteger(Number(optionsNum))) {
     return { limit: Number(optionsNum) };
     return { limit: Number(optionsNum) };
   }
   }
@@ -22,11 +25,15 @@ export const parseNumOption = (optionsNum: string): ParseNumOptionResult | null
 
 
   // check start
   // check start
   if (start < 1) {
   if (start < 1) {
-    throw new Error(`The specified option 'num' is { start: ${start}, end: ${end} } : the start must be larger or equal than 1`);
+    throw new Error(
+      `The specified option 'num' is { start: ${start}, end: ${end} } : the start must be larger or equal than 1`,
+    );
   }
   }
   // check end
   // check end
   if (start > end && end > 0) {
   if (start > end && end > 0) {
-    throw new Error(`The specified option 'num' is { start: ${start}, end: ${end} } : the end must be larger or equal than the start`);
+    throw new Error(
+      `The specified option 'num' is { start: ${start}, end: ${end} } : the end must be larger or equal than the start`,
+    );
   }
   }
 
 
   const offset = start - 1;
   const offset = start - 1;

+ 23 - 17
packages/remark-lsx/src/client/utils/page-node.spec.ts

@@ -6,29 +6,28 @@ import type { PageNode } from '../../interfaces/page-node';
 
 
 import { generatePageNodeTree } from './page-node';
 import { generatePageNodeTree } from './page-node';
 
 
-
 function omitPageData(pageNode: PageNode): Omit<PageNode, 'page'> {
 function omitPageData(pageNode: PageNode): Omit<PageNode, 'page'> {
   const obj = Object.assign({}, pageNode);
   const obj = Object.assign({}, pageNode);
   delete obj.page;
   delete obj.page;
 
 
   // omit data in children
   // omit data in children
-  obj.children = obj.children.map(child => omitPageData(child));
+  obj.children = obj.children.map((child) => omitPageData(child));
 
 
   return obj;
   return obj;
 }
 }
 
 
 describe('generatePageNodeTree()', () => {
 describe('generatePageNodeTree()', () => {
-
   it("returns when the rootPagePath is '/'", () => {
   it("returns when the rootPagePath is '/'", () => {
     // setup
     // setup
-    const pages: IPageHasId[] = [
-      '/',
-      '/Sandbox',
-    ].map(path => mock<IPageHasId>({ path }));
+    const pages: IPageHasId[] = ['/', '/Sandbox'].map((path) =>
+      mock<IPageHasId>({ path }),
+    );
 
 
     // when
     // when
     const result = generatePageNodeTree('/', pages);
     const result = generatePageNodeTree('/', pages);
-    const resultWithoutPageData = result.map(pageNode => omitPageData(pageNode));
+    const resultWithoutPageData = result.map((pageNode) =>
+      omitPageData(pageNode),
+    );
 
 
     // then
     // then
     expect(resultWithoutPageData).toStrictEqual([
     expect(resultWithoutPageData).toStrictEqual([
@@ -47,11 +46,13 @@ describe('generatePageNodeTree()', () => {
       '/Sandbox/level2/level3-1',
       '/Sandbox/level2/level3-1',
       '/Sandbox/level2/level3-2',
       '/Sandbox/level2/level3-2',
       '/Sandbox/level2/level3-3',
       '/Sandbox/level2/level3-3',
-    ].map(path => mock<IPageHasId>({ path }));
+    ].map((path) => mock<IPageHasId>({ path }));
 
 
     // when
     // when
     const result = generatePageNodeTree('/Sandbox', pages);
     const result = generatePageNodeTree('/Sandbox', pages);
-    const resultWithoutPageData = result.map(pageNode => omitPageData(pageNode));
+    const resultWithoutPageData = result.map((pageNode) =>
+      omitPageData(pageNode),
+    );
 
 
     // then
     // then
     expect(resultWithoutPageData).toStrictEqual([
     expect(resultWithoutPageData).toStrictEqual([
@@ -83,11 +84,13 @@ describe('generatePageNodeTree()', () => {
       '/user/bar',
       '/user/bar',
       '/user/bar/memo/2023/06/01',
       '/user/bar/memo/2023/06/01',
       '/user/bar/memo/2023/06/02/memo-test',
       '/user/bar/memo/2023/06/02/memo-test',
-    ].map(path => mock<IPageHasId>({ path }));
+    ].map((path) => mock<IPageHasId>({ path }));
 
 
     // when
     // when
     const result = generatePageNodeTree('/', pages);
     const result = generatePageNodeTree('/', pages);
-    const resultWithoutPageData = result.map(pageNode => omitPageData(pageNode));
+    const resultWithoutPageData = result.map((pageNode) =>
+      omitPageData(pageNode),
+    );
 
 
     // then
     // then
     expect(resultWithoutPageData).toStrictEqual([
     expect(resultWithoutPageData).toStrictEqual([
@@ -145,12 +148,14 @@ describe('generatePageNodeTree()', () => {
       '/user',
       '/user',
       '/user/foo',
       '/user/foo',
       '/user/bar',
       '/user/bar',
-    ].map(path => mock<IPageHasId>({ path }));
+    ].map((path) => mock<IPageHasId>({ path }));
 
 
     // when
     // when
     const depthRange = OptionParser.parseRange('1:2');
     const depthRange = OptionParser.parseRange('1:2');
     const result = generatePageNodeTree('/', pages, depthRange);
     const result = generatePageNodeTree('/', pages, depthRange);
-    const resultWithoutPageData = result.map(pageNode => omitPageData(pageNode));
+    const resultWithoutPageData = result.map((pageNode) =>
+      omitPageData(pageNode),
+    );
 
 
     // then
     // then
     expect(resultWithoutPageData).toStrictEqual([
     expect(resultWithoutPageData).toStrictEqual([
@@ -190,12 +195,14 @@ describe('generatePageNodeTree()', () => {
       '/foo/level2',
       '/foo/level2',
       '/foo/level2/level3-1',
       '/foo/level2/level3-1',
       '/foo/level2/level3-2',
       '/foo/level2/level3-2',
-    ].map(path => mock<IPageHasId>({ path }));
+    ].map((path) => mock<IPageHasId>({ path }));
 
 
     // when
     // when
     const depthRange = OptionParser.parseRange('2:3');
     const depthRange = OptionParser.parseRange('2:3');
     const result = generatePageNodeTree('/', pages, depthRange);
     const result = generatePageNodeTree('/', pages, depthRange);
-    const resultWithoutPageData = result.map(pageNode => omitPageData(pageNode));
+    const resultWithoutPageData = result.map((pageNode) =>
+      omitPageData(pageNode),
+    );
 
 
     // then
     // then
     expect(resultWithoutPageData).toStrictEqual([
     expect(resultWithoutPageData).toStrictEqual([
@@ -214,5 +221,4 @@ describe('generatePageNodeTree()', () => {
       },
       },
     ]);
     ]);
   });
   });
-
 });
 });

+ 26 - 10
packages/remark-lsx/src/client/utils/page-node.ts

@@ -7,7 +7,6 @@ import { removeTrailingSlash } from '@growi/core/dist/utils/path-utils';
 import type { PageNode } from '../../interfaces/page-node';
 import type { PageNode } from '../../interfaces/page-node';
 import { getDepthOfPath } from '../../utils/depth-utils';
 import { getDepthOfPath } from '../../utils/depth-utils';
 
 
-
 function getParentPath(path: string) {
 function getParentPath(path: string) {
   return removeTrailingSlash(decodeURIComponent(url.resolve(path, './')));
   return removeTrailingSlash(decodeURIComponent(url.resolve(path, './')));
 }
 }
@@ -22,15 +21,18 @@ function getParentPath(path: string) {
  * @memberof Lsx
  * @memberof Lsx
  */
  */
 function generatePageNode(
 function generatePageNode(
-    pathToNodeMap: Record<string, PageNode>, rootPagePath: string, pagePath: string, depthRange?: ParseRangeResult | null,
+  pathToNodeMap: Record<string, PageNode>,
+  rootPagePath: string,
+  pagePath: string,
+  depthRange?: ParseRangeResult | null,
 ): PageNode | null {
 ): PageNode | null {
-
   // exclude rootPagePath itself
   // exclude rootPagePath itself
   if (pagePath === rootPagePath) {
   if (pagePath === rootPagePath) {
     return null;
     return null;
   }
   }
 
 
-  const depthStartToProcess = getDepthOfPath(rootPagePath) + (depthRange?.start ?? 0); // at least 1
+  const depthStartToProcess =
+    getDepthOfPath(rootPagePath) + (depthRange?.start ?? 0); // at least 1
   const currentPageDepth = getDepthOfPath(pagePath);
   const currentPageDepth = getDepthOfPath(pagePath);
 
 
   // return by the depth restriction
   // return by the depth restriction
@@ -49,11 +51,16 @@ function generatePageNode(
   pathToNodeMap[pagePath] = node;
   pathToNodeMap[pagePath] = node;
 
 
   /*
   /*
-    * process recursively for ancestors
-    */
+   * process recursively for ancestors
+   */
   // get or create parent node
   // get or create parent node
   const parentPath = getParentPath(pagePath);
   const parentPath = getParentPath(pagePath);
-  const parentNode = generatePageNode(pathToNodeMap, rootPagePath, parentPath, depthRange);
+  const parentNode = generatePageNode(
+    pathToNodeMap,
+    rootPagePath,
+    parentPath,
+    depthRange,
+  );
   // associate to patent
   // associate to patent
   if (parentNode != null) {
   if (parentNode != null) {
     parentNode.children.push(node);
     parentNode.children.push(node);
@@ -62,11 +69,20 @@ function generatePageNode(
   return node;
   return node;
 }
 }
 
 
-export function generatePageNodeTree(rootPagePath: string, pages: IPageHasId[], depthRange?: ParseRangeResult | null): PageNode[] {
+export function generatePageNodeTree(
+  rootPagePath: string,
+  pages: IPageHasId[],
+  depthRange?: ParseRangeResult | null,
+): PageNode[] {
   const pathToNodeMap: Record<string, PageNode> = {};
   const pathToNodeMap: Record<string, PageNode> = {};
 
 
   pages.forEach((page) => {
   pages.forEach((page) => {
-    const node = generatePageNode(pathToNodeMap, rootPagePath, page.path, depthRange); // this will not be null
+    const node = generatePageNode(
+      pathToNodeMap,
+      rootPagePath,
+      page.path,
+      depthRange,
+    ); // this will not be null
 
 
     // exclude rootPagePath itself
     // exclude rootPagePath itself
     if (node == null) {
     if (node == null) {
@@ -83,7 +99,7 @@ export function generatePageNodeTree(rootPagePath: string, pages: IPageHasId[],
     const parentPath = getParentPath(pagePath);
     const parentPath = getParentPath(pagePath);
 
 
     // pick up what parent doesn't exist
     // pick up what parent doesn't exist
-    if ((parentPath === '/') || !(parentPath in pathToNodeMap)) {
+    if (parentPath === '/' || !(parentPath in pathToNodeMap)) {
       rootNodes.push(pathToNodeMap[pagePath]);
       rootNodes.push(pathToNodeMap[pagePath]);
     }
     }
   });
   });

+ 16 - 16
packages/remark-lsx/src/interfaces/api.ts

@@ -1,23 +1,23 @@
 import type { IPageHasId } from '@growi/core';
 import type { IPageHasId } from '@growi/core';
 
 
 export type LsxApiOptions = {
 export type LsxApiOptions = {
-  depth?: string,
-  filter?: string,
-  except?: string,
-  sort?: string,
-  reverse?: string,
-}
+  depth?: string;
+  filter?: string;
+  except?: string;
+  sort?: string;
+  reverse?: string;
+};
 
 
 export type LsxApiParams = {
 export type LsxApiParams = {
-  pagePath: string,
-  offset?: number,
-  limit?: number,
-  options?: LsxApiOptions,
-}
+  pagePath: string;
+  offset?: number;
+  limit?: number;
+  options?: LsxApiOptions;
+};
 
 
 export type LsxApiResponseData = {
 export type LsxApiResponseData = {
-  pages: IPageHasId[],
-  cursor: number,
-  total: number,
-  toppageViewersCount: number,
-}
+  pages: IPageHasId[];
+  cursor: number;
+  total: number;
+  toppageViewersCount: number;
+};

+ 4 - 4
packages/remark-lsx/src/interfaces/page-node.ts

@@ -1,7 +1,7 @@
 import type { IPageHasId } from '@growi/core';
 import type { IPageHasId } from '@growi/core';
 
 
 export type PageNode = {
 export type PageNode = {
-  pagePath: string,
-  children: PageNode[],
-  page?: IPageHasId,
-}
+  pagePath: string;
+  children: PageNode[];
+  page?: IPageHasId;
+};

+ 15 - 5
packages/remark-lsx/src/server/index.ts

@@ -27,8 +27,7 @@ const lsxValidator = [
         });
         });
 
 
         return jsonData;
         return jsonData;
-      }
-      catch (err) {
+      } catch (err) {
         throw new Error('Invalid JSON format in options');
         throw new Error('Invalid JSON format in options');
       }
       }
     }),
     }),
@@ -46,15 +45,26 @@ const paramValidator = (req: Request, res: Response, next: NextFunction) => {
     return new Error(`Invalid lsx parameter: ${err.param}: ${err.msg}`);
     return new Error(`Invalid lsx parameter: ${err.param}: ${err.msg}`);
   });
   });
 
 
-  res.status(400).json({ errors: errs.map(err => err.message) });
+  res.status(400).json({ errors: errs.map((err) => err.message) });
 };
 };
 
 
 // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
 // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
 const middleware = (crowi: any, app: any): void => {
 const middleware = (crowi: any, app: any): void => {
-  const loginRequired = crowi.require('../middlewares/login-required')(crowi, true, loginRequiredFallback);
+  const loginRequired = crowi.require('../middlewares/login-required')(
+    crowi,
+    true,
+    loginRequiredFallback,
+  );
   const accessTokenParser = crowi.accessTokenParser;
   const accessTokenParser = crowi.accessTokenParser;
 
 
-  app.get('/_api/lsx', accessTokenParser, loginRequired, lsxValidator, paramValidator, listPages);
+  app.get(
+    '/_api/lsx',
+    accessTokenParser,
+    loginRequired,
+    lsxValidator,
+    paramValidator,
+    listPages,
+  );
 };
 };
 
 
 export default middleware;
 export default middleware;

+ 8 - 7
packages/remark-lsx/src/server/routes/list-pages/add-depth-condition.spec.ts

@@ -4,7 +4,6 @@ import { mock } from 'vitest-mock-extended';
 import { addDepthCondition } from './add-depth-condition';
 import { addDepthCondition } from './add-depth-condition';
 import type { PageQuery } from './generate-base-query';
 import type { PageQuery } from './generate-base-query';
 
 
-
 // mocking modules
 // mocking modules
 const mocks = vi.hoisted(() => {
 const mocks = vi.hoisted(() => {
   return {
   return {
@@ -12,11 +11,11 @@ const mocks = vi.hoisted(() => {
   };
   };
 });
 });
 
 
-vi.mock('../../../utils/depth-utils', () => ({ getDepthOfPath: mocks.getDepthOfPathMock }));
-
+vi.mock('../../../utils/depth-utils', () => ({
+  getDepthOfPath: mocks.getDepthOfPathMock,
+}));
 
 
 describe('addDepthCondition()', () => {
 describe('addDepthCondition()', () => {
-
   it('returns query as-is', () => {
   it('returns query as-is', () => {
     // setup
     // setup
     const query = mock<PageQuery>();
     const query = mock<PageQuery>();
@@ -29,7 +28,6 @@ describe('addDepthCondition()', () => {
   });
   });
 
 
   describe('throws http-errors instance', () => {
   describe('throws http-errors instance', () => {
-
     it('when the start is smaller than 1', () => {
     it('when the start is smaller than 1', () => {
       // setup
       // setup
       const query = mock<PageQuery>();
       const query = mock<PageQuery>();
@@ -41,9 +39,12 @@ describe('addDepthCondition()', () => {
       const caller = () => addDepthCondition(query, '/', depthRange);
       const caller = () => addDepthCondition(query, '/', depthRange);
 
 
       // then
       // then
-      expect(caller).toThrowError(new Error("The specified option 'depth' is { start: -1, end: 10 } : the start must be larger or equal than 1"));
+      expect(caller).toThrowError(
+        new Error(
+          "The specified option 'depth' is { start: -1, end: 10 } : the start must be larger or equal than 1",
+        ),
+      );
       expect(mocks.getDepthOfPathMock).not.toHaveBeenCalled();
       expect(mocks.getDepthOfPathMock).not.toHaveBeenCalled();
     });
     });
-
   });
   });
 });
 });

+ 13 - 4
packages/remark-lsx/src/server/routes/list-pages/add-depth-condition.ts

@@ -5,8 +5,11 @@ import { getDepthOfPath } from '../../../utils/depth-utils';
 
 
 import type { PageQuery } from './generate-base-query';
 import type { PageQuery } from './generate-base-query';
 
 
-export const addDepthCondition = (query: PageQuery, pagePath: string, depthRange: ParseRangeResult | null): PageQuery => {
-
+export const addDepthCondition = (
+  query: PageQuery,
+  pagePath: string,
+  depthRange: ParseRangeResult | null,
+): PageQuery => {
   if (depthRange == null) {
   if (depthRange == null) {
     return query;
     return query;
   }
   }
@@ -15,11 +18,17 @@ export const addDepthCondition = (query: PageQuery, pagePath: string, depthRange
 
 
   // check start
   // check start
   if (start < 1) {
   if (start < 1) {
-    throw createError(400, `The specified option 'depth' is { start: ${start}, end: ${end} } : the start must be larger or equal than 1`);
+    throw createError(
+      400,
+      `The specified option 'depth' is { start: ${start}, end: ${end} } : the start must be larger or equal than 1`,
+    );
   }
   }
   // check end
   // check end
   if (start > end && end > 0) {
   if (start > end && end > 0) {
-    throw createError(400, `The specified option 'depth' is { start: ${start}, end: ${end} } : the end must be larger or equal than the start`);
+    throw createError(
+      400,
+      `The specified option 'depth' is { start: ${start}, end: ${end} } : the end must be larger or equal than the start`,
+    );
   }
   }
 
 
   const depthOfPath = getDepthOfPath(pagePath);
   const depthOfPath = getDepthOfPath(pagePath);

+ 52 - 51
packages/remark-lsx/src/server/routes/list-pages/add-num-condition.spec.ts

@@ -5,9 +5,7 @@ import { addNumCondition } from './add-num-condition';
 import type { PageQuery } from './generate-base-query';
 import type { PageQuery } from './generate-base-query';
 
 
 describe('addNumCondition() throws 400 http-errors instance', () => {
 describe('addNumCondition() throws 400 http-errors instance', () => {
-
   it("when the param 'offset' is a negative value", () => {
   it("when the param 'offset' is a negative value", () => {
-
     // setup
     // setup
     const queryMock = mock<PageQuery>();
     const queryMock = mock<PageQuery>();
 
 
@@ -15,64 +13,67 @@ describe('addNumCondition() throws 400 http-errors instance', () => {
     const caller = () => addNumCondition(queryMock, -1, 10);
     const caller = () => addNumCondition(queryMock, -1, 10);
 
 
     // then
     // then
-    expect(caller).toThrowError(createError(400, "The param 'offset' must be larger or equal than 0"));
+    expect(caller).toThrowError(
+      createError(400, "The param 'offset' must be larger or equal than 0"),
+    );
     expect(queryMock.skip).not.toHaveBeenCalledWith();
     expect(queryMock.skip).not.toHaveBeenCalledWith();
     expect(queryMock.limit).not.toHaveBeenCalledWith();
     expect(queryMock.limit).not.toHaveBeenCalledWith();
   });
   });
 });
 });
 
 
-
 describe('addNumCondition() set skip and limit with', () => {
 describe('addNumCondition() set skip and limit with', () => {
-
   it.concurrent.each`
   it.concurrent.each`
-    offset        | limit           | expectedSkip   | expectedLimit
-    ${1}          | ${-1}           | ${1}           | ${null}
-    ${0}          | ${0}            | ${null}        | ${0}
-    ${0}          | ${10}           | ${null}        | ${10}
-    ${NaN}        | ${NaN}          | ${null}        | ${null}
-    ${undefined}  | ${undefined}    | ${null}        | ${50}
-  `("{ offset: $offset, limit: $limit }'", ({
-    offset, limit, expectedSkip, expectedLimit,
-  }) => {
-    // setup
-    const queryMock = mock<PageQuery>();
+    offset        | limit         | expectedSkip | expectedLimit
+    ${1}          | ${-1}         | ${1}         | ${null}
+    ${0}          | ${0}          | ${null}      | ${0}
+    ${0}          | ${10}         | ${null}      | ${10}
+    ${Number.NaN} | ${Number.NaN} | ${null}      | ${null}
+    ${undefined}  | ${undefined}  | ${null}      | ${50}
+  `(
+    "{ offset: $offset, limit: $limit }'",
+    ({ offset, limit, expectedSkip, expectedLimit }) => {
+      // setup
+      const queryMock = mock<PageQuery>();
 
 
-    // result for q.skip()
-    const querySkipResultMock = mock<PageQuery>();
-    queryMock.skip.calledWith(expectedSkip).mockImplementation(() => querySkipResultMock);
-    // result for q.limit()
-    const queryLimitResultMock = mock<PageQuery>();
-    queryMock.limit.calledWith(expectedLimit).mockImplementation(() => queryLimitResultMock);
-    // result for q.skil().limit()
-    const querySkipAndLimitResultMock = mock<PageQuery>();
-    querySkipResultMock.limit.calledWith(expectedLimit).mockImplementation(() => querySkipAndLimitResultMock);
+      // result for q.skip()
+      const querySkipResultMock = mock<PageQuery>();
+      queryMock.skip
+        .calledWith(expectedSkip)
+        .mockImplementation(() => querySkipResultMock);
+      // result for q.limit()
+      const queryLimitResultMock = mock<PageQuery>();
+      queryMock.limit
+        .calledWith(expectedLimit)
+        .mockImplementation(() => queryLimitResultMock);
+      // result for q.skil().limit()
+      const querySkipAndLimitResultMock = mock<PageQuery>();
+      querySkipResultMock.limit
+        .calledWith(expectedLimit)
+        .mockImplementation(() => querySkipAndLimitResultMock);
 
 
-    // when
-    const result = addNumCondition(queryMock, offset, limit);
+      // when
+      const result = addNumCondition(queryMock, offset, limit);
 
 
-    // then
-    if (expectedSkip != null) {
-      expect(queryMock.skip).toHaveBeenCalledWith(expectedSkip);
-      if (expectedLimit != null) {
-        expect(querySkipResultMock.limit).toHaveBeenCalledWith(expectedLimit);
-        expect(result).toEqual(querySkipAndLimitResultMock); // q.skip().limit()
-      }
-      else {
-        expect(querySkipResultMock.limit).not.toHaveBeenCalled();
-        expect(result).toEqual(querySkipResultMock); // q.skil()
-      }
-    }
-    else {
-      expect(queryMock.skip).not.toHaveBeenCalled();
-      if (expectedLimit != null) {
-        expect(queryMock.limit).toHaveBeenCalledWith(expectedLimit);
-        expect(result).toEqual(queryLimitResultMock); // q.limit()
+      // then
+      if (expectedSkip != null) {
+        expect(queryMock.skip).toHaveBeenCalledWith(expectedSkip);
+        if (expectedLimit != null) {
+          expect(querySkipResultMock.limit).toHaveBeenCalledWith(expectedLimit);
+          expect(result).toEqual(querySkipAndLimitResultMock); // q.skip().limit()
+        } else {
+          expect(querySkipResultMock.limit).not.toHaveBeenCalled();
+          expect(result).toEqual(querySkipResultMock); // q.skil()
+        }
+      } else {
+        expect(queryMock.skip).not.toHaveBeenCalled();
+        if (expectedLimit != null) {
+          expect(queryMock.limit).toHaveBeenCalledWith(expectedLimit);
+          expect(result).toEqual(queryLimitResultMock); // q.limit()
+        } else {
+          expect(queryMock.limit).not.toHaveBeenCalled();
+          expect(result).toEqual(queryMock); // as-is
+        }
       }
       }
-      else {
-        expect(queryMock.limit).not.toHaveBeenCalled();
-        expect(result).toEqual(queryMock); // as-is
-      }
-    }
-  });
-
+    },
+  );
 });
 });

+ 5 - 3
packages/remark-lsx/src/server/routes/list-pages/add-num-condition.ts

@@ -2,14 +2,16 @@ import createError from 'http-errors';
 
 
 import type { PageQuery } from './generate-base-query';
 import type { PageQuery } from './generate-base-query';
 
 
-
 const DEFAULT_PAGES_NUM = 50;
 const DEFAULT_PAGES_NUM = 50;
 
 
 /**
 /**
  * add num condition that limit fetched pages
  * add num condition that limit fetched pages
  */
  */
-export const addNumCondition = (query: PageQuery, offset = 0, limit = DEFAULT_PAGES_NUM): PageQuery => {
-
+export const addNumCondition = (
+  query: PageQuery,
+  offset = 0,
+  limit = DEFAULT_PAGES_NUM,
+): PageQuery => {
   // check offset
   // check offset
   if (offset < 0) {
   if (offset < 0) {
     throw createError(400, "The param 'offset' must be larger or equal than 0");
     throw createError(400, "The param 'offset' must be larger or equal than 0");

+ 14 - 3
packages/remark-lsx/src/server/routes/list-pages/add-sort-condition.ts

@@ -9,15 +9,26 @@ import type { PageQuery } from './generate-base-query';
  * If only the sort key is specified, the sort order is the ascending order.
  * If only the sort key is specified, the sort order is the ascending order.
  *
  *
  */
  */
-export const addSortCondition = (query: PageQuery, optionsSortArg?: string, optionsReverse?: string): PageQuery => {
+export const addSortCondition = (
+  query: PageQuery,
+  optionsSortArg?: string,
+  optionsReverse?: string,
+): PageQuery => {
   // init sort key
   // init sort key
   const optionsSort = optionsSortArg ?? 'path';
   const optionsSort = optionsSortArg ?? 'path';
 
 
   // the default sort order
   // the default sort order
   const isReversed = optionsReverse === 'true';
   const isReversed = optionsReverse === 'true';
 
 
-  if (optionsSort !== 'path' && optionsSort !== 'createdAt' && optionsSort !== 'updatedAt') {
-    throw createError(400, `The specified value '${optionsSort}' for the sort option is invalid. It must be 'path', 'createdAt' or 'updatedAt'.`);
+  if (
+    optionsSort !== 'path' &&
+    optionsSort !== 'createdAt' &&
+    optionsSort !== 'updatedAt'
+  ) {
+    throw createError(
+      400,
+      `The specified value '${optionsSort}' for the sort option is invalid. It must be 'path', 'createdAt' or 'updatedAt'.`,
+    );
   }
   }
 
 
   const sortOption = {};
   const sortOption = {};

+ 10 - 4
packages/remark-lsx/src/server/routes/list-pages/generate-base-query.ts

@@ -5,12 +5,18 @@ import type { Document, Query } from 'mongoose';
 export type PageQuery = Query<IPageHasId[], Document>;
 export type PageQuery = Query<IPageHasId[], Document>;
 
 
 export type PageQueryBuilder = {
 export type PageQueryBuilder = {
-  query: PageQuery,
-  addConditionToListOnlyDescendants: (pagePath: string) => PageQueryBuilder,
-  addConditionToFilteringByViewerForList: (builder: PageQueryBuilder, user: IUser) => PageQueryBuilder,
+  query: PageQuery;
+  addConditionToListOnlyDescendants: (pagePath: string) => PageQueryBuilder;
+  addConditionToFilteringByViewerForList: (
+    builder: PageQueryBuilder,
+    user: IUser,
+  ) => PageQueryBuilder;
 };
 };
 
 
-export const generateBaseQuery = async(pagePath: string, user: IUser): Promise<PageQueryBuilder> => {
+export const generateBaseQuery = async (
+  pagePath: string,
+  user: IUser,
+): Promise<PageQueryBuilder> => {
   const Page = model<IPageHasId>('Page');
   const Page = model<IPageHasId>('Page');
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
   const PageAny = Page as any;
   const PageAny = Page as any;

+ 2 - 4
packages/remark-lsx/src/server/routes/list-pages/get-toppage-viewers-count.ts

@@ -1,7 +1,7 @@
 import type { IPage } from '@growi/core';
 import type { IPage } from '@growi/core';
 import { model } from 'mongoose';
 import { model } from 'mongoose';
 
 
-export const getToppageViewersCount = async(): Promise<number> => {
+export const getToppageViewersCount = async (): Promise<number> => {
   const Page = model<IPage>('Page');
   const Page = model<IPage>('Page');
 
 
   const aggRes = await Page.aggregate<{ count: number }>([
   const aggRes = await Page.aggregate<{ count: number }>([
@@ -9,7 +9,5 @@ export const getToppageViewersCount = async(): Promise<number> => {
     { $project: { count: { $size: '$seenUsers' } } },
     { $project: { count: { $size: '$seenUsers' } } },
   ]);
   ]);
 
 
-  return aggRes.length > 0
-    ? aggRes[0].count
-    : 1;
+  return aggRes.length > 0 ? aggRes[0].count : 1;
 };
 };

+ 20 - 15
packages/remark-lsx/src/server/routes/list-pages/index.spec.ts

@@ -3,14 +3,15 @@ import type { Request, Response } from 'express';
 import createError from 'http-errors';
 import createError from 'http-errors';
 import { mock } from 'vitest-mock-extended';
 import { mock } from 'vitest-mock-extended';
 
 
-import type { LsxApiResponseData, LsxApiParams } from '../../../interfaces/api';
+import type { LsxApiParams, LsxApiResponseData } from '../../../interfaces/api';
 
 
 import type { PageQuery, PageQueryBuilder } from './generate-base-query';
 import type { PageQuery, PageQueryBuilder } from './generate-base-query';
 
 
 import { listPages } from '.';
 import { listPages } from '.';
 
 
-interface IListPagesRequest extends Request<undefined, undefined, undefined, LsxApiParams> {
-  user: IUser,
+interface IListPagesRequest
+  extends Request<undefined, undefined, undefined, LsxApiParams> {
+  user: IUser;
 }
 }
 
 
 // mocking modules
 // mocking modules
@@ -23,15 +24,21 @@ const mocks = vi.hoisted(() => {
   };
   };
 });
 });
 
 
-vi.mock('./add-num-condition', () => ({ addNumCondition: mocks.addNumConditionMock }));
-vi.mock('./add-sort-condition', () => ({ addSortCondition: mocks.addSortConditionMock }));
-vi.mock('./generate-base-query', () => ({ generateBaseQuery: mocks.generateBaseQueryMock }));
-vi.mock('./get-toppage-viewers-count', () => ({ getToppageViewersCount: mocks.getToppageViewersCountMock }));
-
+vi.mock('./add-num-condition', () => ({
+  addNumCondition: mocks.addNumConditionMock,
+}));
+vi.mock('./add-sort-condition', () => ({
+  addSortCondition: mocks.addSortConditionMock,
+}));
+vi.mock('./generate-base-query', () => ({
+  generateBaseQuery: mocks.generateBaseQueryMock,
+}));
+vi.mock('./get-toppage-viewers-count', () => ({
+  getToppageViewersCount: mocks.getToppageViewersCountMock,
+}));
 
 
 describe('listPages', () => {
 describe('listPages', () => {
-
-  it("returns 400 HTTP response when the query 'pagePath' is undefined", async() => {
+  it("returns 400 HTTP response when the query 'pagePath' is undefined", async () => {
     // setup
     // setup
     const reqMock = mock<IListPagesRequest>();
     const reqMock = mock<IListPagesRequest>();
     const resMock = mock<Response>();
     const resMock = mock<Response>();
@@ -48,7 +55,6 @@ describe('listPages', () => {
   });
   });
 
 
   describe('with num option', () => {
   describe('with num option', () => {
-
     const reqMock = mock<IListPagesRequest>();
     const reqMock = mock<IListPagesRequest>();
     reqMock.query = { pagePath: '/Sandbox' };
     reqMock.query = { pagePath: '/Sandbox' };
 
 
@@ -60,7 +66,7 @@ describe('listPages', () => {
     const queryMock = mock<PageQuery>();
     const queryMock = mock<PageQuery>();
     builderMock.query = queryMock;
     builderMock.query = queryMock;
 
 
-    it('returns 200 HTTP response', async() => {
+    it('returns 200 HTTP response', async () => {
       // setup query.clone().count()
       // setup query.clone().count()
       const queryClonedMock = mock<PageQuery>();
       const queryClonedMock = mock<PageQuery>();
       queryMock.clone.mockReturnValue(queryClonedMock);
       queryMock.clone.mockReturnValue(queryClonedMock);
@@ -98,7 +104,7 @@ describe('listPages', () => {
       expect(resStatusMock.send).toHaveBeenCalledWith(expectedResponseData);
       expect(resStatusMock.send).toHaveBeenCalledWith(expectedResponseData);
     });
     });
 
 
-    it('returns 500 HTTP response when an unexpected error occured', async() => {
+    it('returns 500 HTTP response when an unexpected error occured', async () => {
       // setup
       // setup
       const reqMock = mock<IListPagesRequest>();
       const reqMock = mock<IListPagesRequest>();
       reqMock.query = { pagePath: '/Sandbox' };
       reqMock.query = { pagePath: '/Sandbox' };
@@ -125,7 +131,7 @@ describe('listPages', () => {
       expect(resStatusMock.send).toHaveBeenCalledWith('error for test');
       expect(resStatusMock.send).toHaveBeenCalledWith('error for test');
     });
     });
 
 
-    it('returns 400 HTTP response when the value is invalid', async() => {
+    it('returns 400 HTTP response when the value is invalid', async () => {
       // setup
       // setup
       const reqMock = mock<IListPagesRequest>();
       const reqMock = mock<IListPagesRequest>();
       reqMock.query = { pagePath: '/Sandbox' };
       reqMock.query = { pagePath: '/Sandbox' };
@@ -151,6 +157,5 @@ describe('listPages', () => {
       expect(resMock.status).toHaveBeenCalledOnce();
       expect(resMock.status).toHaveBeenCalledOnce();
       expect(resStatusMock.send).toHaveBeenCalledWith('error for test');
       expect(resStatusMock.send).toHaveBeenCalledWith('error for test');
     });
     });
-
   });
   });
 });
 });

+ 35 - 24
packages/remark-lsx/src/server/routes/list-pages/index.ts

@@ -1,4 +1,3 @@
-
 import type { IUser } from '@growi/core';
 import type { IUser } from '@growi/core';
 import { OptionParser } from '@growi/core/dist/remark-plugins';
 import { OptionParser } from '@growi/core/dist/remark-plugins';
 import { pathUtils } from '@growi/core/dist/utils';
 import { pathUtils } from '@growi/core/dist/utils';
@@ -11,19 +10,26 @@ import type { LsxApiParams, LsxApiResponseData } from '../../../interfaces/api';
 import { addDepthCondition } from './add-depth-condition';
 import { addDepthCondition } from './add-depth-condition';
 import { addNumCondition } from './add-num-condition';
 import { addNumCondition } from './add-num-condition';
 import { addSortCondition } from './add-sort-condition';
 import { addSortCondition } from './add-sort-condition';
-import { generateBaseQuery, type PageQuery } from './generate-base-query';
+import { type PageQuery, generateBaseQuery } from './generate-base-query';
 import { getToppageViewersCount } from './get-toppage-viewers-count';
 import { getToppageViewersCount } from './get-toppage-viewers-count';
 
 
-
 const { addTrailingSlash, removeTrailingSlash } = pathUtils;
 const { addTrailingSlash, removeTrailingSlash } = pathUtils;
 
 
 /**
 /**
  * add filter condition that filter fetched pages
  * add filter condition that filter fetched pages
  */
  */
-function addFilterCondition(query, pagePath, optionsFilter, isExceptFilter = false): PageQuery {
+function addFilterCondition(
+  query,
+  pagePath,
+  optionsFilter,
+  isExceptFilter = false,
+): PageQuery {
   // when option strings is 'filter=', the option value is true
   // when option strings is 'filter=', the option value is true
   if (optionsFilter == null || optionsFilter === true) {
   if (optionsFilter == null || optionsFilter === true) {
-    throw createError(400, 'filter option require value in regular expression.');
+    throw createError(
+      400,
+      'filter option require value in regular expression.',
+    );
   }
   }
 
 
   const pagePathForRegexp = escapeStringRegexp(addTrailingSlash(pagePath));
   const pagePathForRegexp = escapeStringRegexp(addTrailingSlash(pagePath));
@@ -32,13 +38,13 @@ function addFilterCondition(query, pagePath, optionsFilter, isExceptFilter = fal
   try {
   try {
     if (optionsFilter.charAt(0) === '^') {
     if (optionsFilter.charAt(0) === '^') {
       // move '^' to the first of path
       // move '^' to the first of path
-      filterPath = new RegExp(`^${pagePathForRegexp}${optionsFilter.slice(1, optionsFilter.length)}`);
-    }
-    else {
+      filterPath = new RegExp(
+        `^${pagePathForRegexp}${optionsFilter.slice(1, optionsFilter.length)}`,
+      );
+    } else {
       filterPath = new RegExp(`^${pagePathForRegexp}.*${optionsFilter}`);
       filterPath = new RegExp(`^${pagePathForRegexp}.*${optionsFilter}`);
     }
     }
-  }
-  catch (err) {
+  } catch (err) {
     throw createError(400, err);
     throw createError(400, err);
   }
   }
 
 
@@ -56,12 +62,15 @@ function addExceptCondition(query, pagePath, optionsFilter): PageQuery {
   return addFilterCondition(query, pagePath, optionsFilter, true);
   return addFilterCondition(query, pagePath, optionsFilter, true);
 }
 }
 
 
-interface IListPagesRequest extends Request<undefined, undefined, undefined, LsxApiParams> {
-  user: IUser,
+interface IListPagesRequest
+  extends Request<undefined, undefined, undefined, LsxApiParams> {
+  user: IUser;
 }
 }
 
 
-
-export const listPages = async(req: IListPagesRequest, res: Response): Promise<Response> => {
+export const listPages = async (
+  req: IListPagesRequest,
+  res: Response,
+): Promise<Response> => {
   const user = req.user;
   const user = req.user;
 
 
   if (req.query.pagePath == null) {
   if (req.query.pagePath == null) {
@@ -75,17 +84,14 @@ export const listPages = async(req: IListPagesRequest, res: Response): Promise<R
     options: req.query?.options ?? {},
     options: req.query?.options ?? {},
   };
   };
 
 
-  const {
-    pagePath, offset, limit, options,
-  } = params;
+  const { pagePath, offset, limit, options } = params;
   const builder = await generateBaseQuery(params.pagePath, user);
   const builder = await generateBaseQuery(params.pagePath, user);
 
 
   // count viewers of `/`
   // count viewers of `/`
   let toppageViewersCount;
   let toppageViewersCount;
   try {
   try {
     toppageViewersCount = await getToppageViewersCount();
     toppageViewersCount = await getToppageViewersCount();
-  }
-  catch (error) {
+  } catch (error) {
     return res.status(500).send(error);
     return res.status(500).send(error);
   }
   }
 
 
@@ -93,7 +99,11 @@ export const listPages = async(req: IListPagesRequest, res: Response): Promise<R
   try {
   try {
     // depth
     // depth
     if (options?.depth != null) {
     if (options?.depth != null) {
-      query = addDepthCondition(query, params.pagePath, OptionParser.parseRange(options.depth));
+      query = addDepthCondition(
+        query,
+        params.pagePath,
+        OptionParser.parseRange(options.depth),
+      );
     }
     }
     // filter
     // filter
     if (options?.filter != null) {
     if (options?.filter != null) {
@@ -115,15 +125,16 @@ export const listPages = async(req: IListPagesRequest, res: Response): Promise<R
     const cursor = (offset ?? 0) + pages.length;
     const cursor = (offset ?? 0) + pages.length;
 
 
     const responseData: LsxApiResponseData = {
     const responseData: LsxApiResponseData = {
-      pages, cursor, total, toppageViewersCount,
+      pages,
+      cursor,
+      total,
+      toppageViewersCount,
     };
     };
     return res.status(200).send(responseData);
     return res.status(200).send(responseData);
-  }
-  catch (error) {
+  } catch (error) {
     if (isHttpError(error)) {
     if (isHttpError(error)) {
       return res.status(error.status).send(error.message);
       return res.status(error.status).send(error.message);
     }
     }
     return res.status(500).send(error.message);
     return res.status(500).send(error.message);
   }
   }
-
 };
 };

+ 0 - 2
packages/remark-lsx/src/utils/depth-utils.spec.ts

@@ -1,7 +1,6 @@
 import { getDepthOfPath } from './depth-utils';
 import { getDepthOfPath } from './depth-utils';
 
 
 describe('getDepthOfPath()', () => {
 describe('getDepthOfPath()', () => {
-
   it('returns 0 when the path does not include slash', () => {
   it('returns 0 when the path does not include slash', () => {
     // when
     // when
     const result = getDepthOfPath('Sandbox');
     const result = getDepthOfPath('Sandbox');
@@ -9,5 +8,4 @@ describe('getDepthOfPath()', () => {
     // then
     // then
     expect(result).toBe(0);
     expect(result).toBe(0);
   });
   });
-
 });
 });

+ 2 - 6
packages/remark-lsx/tsconfig.json

@@ -4,9 +4,7 @@
   "compilerOptions": {
   "compilerOptions": {
     "jsx": "react-jsx",
     "jsx": "react-jsx",
 
 
-    "types": [
-      "vitest/globals"
-    ],
+    "types": ["vitest/globals"],
 
 
     /* TODO: remove below flags for strict checking */
     /* TODO: remove below flags for strict checking */
     "strict": false,
     "strict": false,
@@ -15,7 +13,5 @@
     "noImplicitAny": false,
     "noImplicitAny": false,
     "noImplicitOverride": true
     "noImplicitOverride": true
   },
   },
-  "include": [
-    "src"
-  ]
+  "include": ["src"]
 }
 }

+ 1 - 3
packages/remark-lsx/vite.server.config.ts

@@ -21,9 +21,7 @@ export default defineConfig({
     outDir: 'dist/server',
     outDir: 'dist/server',
     sourcemap: true,
     sourcemap: true,
     lib: {
     lib: {
-      entry: [
-        'src/server/index.ts',
-      ],
+      entry: ['src/server/index.ts'],
       name: 'remark-lsx-libs',
       name: 'remark-lsx-libs',
       formats: ['cjs'],
       formats: ['cjs'],
     },
     },

+ 1 - 3
packages/remark-lsx/vitest.config.ts

@@ -2,9 +2,7 @@ import tsconfigPaths from 'vite-tsconfig-paths';
 import { defineConfig } from 'vitest/config';
 import { defineConfig } from 'vitest/config';
 
 
 export default defineConfig({
 export default defineConfig({
-  plugins: [
-    tsconfigPaths(),
-  ],
+  plugins: [tsconfigPaths()],
   test: {
   test: {
     environment: 'node',
     environment: 'node',
     clearMocks: true,
     clearMocks: true,