Răsfoiți Sursa

build remark-lsx with vite

Yuki Takei 3 ani în urmă
părinte
comite
e535fd41ee

+ 0 - 2
apps/app/jest.config.js

@@ -7,8 +7,6 @@ const MODULE_NAME_MAPPING = {
   '^@growi/codemirror-textlint$': '<rootDir>/../../packages/codemirror-textlint/src',
   '^@growi/remark-drawio$': '<rootDir>/../../packages/remark-drawio/src',
   '^@growi/remark-growi-directive$': '<rootDir>/../../packages/remark-growi-directive/src',
-  '^@growi/remark-lsx$': '<rootDir>/../../packages/remark-drawio/src',
-  '^@growi/remark-lsx/(.+)$': '<rootDir>/../../packages/remark-lsx/src/$1',
   '^@growi/ui$': '<rootDir>/../../packages/ui/src',
 };
 

+ 1 - 1
apps/app/src/server/crowi/index.js

@@ -3,7 +3,7 @@ import http from 'http';
 import path from 'path';
 
 import { createTerminus } from '@godaddy/terminus';
-import lsxRoutes from '@growi/remark-lsx/server/routes';
+import lsxRoutes from '@growi/remark-lsx/dist/server/routes';
 import mongoose from 'mongoose';
 import next from 'next';
 

+ 2 - 2
apps/app/src/services/renderer/renderer.tsx

@@ -4,8 +4,8 @@ import type { ComponentType } from 'react';
 import { isClient } from '@growi/core';
 import * as drawioPlugin from '@growi/remark-drawio';
 import growiDirective from '@growi/remark-growi-directive';
-import { Lsx, LsxImmutable } from '@growi/remark-lsx/components';
-import * as lsxGrowiPlugin from '@growi/remark-lsx/services/renderer';
+import { Lsx, LsxImmutable } from '@growi/remark-lsx/dist/components';
+import * as lsxGrowiPlugin from '@growi/remark-lsx/dist/services/renderer';
 import type { Schema as SanitizeOption } from 'hast-util-sanitize';
 import type { SpecialComponents } from 'react-markdown/lib/ast-to-react';
 import type { NormalComponents } from 'react-markdown/lib/complex-types';

+ 2 - 2
apps/app/tsconfig.build.client.json

@@ -16,8 +16,8 @@
       // "@growi/preset-themes": ["../../packages/preset-themes/src"],
       "@growi/remark-drawio": ["../../packages/remark-drawio/src"],
       "@growi/remark-growi-directive": ["../../packages/remark-growi-directive/src"],
-      "@growi/remark-lsx": ["../../packages/remark-lsx/src"],
-      "@growi/remark-lsx/*": ["../../packages/remark-lsx/src/*"],
+      // "@growi/remark-lsx": ["../../packages/remark-lsx/src"],
+      // "@growi/remark-lsx/*": ["../../packages/remark-lsx/src/*"],
       // "@growi/slack": ["../../packages/slack/src"],
       "@growi/ui": ["../../packages/ui/src"],
 

+ 1 - 1
apps/app/tsconfig.build.server.json

@@ -13,7 +13,7 @@
     "paths": {
       "~/*": ["./src/*"],
       "^/*": ["./*"],
-      "@growi/remark-lsx/*": ["../../packages/remark-lsx/dist/*"],
+      // "@growi/remark-lsx/*": ["../../packages/remark-lsx/dist/*"],
       "debug": ["./src/utils/logger/alias-for-debug"]
     }
   },

+ 2 - 2
apps/app/tsconfig.json

@@ -16,8 +16,8 @@
       // "@growi/preset-themes": ["../../packages/preset-themes/src"],
       "@growi/remark-drawio": ["../../packages/remark-drawio/src"],
       "@growi/remark-growi-directive": ["../../packages/remark-growi-directive/src"],
-      "@growi/remark-lsx": ["../../packages/remark-lsx/src"],
-      "@growi/remark-lsx/*": ["../../packages/remark-lsx/src/*"],
+      // "@growi/remark-lsx": ["../../packages/remark-lsx/src"],
+      // "@growi/remark-lsx/*": ["../../packages/remark-lsx/src/*"],
       // "@growi/slack": ["../../packages/slack/src"],
       "@growi/ui": ["../../packages/ui/src"],
 

