Steven Fukase 4 лет назад
Родитель
Сommit
2c2ff97a72

+ 1 - 0
packages/app/package.json

@@ -160,6 +160,7 @@
     "@atlaskit/navigation-next": "^8.0.5",
     "@handsontable/react": "=2.1.0",
     "@textlint/kernel": "^12.0.2",
+    "@types/codemirror": "^5.60.2",
     "@types/compression": "^1.7.0",
     "@types/express": "^4.17.11",
     "@types/multer": "^1.4.5",

+ 0 - 63
packages/app/src/client/util/codemirror/codemirror-textlint.js

@@ -1,63 +0,0 @@
-import { TextlintKernel } from '@textlint/kernel';
-import textlintToCodeMirror from 'textlint-message-to-codemirror';
-
-const ruleModulesList = {
-  'max-comma': require('textlint-rule-max-comma').default,
-  'common-misspellings': require('textlint-rule-common-misspellings').default,
-};
-
-const kernel = new TextlintKernel();
-
-let textlintOption = {};
-
-const createSetupRules = (rules, ruleOptions) => (
-  Object.keys(rules).map(ruleName => (
-    {
-      ruleId: ruleName,
-      rule: rules[ruleName],
-      options: ruleOptions[ruleName],
-    }
-  ))
-);
-
-
-export default function createValidator(rulesConfigArray) {
-  const rules = rulesConfigArray.reduce((rules, rule) => {
-    rules[rule.name] = ruleModulesList[rule.name];
-    return rules;
-  }, {});
-
-  const rulesOption = rulesConfigArray.reduce((rules, rule) => {
-    rules[rule.name] = rule.options || {};
-    return rules;
-  }, {});
-
-
-  textlintOption = Object.assign(
-    {},
-    {
-      rules: createSetupRules(rules, rulesOption),
-      plugins: [
-        {
-          pluginId: 'markdown',
-          plugin: require('textlint-plugin-markdown'),
-        },
-      ],
-      ext: '.md',
-    },
-  );
-
-  return (text, callback) => {
-    if (!text) {
-      callback([]);
-      return;
-    }
-    kernel
-      .lintText(text, textlintOption)
-      .then((result) => {
-        const lintMessages = result.messages;
-        const lintErrors = lintMessages.map(textlintToCodeMirror);
-        callback(lintErrors);
-      });
-  };
-}

+ 88 - 0
packages/app/src/client/util/codemirror/codemirror-textlint.ts

@@ -0,0 +1,88 @@
+import { TextlintKernel, TextlintRuleOptions } from '@textlint/kernel';
+import textlintToCodeMirror from 'textlint-message-to-codemirror';
+import textlintRuleMaxComma from 'textlint-rule-max-comma';
+import textlintRuleCommonMisspellings from 'textlint-rule-common-misspellings';
+import { AsyncLinter, Annotation } from 'codemirror/addon/lint/lint';
+import loggerFactory from '../../../utils/logger';
+
+type RulesConfigObj = {
+  name: string,
+  options?: unknown,
+}
+
+type RuleExtension = {
+  ext: string
+}
+
+type RulesConfigArray = Array<RulesConfigObj>
+
+const ruleModulesList = {
+  'max-comma': textlintRuleMaxComma,
+  'common-misspellings': textlintRuleCommonMisspellings,
+};
+
+const logger = loggerFactory('growi:codemirror:codemirror-textlint');
+const kernel = new TextlintKernel();
+const textlintOption: TextlintRuleOptions<RuleExtension> = { ext: '.md' };
+
+const createSetupRules = (rules, ruleOptions) => (
+  Object.keys(rules).map(ruleName => (
+    {
+      ruleId: ruleName,
+      rule: rules[ruleName],
+      options: ruleOptions[ruleName],
+    }
+  ))
+);
+
+
+export const createValidator = (rulesConfigArray: RulesConfigArray): AsyncLinter<RulesConfigArray> => {
+
+  const filteredConfigArray = rulesConfigArray
+    .filter((rule) => {
+      if (ruleModulesList[rule.name] == null) {
+        logger.error(`Textlint rule ${rule.name} is not installed`);
+      }
+      return ruleModulesList[rule.name] != null;
+    });
+
+  const rules = filteredConfigArray
+    .reduce((rules, rule) => {
+      rules[rule.name] = ruleModulesList[rule.name];
+      return rules;
+    }, {});
+
+  const rulesOption = filteredConfigArray
+    .reduce((rules, rule) => {
+      rules[rule.name] = rule.options || {};
+      return rules;
+    }, {});
+
+  Object.assign(
+    textlintOption,
+    {
+      rules: createSetupRules(rules, rulesOption),
+      plugins: [
+        {
+          pluginId: 'markdown',
+          plugin: require('textlint-plugin-markdown'),
+        },
+      ],
+    },
+  );
+
+
+  return (text, callback) => {
+    if (!text) {
+      callback([]);
+      return;
+    }
+    kernel
+      .lintText(text, textlintOption)
+      .then((result) => {
+        const lintMessages = result.messages;
+        const lintErrors: Annotation[] = lintMessages.map(textlintToCodeMirror);
+        callback(lintErrors);
+      });
+  };
+};

