scrapbox-lint
scrapboxで校閲を行うUserScript by /hata6502/hata6502.icon
/hata6502/scrapbox-lint
textlintをworkerで動かして校閲している
ESModule workerを使っているため、提示されたコードのままではFirefoxで動かせない
少しいじってみる
変更点
型定義を不完全ながら追加
refactoring
""にする
querySelector()をやめる
コメントを追加
校閲数の表示
隠れている文字の場合は、そのひとつ上のDOMを指定する
import errorになったコードを差し替える
code:js
const { runScrapboxLint } = await import("/api/code/takker/scrapbox-lint-min/script.js");
await runScrapboxLint({});
指摘箇所を赤色で表示します。
「私は私は」
「何れ」よりも「いずれ」のほうが読みやすい。
「しかし」執筆は難しい。「しかし」を連続して使うと、文の流れが不規則になりがちだ。
気軽にアイデアをアウトプット「したり」、かっちり文章を整える。「たり」が抜けている。
PDF からのコピペでありがちな「タ゛クテン」とかを見つけられる。
うーん?動かないなtakker.icon
09:38:15 workerはindex.jsじゃなくてworker.jsだった
bundle
https://scrapbox-bundler.vercel.app?url=https://scrapbox.io/api/code/takker/scrapbox-lint/script.ts&template=https://scrapbox.io/api/code/takker/scrapbox-lint/template-ui&define=WORKER_URL:"/api/code/takker/scrapbox-lint-worker/script.js"&bundle&run&output=download
https://scrapbox-bundler.vercel.app?url=https://scrapbox.io/api/code/takker/scrapbox-lint/worker.ts&format=iife&bundle&minify&run&output=newtab
bundleに失敗した
textlint-rule-ja-hiragana-daimeishiを始めとしたいくつかのmoduleが内部でfsを用いている
Denoで型チェックをしていたときには気づかなかった
DenoのIO APIに置き換えられていたから
/hata6502/hata6502.iconさんはこれをいったいどうやってbrowser向けにbundleしたのだろうか?
09:19:38 どうやらbabel-plugin-static-fsを使っているようだ
ええ……esm.shじゃあどうあがいたってbundleできないじゃんtakker.icon
代替策
https://scrapbox.io/api/code/hata6502/scrapbox-lint/worker.js をIIFEにbundleする
https://scrapbox-bundler.vercel.app/?url=https://scrapbox.io/api/code/hata6502/scrapbox-lint/worker.js&template=https://scrapbox.io/api/code/takker/scrapbox-lint/template-worker&format=iife&bundle&minify&run&output=download
code:template-ui(txt)
scrapbox-lint-min
/takker/scrapbox-lintを@URL@ これでbundleしたコード
code:script.js
@CODE@
code:template-worker(txt)
scrapbox-lint-worker
kohsei-san-core/index.jsを@URL@ これでbundleしたコード
Firefoxからも使えるよう、IIFEに変換してある
code:script.js
@CODE@
code:script.ts
/// <reference no-default-lib="true" />
/// <reference lib="deno.ns" />
/// <reference lib="deno.unstable" />
/// <reference lib="dom" />
import type { LintOption } from "./lintOptions.ts";
import type { MessageResponse } from "./types.ts";
import type { Scrapbox } from "./deps_scrapbox.ts";
declare const WORKER_URL: string;
declare const scrapbox: Scrapbox;
エントリポイント
code:script.ts
let result: MessageResponse"result" | undefined;
const worker = new Worker(WORKER_URL);
export interface ScrapboxLintProps {
/** textlintのoptionsが書かれてたJSONファイル */
lintOptionURL: string | URL;
}
/** entry point */
export const runScrapboxLint = async (props: ScrapboxLintProps) => {
document.head.insertAdjacentHTML(
"beforeend",
'<link rel="stylesheet" href="/api/code/takker/microtip/index.css">',
);
const lintOption = await getLintOption(props);
worker.addEventListener("message", (event) => {
const data = event.data;
switch (data.type) {
case "result": {
if (scrapbox.Layout !== "page" || getText() !== data.text) {
return;
}
result = data.result;
updatePins();
break;
}
// TODO: exhaustive check
}
});
ここのPerformanceObserverは何の役割をしているのだろうか?
code:script.ts
new PerformanceObserver(updatePins).observe({type: 'layout-shift', buffered: true});
lintPage(lintOption);
scrapbox.on("lines:changed", () => lintPage(lintOption));
scrapbox.on("layout:changed", () => lintPage(lintOption)); // トップページでは校閲情報をクリアする
scrapbox.on("project:changed", () => location.reload());
};
textlintのoptionを読み込む
code:script.ts
const getLintOption = async ({ lintOptionURL }: ScrapboxLintProps): Promise<LintOption> => {
if (!lintOptionURL) {
return {};
}
const response = await fetch(lintOptionURL);
if (!response.ok) {
throw new Error(
${response.status} ${response.statusText}
);
}
return response.json() as Promise<LintOption>;
};
utilities
code:script.ts
/** 現在のページのテキストを取得する */
const getText = () => scrapbox.Page.lines.map((line) => line.text).join("\n");
Lintを実行する
code:script.ts
const lintPage = (lintOption: LintOption) => {
result = undefined;
updatePins();
if (scrapbox.Layout !== "page") {
return;
}
worker.postMessage({ type: "lint", lintOption, text: getText() });
};
指摘箇所を表示するUIを作成・更新する
code:script.ts
const pinElements = [] as HTMLDivElement[];
const updatePins = () => {
pinElements.forEach((pinElement) => pinElement.remove());
pinElements.splice(0); // 全要素を削除する
const bodyRect = document.body.getBoundingClientRect();
const messages = result?.messages;
if (!messages) return;
messages.forEach((message) => {
const lineID = scrapbox.Page.linesmessage.line - 1.id;
const lineElement = document.getElementById(L${lineID});
const charElement = lineElement.getElementsByClassName(c-${message.column - 1})?.0;
const charRect = charElement.classList.contains("empty-char-index") ?
// 隠れている文字だったら、そのひとつ上のDOMを代わりに使う
charElement.parentElement.getBoundingClientRect() :
charElement.getBoundingClientRect();
const pinElement = document.createElement("div");
pinElement.dataset.microtipPosition = "top";
pinElement.style.position = "absolute";
pinElement.style.left = ${charRect.left - bodyRect.left}px;
pinElement.style.top = ${charRect.top - bodyRect.top}px;
pinElement.style.height = ${charRect.height}px;
pinElement.style.width = ${charRect.width}px;
pinElement.style.backgroundColor = "rgba(241, 93, 105, 0.5)";
pinElement.setAttribute("aria-label", message.message);
pinElement.setAttribute("role", "tooltip");
document.body.append(pinElement);
pinElements.push(pinElement);
});
if (messages.length > 0) {
const item = ensureStatusItem();
item.textContent = lint: ${messages.length};
} else {
getStatusItem()?.remove?.();
}
};
status-bar (scrapbox)周り
code:script.ts
const statusBarItemId = "scrapbox-lint";
function getStatusItem() {
return document.querySelector(div[data-id="${statusBarItemId}"]);
}
function ensureStatusItem() {
let item = getStatusItem();
if (item) return item;
item ??= document.createElement('div');
item.dataset.id = statusBarItemId;
getStatusBar().append(item);
return item;
}
function getStatusBar() {
return document.getElementsByClassName('status-bar')?.0;
}
worker code
code:worker.ts
/// <reference no-default-lib="true" />
/// <reference lib="deno.ns" />
/// <reference lib="deno.unstable" />
/// <reference lib="webworker" />
import { lint } from "./kohsei-san-core.ts";
import type { LintOption } from "./lintOptions.ts";
import type { MessageRequest } from "./types.ts";
declare global {
interface WorkerGlobalScope {
kuromojin: {
dicPath: string;
}
}
}
self.kuromojin = {
dicPath: "https://storage.googleapis.com/scrapbox-lint/",
};
self.addEventListener("message", async (event: MessageEvent) => {
const data = event.data as MessageRequest;
switch (data.type) {
case "lint": {
const { lintOption, text } = data;
const result = await lint({ lintOption, text });
self.postMessage({
type: "result",
result,
text,
});
break;
}
// TODO: exhaustive check
}
});
lint({ lintOption: {}, text: "初回校正時でもキャッシュにヒットさせるため。" });
型定義
code:types.ts
import type { TextlintResult } from "./deps.ts";
import type { LintOption } from "./lintOptions.ts";
export interface MessageRequest {
type: "lint";
lintOption: LintOption;
text: string;
}
export interface MessageResponse {
type: "result";
result: TextlintResult;
text: string;
}
kohsei-sanのlint.tsから引っ張ってきた
These codes are under the LICENSE
code:kohsei-san-core.ts
import {
TextlintKernel,
textlintFilterRuleURLs,
textlintPluginText,
textlintRuleGeneralNovelStyleJa,
textlintRuleJaHiraganaDaimeishi,
textlintRuleJaHiraganaFukushi,
textlintRuleJaHiraganaHojodoushi,
textlintRuleJaHiraganaKeishikimeishi,
textlintRuleJaJoyoOrJinmeiyoKanji,
textlintRuleJaKyoikuKanji,
textlintRuleJaNoMixedPeriod,
textlintRuleJaNoRedundantExpression,
textlintRuleJaNoSuccessiveWord,
textlintRuleJaNoWeakPhrase,
textlintRuleJaUnnaturalAlphabet,
textlintRuleMaxAppearenceCountOfWords,
textlintRuleNoDoubledConjunctiveParticleGa,
textlintRuleNoDroppingI,
textlintRuleNoFiller,
textlintRuleNoHankakuKana,
textlintRuleNoInsertDroppingSa,
textlintRuleNoInsertRe,
textlintRuleNoKangxiRadicals,
textlintRuleNoMixedZenkakuAndHankakuAlphabet,
textlintRuleNoZeroWidthSpaces,
textlintRulePreferTariTari,
textlintRulePresetJapanese,
textlintRulePresetJaSpacing,
textlintRulePresetJaTechnicalWriting,
textlintRulePresetJTFStyle,
textlintRuleSentenceLength,
} from "./deps.ts";
import type { TextlintResult } from "./deps.ts";
import type { LintOption } from "./lintOptions.ts";
const kernel = new TextlintKernel();
const lint = ({
lintOption,
text,
}: {
lintOption: LintOption;
text: string;
}): Promise<TextlintResult> =>
kernel.lintText(text, {
ext: '.txt',
filterRules: [
{
ruleId: 'urls',
rule: textlintFilterRuleURLs,
},
],
plugins: [
{
pluginId: 'text',
plugin: textlintPluginText,
},
],
rules: [
...(lintOption.presetJaSpacing
? Object.keys(textlintRulePresetJaSpacing.rules).map((key) => ({
ruleId: key,
rule: textlintRulePresetJaSpacing.ruleskey,
options:
lintOption.presetJaSpacing?.key ?? textlintRulePresetJaSpacing.rulesConfigkey,
}))
: []),
...Object.keys(textlintRulePresetJapanese.rules)
.filter((key) => !'sentence-length'.includes(key))
.map((key) => ({
ruleId: key,
rule: textlintRulePresetJapanese.ruleskey,
options: textlintRulePresetJapanese.rulesConfigkey,
})),
...(lintOption.presetJaTechnicalWriting
? Object.keys(textlintRulePresetJaTechnicalWriting.rules)
.filter((key) => !'sentence-length'.includes(key))
.map((key) => ({
ruleId: key,
rule: textlintRulePresetJaTechnicalWriting.ruleskey,
options:
lintOption.presetJaTechnicalWriting?.key ??
textlintRulePresetJaTechnicalWriting.rulesConfigkey,
}))
: []),
...(lintOption.presetJTFStyle
? Object.keys(textlintRulePresetJTFStyle.rules).map((key) => ({
ruleId: key,
rule: textlintRulePresetJTFStyle.ruleskey,
options:
lintOption.presetJTFStyle?.key ?? textlintRulePresetJTFStyle.rulesConfigkey,
}))
: []),
...(lintOption.generalNovelStyleJa
? [
{
ruleId: 'general-novel-style-ja',
rule: textlintRuleGeneralNovelStyleJa,
options:
typeof lintOption.generalNovelStyleJa === 'object' &&
lintOption.generalNovelStyleJa !== null
? lintOption.generalNovelStyleJa
: undefined,
},
]
: []),
{
ruleId: 'ja-hiragana-daimeishi',
rule: textlintRuleJaHiraganaDaimeishi,
},
{
ruleId: 'ja-hiragana-fukushi',
rule: textlintRuleJaHiraganaFukushi,
},
{
ruleId: 'ja-hiragana-hojodoushi',
rule: textlintRuleJaHiraganaHojodoushi,
},
{
ruleId: 'ja-hiragana-keishikimeishi',
rule: textlintRuleJaHiraganaKeishikimeishi,
},
{
ruleId: 'ja-joyo-or-jinmeiyo-kanji',
rule: textlintRuleJaJoyoOrJinmeiyoKanji,
},
...(lintOption.jaKyoikuKanji
? [
{
ruleId: 'ja-kyoiku-kanji',
rule: textlintRuleJaKyoikuKanji,
options:
typeof lintOption.jaKyoikuKanji === 'object' && lintOption.jaKyoikuKanji !== null
? lintOption.jaKyoikuKanji
: undefined,
},
]
: []),
...(lintOption.jaNoMixedPeriod
? [
{
ruleId: 'ja-no-mixed-period',
rule: textlintRuleJaNoMixedPeriod,
options:
typeof lintOption.jaNoMixedPeriod === 'object' &&
lintOption.jaNoMixedPeriod !== null
? lintOption.jaNoMixedPeriod
: undefined,
},
]
: []),
{
ruleId: 'ja-no-redundant-expression',
rule: textlintRuleJaNoRedundantExpression,
},
{
ruleId: 'ja-no-successive-word',
rule: textlintRuleJaNoSuccessiveWord,
options: {
allow: ['/\\u2000-\\u2DFF\\u2E00-\\u33FF\\uF900-\\uFFFD/'],
},
},
...(lintOption.jaNoWeakPhrase
? [
{
ruleId: 'ja-no-weak-phrase',
rule: textlintRuleJaNoWeakPhrase,
options:
typeof lintOption.jaNoWeakPhrase === 'object' && lintOption.jaNoWeakPhrase !== null
? lintOption.jaNoWeakPhrase
: undefined,
},
]
: []),
{
ruleId: 'ja-unnatural-alphabet',
rule: textlintRuleJaUnnaturalAlphabet,
},
...(lintOption.maxAppearenceCountOfWords
? [
{
ruleId: 'max-appearence-count-of-words',
rule: textlintRuleMaxAppearenceCountOfWords,
options:
typeof lintOption.maxAppearenceCountOfWords === 'object' &&
lintOption.maxAppearenceCountOfWords !== null
? lintOption.maxAppearenceCountOfWords
: undefined,
},
]
: []),
{
ruleId: 'no-doubled-conjunctive-particle-ga',
rule: textlintRuleNoDoubledConjunctiveParticleGa,
},
{
ruleId: 'no-dropping-i',
rule: textlintRuleNoDroppingI,
},
...(lintOption.noFiller
? [
{
ruleId: 'no-filler',
rule: textlintRuleNoFiller,
options:
typeof lintOption.noFiller === 'object' && lintOption.noFiller !== null
? lintOption.noFiller
: undefined,
},
]
: []),
{
ruleId: 'no-hankaku-kana',
rule: textlintRuleNoHankakuKana,
},
{
ruleId: 'no-insert-dropping-sa',
rule: textlintRuleNoInsertDroppingSa,
},
{
ruleId: 'no-insert-re',
rule: textlintRuleNoInsertRe,
},
{
ruleId: 'no-kangxi-radicals',
rule: textlintRuleNoKangxiRadicals,
},
{
ruleId: 'no-mixed-zenkaku-and-hankaku-alphabet',
rule: textlintRuleNoMixedZenkakuAndHankakuAlphabet,
},
{
ruleId: 'no-zero-width-spaces',
rule: textlintRuleNoZeroWidthSpaces,
},
{
ruleId: 'prefer-tari-tari',
rule: textlintRulePreferTariTari,
},
{
ruleId: 'sentence-length',
rule: textlintRuleSentenceLength,
options: {
exclusionPatterns: [
// This line is under the CC BY-SA 4.0.
'/https?:\\/\\/(www\\.)?-a-zA-Z0-9@:%._\\+~#={1,256}\\.a-zA-Z0-9(){1,6}\\b(-a-zA-Z0-9()@:%_\\+.~#?&//=*)/',
],
},
},
],
});
export { lint };
export type { LintOption };
外部依存しているmodules
https://cdn.esm.sh/v61/re2@1.15.4/deno/re2.js のbuildに失敗してしまっている
https://esm.sh/textlint-filter-rule-urls@1.0.2 のimport pathに含まれているmodule
https://esm.sh/re2 ももちろんだめ
code:error
/* esm.sh - error */
throw new Error("esm.sh " + "parseCJSModuleExports: Can't resolve './build/Release/re2' in '/tmp/esm-build-68a4b25e913c8e21b60dd845fc4ef83bbf7c8b4f-b91bbc49/node_modules/re2'");
export default null;
url-regex-safeというmoduleの中で使われているらしい
ちょうどREADMEにこの件のの注意書きがあったhttps://github.com/spamscanner/url-regex-safe#browser
Since RE2 is not made for the browser, it will not be used, and therefore CVE-2020-7661 is still an issue on the client-side. However it is not severe since the most it would do is crash the browser tab (as on the Node.js side it would have crashed the entire process and thrown an out of memory exception).
browserから使うにはhttps://unpkg.com/url-regex-safe@3.0.0/dist/url-regex-safe.js を使うしかないが、ESModuleじゃないんだよな……
書き換えるのが面倒だ……
textlint-filter-rule-urls/src/textlintFilterRuleURLsModule.tsを書き換えるほうが手っ取り早いな
url-regex-safeに相当する機能を用意しないといけない
仕方ない。コードを書き換えよう
url-regex-safe-deno
from https://raw.githubusercontent.com/textlint-rule/textlint-filter-rule-urls/4ff7bafb8818f7045e3d9fb3c65bcadffabde2ea/src/textlintFilterRuleURLsModule.ts
code:textlint-filter-fule-urls.ts
import type { TextlintFilterRuleModule } from "https://cdn.esm.sh/v61/@textlint/types@12.1.0/lib/src/index.d.ts";
import { urlRegexSafe } from "../url-regex-safe-deno/mod.ts";
const textlintFilterRuleURLsModule: TextlintFilterRuleModule = ({
Syntax,
getSource,
shouldIgnore,
}) => ({
Syntax.Document: (node) => {
const regex: RegExp = urlRegexSafe();
const text = getSource(node);
let url;
while ((url = regex.exec(text))) {
shouldIgnore([url.index, url.index + url0.length], {});
}
},
});
export { textlintFilterRuleURLsModule as default };
code:deps_scrapbox.ts
export type { Scrapbox } from "https://raw.githubusercontent.com/scrapbox-jp/types/0.0.8/mod.ts";
code:deps.ts
export { TextlintKernel } from "https://esm.sh/@textlint/kernel@12.1.0";
export type { TextlintResult } from "https://esm.sh/@textlint/kernel@12.1.0";
export {
default as textlintPluginText
} from "https://esm.sh/@textlint/textlint-plugin-text@12.1.0";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleNoDroppingI
} from "https://esm.sh/@textlint-ja/textlint-rule-no-dropping-i@2.0.0";
export {
default as textlintRuleNoFiller
} from "https://esm.sh/@textlint-ja/textlint-rule-no-filler@1.1.0";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleNoInsertDroppingSa
} from "https://esm.sh/@textlint-ja/textlint-rule-no-insert-dropping-sa@2.0.1";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleNoInsertRe
} from "https://esm.sh/@textlint-ja/textlint-rule-no-insert-re@1.0.0";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleNoZeroWidthSpaces
} from "https://esm.sh/textlint-rule-no-zero-width-spaces@1.0.1";
export {
default as textlintFilterRuleURLs
//} from "https://esm.sh/textlint-filter-rule-urls@1.0.2";
} from "./textlint-filter-fule-urls.ts";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleGeneralNovelStyleJa
} from "https://esm.sh/textlint-rule-general-novel-style-ja";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleJaHiraganaDaimeishi
} from "https://esm.sh/textlint-rule-ja-hiragana-daimeishi";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleJaHiraganaFukushi
} from "https://esm.sh/textlint-rule-ja-hiragana-fukushi";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleJaHiraganaHojodoushi
} from "https://esm.sh/textlint-rule-ja-hiragana-hojodoushi";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleJaHiraganaKeishikimeishi
} from "https://esm.sh/textlint-rule-ja-hiragana-keishikimeishi";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleJaJoyoOrJinmeiyoKanji
} from "https://esm.sh/textlint-rule-ja-joyo-or-jinmeiyo-kanji@1.0.3";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleJaKyoikuKanji
} from "https://esm.sh/textlint-rule-ja-kyoiku-kanji";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleJaNoMixedPeriod
} from "https://esm.sh/textlint-rule-ja-no-mixed-period";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleJaNoRedundantExpression
} from "https://esm.sh/textlint-rule-ja-no-redundant-expression";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleJaNoSuccessiveWord
} from "https://esm.sh/textlint-rule-ja-no-successive-word";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleJaNoWeakPhrase
} from "https://esm.sh/textlint-rule-ja-no-weak-phrase";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleJaUnnaturalAlphabet
} from "https://esm.sh/textlint-rule-ja-unnatural-alphabet";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleMaxAppearenceCountOfWords
} from "https://esm.sh/textlint-rule-max-appearence-count-of-words";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleNoDoubledConjunctiveParticleGa
} from "https://esm.sh/textlint-rule-no-doubled-conjunctive-particle-ga";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleNoHankakuKana
} from "https://esm.sh/textlint-rule-no-hankaku-kana";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleNoKangxiRadicals
} from "https://esm.sh/textlint-rule-no-kangxi-radicals";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleNoMixedZenkakuAndHankakuAlphabet
} from "https://esm.sh/textlint-rule-no-mixed-zenkaku-and-hankaku-alphabet";
// @ts-ignore 型が定義されていない。
export {
default as textlintRulePreferTariTari
} from "https://esm.sh/textlint-rule-prefer-tari-tari";
// @ts-ignore 型が定義されていない。
export {
default as textlintRulePresetJaSpacing
} from "https://esm.sh/textlint-rule-preset-ja-spacing";
// @ts-ignore 型が定義されていない。
export {
default as textlintRulePresetJaTechnicalWriting
} from "https://esm.sh/textlint-rule-preset-ja-technical-writing";
// @ts-ignore 型が定義されていない。
export {
default as textlintRulePresetJapanese
} from "https://esm.sh/textlint-rule-preset-japanese";
// @ts-ignore 型が定義されていない。
export {
default as textlintRulePresetJTFStyle
} from "https://esm.sh/textlint-rule-preset-jtf-style";
// @ts-ignore 型が定義されていない。
export {
default as textlintRuleSentenceLength
} from "https://esm.sh/textlint-rule-sentence-length";
textlintのオプションの型定義
/hata6502/lintOptionを参考に作った
説明はそれぞれのrepoから引用した
2022-01-10 07:00:25 型定義作るのに時間がかかりそうなので一旦スキップ
code:lintOptions.ts
export interface LintOption{
presetJaSpacing?: boolean | PresetJaSpacingInit;
presetJaTechnicalWriting?: boolean | PresetJaTechnicalWritingInit;
presetJTFStyle?: boolean | PresetJTFStyleInit;
generalNovelStyleJa?: boolean | GeneralNovelStyleJaInit;
jaKyoikuKanji?: boolean | JaKyoikuKanjiInit;
jaNoMixedPeriod?: boolean | JaNoMixedPeriodInit;
jaNoWeakPhrase?: boolean | JaNoWeakPhraseInit;
maxAppearenceCountOfWords?: boolean | MaxAppearenceCountOfWords;
noFiller?: boolean | NoFillerInit;
}
textlint-rule-preset-ja-spacing
日本語周りにおけるスペースの有無を決定する textlint ルールプリセットを提供します。
code:lintOptions.ts
export interface PresetJaSpacingInit {
"ja-space-between-half-and-full-width"?: {
space?: "never" | "always";
exceptPunctuation?: boolean;
lintStyledNode?: boolean;
};
"ja-space-around-code"?: boolean | {
before?: boolean;
after?: boolean;
};
"ja-no-space-between-full-width"?: boolean;
"ja-nakaguro-or-halfwidth-space-between-katakana"?: boolean;
"ja-no-space-around-parentheses"?: boolean;
"ja-space-after-exclamation"?: boolean;
"ja-space-after-question"?: boolean;
}
textlint-rule-preset-ja-technical-writing
技術文書向けの textlint ルールプリセットです。
code:lintOptions.ts
export interface PresetJaTechnicalWritingInit {
"sentence-length"?: boolean | {
max?: number;
skipPatterns?: string[];
skipUrlStringLink?: boolean;
};
"max-comma"?: {
max: number;
};
"max-ten"?: {
max: number;
};
"max-kanji-continuous-len"?: {
max: number;
},
"arabic-kanji-numbers"?: boolean;
"no-mix-dearu-desumasu"?: {
preferInHeader: string;
preferInBody: string;
preferInList: string;
strict: boolean;
};
"ja-no-mixed-period": {
periodMark: string;
};
"no-double-negative-ja"?: boolean;
"no-dropping-the-ra"?: boolean;
"no-doubled-conjunctive-particle-ga"?: boolean;
"no-doubled-conjunction"?: boolean;
"no-doubled-joshi"?: {
min_interval: number;
};
"no-nfd"?: boolean;
"no-invalid-control-character"?: boolean;
"no-zero-width-spaces"?: boolean;
"no-exclamation-question-mark"?: boolean;
"no-hankaku-kana"?: boolean;
"ja-no-weak-phrase"?: boolean;
"ja-no-successive-word"?: boolean;
"ja-no-abusage"?: boolean;
"ja-no-redundant-expression"?: boolean;
"ja-unnatural-alphabet"?: boolean;
"no-unmatched-pair"?: boolean;
}
textlint-rule-preset-JTF-style
JTF 日本語標準スタイルガイド(翻訳用) for textlint.
code:lintOptions.ts
export interface PresetJTFStyleInit {
}
textlint-rule-general-novel-style-ja
日本の小説における一般的な作法に従うための textlint ルールです。
code:lintOptions.ts
export interface GeneralNovelStyleJaInit {
}
textlint-rule-ja-kyoiku-kanji
教育漢字であることをチェックする textlint ルール
code:lintOptions.ts
export interface JaKyoikuKanjiInit {
}
textlint-rule-ja-no-mixed-period
文末の句点(。)の統一 OR 抜けをチェックする textlint ルール
code:lintOptions.ts
export interface JaNoMixedPeriodInit {
}
textlint-rule-ja-no-weak-phrase
弱い日本語表現の利用を禁止する textlint ルール
code:lintOptions.ts
export interface JaNoWeakPhraseInit {
}
textlint-rule-max-appearence-count-of-words
textlint rule that check maximum appearance count of words in paragraph.
code:lintOptions.ts
export interface MaxAppearenceCountOfWords {
}
textlint-rule-no-filler
「ええと」「あの」「まあ」などのフィラー(つなぎ表現)を禁止する textlint ルール
code:lintOptions.ts
export interface NoFillerInit {
}
#2022-01-10 06:25:27