+ 2 - 19
packages/core/src/index.ts

@@ -1,18 +1,3 @@
-import * as _envUtils from './utils/env-utils';
-
-// export utils by *.js
-export const envUtils = _envUtils;
-
-// export utils with namespace
-export * as customTagUtils from './plugin/util/custom-tag-utils';
-export * as templateChecker from './utils/template-checker';
-export * as objectIdUtils from './utils/objectid-utils';
-export * as pagePathUtils from './utils/page-path-utils';
-export * as pathUtils from './utils/path-utils';
-export * as pageUtils from './utils/page-utils';
-
-// export all
-export * from './plugin/interfaces/option-parser';
 export * from './interfaces/attachment';
 export * from './interfaces/color-scheme';
 export * from './interfaces/common';
@@ -29,8 +14,6 @@ export * from './interfaces/user';
 export * from './interfaces/vite';
 export * from './models/devided-page-path';
 export * from './models/vo/error-apiv3';
+export * from './plugin';
 export * from './service/localstorage-manager';
-export * from './utils/basic-interceptor';
-export * from './utils/browser-utils';
-export * from './utils/growi-theme-metadata';
-export * from './utils/with-utils';
+export * from './utils';

+ 2 - 0
packages/core/src/plugin/index.ts

@@ -0,0 +1,2 @@
+export * from './interfaces/option-parser';
+export * from './util/option-parser';

+ 0 - 18
packages/core/src/plugin/model/tag-context.ts

@@ -1,18 +0,0 @@
-/**
- * Context class for custom-tag-utils#findTagAndReplace
- */
-export class TagContext {
-
-  tagExpression: string | null;
-
-  method: string | null;
-
-  args: any;
-
-  constructor(initArgs: any = {}) {
-    this.tagExpression = initArgs.tagExpression || null;
-    this.method = initArgs.method || null;
-    this.args = initArgs.args || null;
-  }
-
-}

+ 0 - 57
packages/core/src/plugin/util/args-parser.js

@@ -1,57 +0,0 @@
-/**
- * Arguments parser for custom tag
- */
-export class ArgsParser {
-
-  /**
-   * @typedef ParseArgsResult
-   * @property {string} firstArgsKey - key of the first argument
-   * @property {string|boolean} firstArgsValue - value of the first argument
-   * @property {object} options - key of the first argument
-   */
-
-  /**
-   * parse plugin argument strings
-   *
-   * @static
-   * @param {string} str
-   * @returns {ParseArgsResult}
-   */
-  static parse(str) {
-    let firstArgsKey = null;
-    let firstArgsValue = null;
-    const options = {};
-
-    if (str != null && str.length > 0) {
-      const splittedArgs = str.split(',');
-
-      splittedArgs.forEach((rawArg, index) => {
-        const arg = rawArg.trim();
-
-        // parse string like 'key1=value1, key2=value2, ...'
-        // see https://regex101.com/r/pYHcOM/1
-        const match = arg.match(/([^=]+)=?(.+)?/);
-
-        if (match == null) {
-          return;
-        }
-
-        const key = match[1];
-        const value = match[2] || true;
-        options[key] = value;
-
-        if (index === 0) {
-          firstArgsKey = key;
-          firstArgsValue = value;
-        }
-      });
-    }
-
-    return {
-      firstArgsKey,
-      firstArgsValue,
-      options,
-    };
-  }
-
-}

+ 0 - 5
packages/core/src/plugin/util/custom-tag-utils.ts

@@ -1,5 +0,0 @@
-export * from '../model/tag-context';
-
-export * from './args-parser';
-
-export * from './option-parser';

+ 1 - 1
packages/core/src/plugin/util/option-parser.ts