+ 4 - 1
packages/app/src/components/PageEditor/CodeMirrorEditor.jsx

@@ -32,7 +32,7 @@ import HandsontableModal from './HandsontableModal';
 import EditorIcon from './EditorIcon';
 import DrawioModal from './DrawioModal';
 
-import createValidator from '../../client/util/codemirror/codemirror-textlint';
+import { createValidator } from '../../client/util/codemirror/codemirror-textlint';
 
 window.JSHINT = JSHINT;
 
@@ -867,6 +867,9 @@ export default class CodeMirrorEditor extends AbstractEditor {
       {
         name: 'max-comma',
       },
+      {
+        name: 'dummy-rule',
+      },
       {
         name: 'common-misspellings',
         options: {

+ 19 - 0
yarn.lock

@@ -2708,6 +2708,13 @@
   resolved "https://registry.yarnpkg.com/@types/cache-manager/-/cache-manager-3.4.0.tgz#414136ea3807a8cd071b8f20370c5df5dbffd382"
   integrity sha512-XVbn2HS+O+Mk2SKRCjr01/8oD5p2Tv1fxxdBqJ0+Cl+UBNiz0WVY5rusHpMGx+qF6Vc2pnRwPVwSKbGaDApCpw==
 
+"@types/codemirror@^5.60.2":
+  version "5.60.2"
+  resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-5.60.2.tgz#1f8b604964efb4fa2f5a6d6d8c5656f93a050d8a"
+  integrity sha512-tk8YxckrdU49GaJYRKxdzzzXrTlyT2nQGnobb8rAk34jt+kYXOxPKGqNgr7SJpl5r6YGaRD4CDfqiL+6A+/z7w==
+  dependencies:
+    "@types/tern" "*"
+
 "@types/color-name@^1.1.1":
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
@@ -2725,6 +2732,11 @@
   resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd"
   integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==
 
+"@types/estree@*":
+  version "0.0.50"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83"
+  integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==
+
 "@types/express-serve-static-core@^4.17.18":
   version "4.17.19"
   resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz#00acfc1632e729acac4f1530e9e16f6dd1508a1d"
@@ -2992,6 +3004,13 @@
   resolved "https://registry.yarnpkg.com/@types/structured-source/-/structured-source-3.0.0.tgz#e95d76037d400c1957f3b709f023b308e92f3829"
   integrity sha512-8u+Wo5+GEXe4jZyQ8TplLp+1A7g32ZcVoE7VZu8VcxnlaEm5I/+T579R7q3qKN76jmK0lRshpo4hl4bj/kEPKA==
 
+"@types/tern@*":
+  version "0.23.4"
+  resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.4.tgz#03926eb13dbeaf3ae0d390caf706b2643a0127fb"
+  integrity sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==
+  dependencies:
+    "@types/estree" "*"
+
 "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2":
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"