@@ -1,4 +1,4 @@
-import { ParseRangeResult } from '../interfaces/option-parser';
+import type { ParseRangeResult } from '../interfaces/option-parser';
 
 /**
  * Options parser for custom tag

+ 16 - 0
packages/core/src/utils/index.ts

@@ -0,0 +1,16 @@
+import * as _envUtils from './env-utils';
+
+// export utils by *.js
+export const envUtils = _envUtils;
+
+// export utils with namespace
+export * as templateChecker from './template-checker';
+export * as objectIdUtils from './objectid-utils';
+export * as pagePathUtils from './page-path-utils';
+export * as pathUtils from './path-utils';
+export * as pageUtils from './page-utils';
+
+export * from './basic-interceptor';
+export * from './browser-utils';
+export * from './growi-theme-metadata';
+export * from './with-utils';

+ 0 - 42
packages/core/test/plugin/util/args-parser.test.js

@@ -1,42 +0,0 @@
-import { ArgsParser } from '~/plugin/util/args-parser';
-
-describe('args-parser', () => {
-
-  test('.parse(null) returns default object', () => {
-    const result = ArgsParser.parse(null);
-
-    expect(result.firstArgsKey).toBeNull();
-    expect(result.firstArgsValue).toBeNull();
-    expect(result.options).toEqual({});
-  });
-
-  test('.parse(\'prefix=/Level1\') returns a valid results', () => {
-    const result = ArgsParser.parse('prefix=/Level1');
-
-    expect(result.firstArgsKey).toBe('prefix');
-    expect(result.firstArgsValue).toBe('/Level1');
-  });
-
-  test('.parse(\'key, opt1=1, opt2=2\') returns a valid results', () => {
-    const result = ArgsParser.parse('key, opt1=1, opt2=2');
-
-    expect(result.firstArgsKey).toBe('key');
-    expect(result.firstArgsValue).toBeTruthy();
-
-    expect(Object.keys(result.options).length).toBe(3);
-    expect(result.options.key).toBeTruthy();
-    expect(result.options.opt1).toBe('1');
-    expect(result.options.opt2).toBe('2');
-  });
-
-  test('.parse(\'key, \') returns a valid results', () => {
-    const result = ArgsParser.parse('key, ');
-
-    expect(result.firstArgsKey).toBe('key');
-    expect(result.firstArgsValue).toBeTruthy();
-
-    expect(Object.keys(result.options).length).toBe(1);
-    expect(result.options.key).toBeTruthy();
-  });
-
-});

+ 0 - 74
packages/core/test/plugin/util/custom-tag-utils.test.js

@@ -1,74 +0,0 @@
-import rewire from 'rewire';
-
-import * as customTagUtils from '~/plugin/util/custom-tag-utils';
-
-// leave it commented out for rewire example -- 2022.08.18 Yuki Takei
-// const rewiredCustomTagUtils = rewire('../../../plugin/util/custom-tag-utils');
-
-describe('customTagUtils', () => {
-
-  test('exports TagContext', () => {
-    expect(customTagUtils.TagContext).not.toBeNull();
-    expect(typeof customTagUtils.TagContext).toBe('function');
-  });
-
-  test('exports ArgsParser', () => {
-    expect(customTagUtils.ArgsParser).not.toBeNull();
-    expect(typeof customTagUtils.ArgsParser).toBe('function');
-  });
-
-  test('exports OptionParser', () => {
-    expect(customTagUtils.OptionParser).not.toBeNull();
-    expect(typeof customTagUtils.OptionParser).toBe('function');
-  });
-
-  // leave it commented out for rewire example -- 2022.08.18 Yuki Takei
-  // test('.createRandomStr(10) returns random string', () => {
-  //   // get private resource
-  //   const createRandomStr = rewiredCustomTagUtils.__get__('createRandomStr');
-  //   expect(createRandomStr(10)).toMatch(/^[a-z0-9]{10}$/);
-  // });
-
-  // test('.findTagAndReplace() returns default object when tagPattern is null', () => {
-  //   const htmlMock = jest.fn();
-  //   htmlMock.replace = jest.fn();
-
-  //   const result = customTagUtils.findTagAndReplace(null, '');
-
-  //   expect(result).toEqual({ html: '', tagContextMap: {} });
-  //   expect(htmlMock.replace).not.toHaveBeenCalled();
-  // });
-
-  // test('.findTagAndReplace() returns default object when html is null', () => {
-  //   const tagPatternMock = jest.fn();
-  //   tagPatternMock.source = jest.fn();
-
-  //   const result = customTagUtils.findTagAndReplace(tagPatternMock, null);
-
-  //   expect(result).toEqual({ html: null, tagContextMap: {} });
-  //   expect(tagPatternMock.source).not.toHaveBeenCalled();
-  // });
-
-  // test('.findTagAndReplace() works correctly', () => {
-  //   // setup mocks for private function
-  //   rewiredCustomTagUtils.__set__('createRandomStr', (length) => {
-  //     return 'dummyDomId';
-  //   });
-
-  //   const tagPattern = /ls|lsx/;
-  //   const html = '<section><h1>header</h1>\n$ls(/)</section>';
-
-  //   const result = rewiredCustomTagUtils.findTagAndReplace(tagPattern, html);
-
-  //   expect(result.html).toMatch(/<section><h1>header<\/h1>\n<div id="ls-dummyDomId"><\/div>/);
-  //   expect(result.tagContextMap).toEqual({
-  //     'ls-dummyDomId': {
-  //       tagExpression: '$ls(/)',
-  //       method: 'ls',
-  //       args: '/',
-  //     },
-  //   });
-  // });
-
-
-});

+ 1 - 0
packages/remark-lsx/.gitignore

@@ -1 +1,2 @@
 /dist
+/types

+ 14 - 9
packages/remark-lsx/package.json

@@ -5,15 +5,16 @@
   "license": "MIT",
   "keywords": ["growi", "growi-plugin"],
   "main": "dist/index.js",
-  "exports": {
-    "./components": "./dist/components/index.js",
-    "./services/renderer": "./dist/services/renderer/index.js",
-    "./server/routes": "./dist/server/routes/index.js"
-  },
-  "files": ["dist"],
+  "types": "types/index.d.ts",
+  "files": [
+    "dist",
+    "types"
+  ],
   "scripts": {
-    "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
+    "build": "vite build",
     "clean": "npx -y shx rm -rf dist",
+    "dev": "vite build --mode dev",
+    "watch": "yarn dev -w",
     "lint:js": "eslint **/*.{js,jsx,ts,tsx}",
     "lint:styles": "stylelint --allow-empty-input src/**/*.scss src/**/*.css",
     "lint": "run-p lint:*"
@@ -25,8 +26,12 @@
     "swr": "^2.0.3"
   },
   "devDependencies": {
-    "eslint-plugin-regex": "^1.8.0",
+    "eslint-plugin-regex": "^1.8.0"
+  },
+  "peerDependencies": {
+    "next": "~12.2",
     "react": "^18.2.0",
-    "react-dom": "^18.2.0"
+    "react-dom": "^18.2.0",
+    "react-markdown": "^8.0.3"
   }
 }

+ 1 - 1
packages/remark-lsx/src/components/LsxPageList/LsxListView.module.scss

@@ -1 +1 @@
-@use '~/styles/molecules/page_list';
+// @use '~/styles/molecules/page_list';

+ 1 - 3
packages/remark-lsx/src/components/lsx-context.ts

@@ -1,6 +1,4 @@
-import { customTagUtils, ParseRangeResult } from '@growi/core';
-
-const { OptionParser } = customTagUtils;
+import { OptionParser, type ParseRangeResult } from '@growi/core/dist/plugin';
 
 
 export class LsxContext {

+ 0 - 6
packages/remark-lsx/src/index.ts

@@ -1,6 +0,0 @@
-import * as _serverRoutes from './server/routes';
-
-export const serverRoutes = _serverRoutes;
-
-export * from './components';
-export * from './services/renderer';

+ 6 - 2
packages/remark-lsx/src/server/routes/index.js → packages/remark-lsx/src/server/routes/index.ts

@@ -1,13 +1,17 @@
+import { routesFactory } from './lsx';
 
 const loginRequiredFallback = (req, res) => {
   return res.status(403).send('login required');
 };
 
-module.exports = (crowi, app) => {
-  const lsx = require('./lsx')(crowi, app);
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
+const middleware = (crowi: any, app: any): void => {
+  const lsx = routesFactory(crowi, app);
 
   const loginRequired = crowi.require('../middlewares/login-required')(crowi, true, loginRequiredFallback);
   const accessTokenParser = crowi.require('../middlewares/access-token-parser')(crowi);
 
   app.get('/_api/lsx', accessTokenParser, loginRequired, lsx.listPages);
 };
+
+export default middleware;

+ 6 - 7
packages/remark-lsx/src/server/routes/lsx.js → packages/remark-lsx/src/server/routes/lsx.ts

@@ -1,9 +1,7 @@
+import { OptionParser } from '@growi/core/dist/plugin';
+import { pathUtils, pagePathUtils } from '@growi/core/dist/utils';
 import createError, { isHttpError } from 'http-errors';
 
-const { pathUtils, pagePathUtils, customTagUtils } = require('@growi/core');
-
-const { OptionParser } = customTagUtils;
-
 
 const DEFAULT_PAGES_NUM = 50;
 
@@ -103,7 +101,7 @@ class Lsx {
       throw createError(400, 'filter option require value in regular expression.');
     }
 
-    let filterPath = '';
+    let filterPath;
     if (optionsFilter.charAt(0) === '^') {
       // move '^' to the first of path
       filterPath = new RegExp(`^${addTrailingSlash(pagePath)}${optionsFilter.slice(1, optionsFilter.length)}`);
@@ -159,9 +157,10 @@ class Lsx {
 
 }
 
-module.exports = (crowi, app) => {
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+export const routesFactory = (crowi, app): any => {
   const Page = crowi.model('Page');
-  const actions = {};
+  const actions: any = {};
 
   /**
    *

+ 0 - 13
packages/remark-lsx/tsconfig.base.json

@@ -1,13 +0,0 @@
-{
-  "$schema": "http://json.schemastore.org/tsconfig",
-  "extends": "../../tsconfig.base.json",
-  "compilerOptions": {
-    "jsx": "preserve",
-  },
-  "include": [
-    "src"
-  ],
-  "exclude": [
-    "src/test"
-  ]
-}

+ 0 - 17
packages/remark-lsx/tsconfig.build.json

@@ -1,17 +0,0 @@
-{
-  "$schema": "http://json.schemastore.org/tsconfig",
-  "extends": "./tsconfig.base.json",
-  "compilerOptions": {
-    "rootDir": "./src",
-    "outDir": "dist",
-    "declaration": true,
-    "noResolve": false,
-    "preserveConstEnums": true,
-    "sourceMap": false,
-    "noEmit": false,
-
-    "baseUrl": ".",
-    "paths": {
-    }
-  }
-}

+ 7 - 3
packages/remark-lsx/tsconfig.json

@@ -1,11 +1,15 @@
 {
   "$schema": "http://json.schemastore.org/tsconfig",
-  "extends": "./tsconfig.base.json",
+  "extends": "../../tsconfig.base.json",
   "compilerOptions": {
+    "jsx": "react-jsxdev",
+
     "baseUrl": ".",
     "paths": {
       "~/*": ["./src/*"],
-      "@growi/*": ["../*/src"]
     }
-  }
+  },
+  "include": [
+    "src"
+  ]
 }

+ 41 - 0
packages/remark-lsx/vite.config.ts

@@ -0,0 +1,41 @@
+import react from '@vitejs/plugin-react';
+import { defineConfig } from 'vite';
+import dts from 'vite-plugin-dts';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  plugins: [
+    react(),
+    dts({ outputDir: 'types' }),
+  ],
+  build: {
+    outDir: 'dist',
+    lib: {
+      entry: [
+        'src/components/index.ts',
+        'src/server/routes/index.ts',
+        'src/services/renderer/index.ts',
+      ],
+      name: 'remark-lsx-libs',
+      formats: ['es', 'cjs'],
+    },
+    rollupOptions: {
+      output: {
+        preserveModules: true,
+        preserveModulesRoot: 'src',
+      },
+      external: [
+        'axios',
+        'http-errors',
+        'is-absolute-url',
+        'react',
+        'next/link',
+        'unified',
+        'swr',
+        /^hast-.*/,
+        /^unist-.*/,
+        /^@growi\/.*/,
+      ],
+    },
+  },
+});