Skip to content

refactor: migrate to TypeScrtipt #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@
"textlintrule"
],
"devDependencies": {
"textlint-scripts": "^2.1.0"
"@textlint/types": "^1.2.2",
"@types/node": "^12.11.1",
"textlint-scripts": "^3.0.0",
"ts-node": "^8.4.1",
"typescript": "^3.6.4"
},
"dependencies": {
"kuromojin": "^1.2.1",
"sentence-splitter": "^3.0.11",
"kuromojin": "^2.0.0",
"sentence-splitter": "^3.1.0",
"textlint-rule-helper": "^2.1.1",
"textlint-util-to-string": "^2.1.1"
"textlint-util-to-string": "^3.0.0"
}
}
38 changes: 24 additions & 14 deletions src/no-doubled-joshi.js → src/no-doubled-joshi.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
// LICENSE : MIT
"use strict";
import {RuleHelper} from "textlint-rule-helper";
import {getTokenizer} from "kuromojin";
import {splitAST as splitSentences, Syntax as SentenceSyntax} from "sentence-splitter";
import StringSource from "textlint-util-to-string";
import { RuleHelper } from "textlint-rule-helper";
import { splitAST as splitSentences, Syntax as SentenceSyntax, SentenceNode } from "sentence-splitter";
import { getTokenizer, KuromojiToken } from "kuromojin";
import {
is助詞Token, is読点Token,
concatJoishiTokens,
createKeyFromKey,
restoreToSurfaceFromKey
} from "./token-utils";
import { TxtNode } from "@textlint/ast-node-types";
import { TextlintRuleModule } from "@textlint/types";
import { StringSource } from "textlint-util-to-string";

/**
* Create token map object
Expand All @@ -19,7 +21,7 @@ import {
* @param tokens
* @returns {*}
*/
function createSurfaceKeyMap(tokens) {
function createSurfaceKeyMap(tokens: KuromojiToken[]): { [index: string]: KuromojiToken[] } {
// 助詞のみを対象とする
return tokens.filter(is助詞Token).reduce((keyMap, token) => {
// "は:助詞.係助詞" : [token]
Expand All @@ -29,10 +31,10 @@ function createSurfaceKeyMap(tokens) {
}
keyMap[tokenKey].push(token);
return keyMap;
}, {});
}, {} as { [index: string]: KuromojiToken[] });
}

function matchExceptionRule(tokens) {
function matchExceptionRule(tokens: KuromojiToken[]) {
let token = tokens[0];
// "の" の重なりは例外
if (token.pos_detail_1 === "連体化") {
Expand All @@ -59,6 +61,14 @@ const defaultOptions = {
separatorChars: ["。", "?", "!", "?", "!"]
};


export interface Options {
min_interval?: number;
strict?: boolean;
allow?: string[];
separatorChars?: string[]
}

/*
1. Paragraph Node -> text
2. text -> sentences
Expand All @@ -67,26 +77,25 @@ const defaultOptions = {

TODO: need abstraction
*/
module.exports = function (context, options = {}) {
const report: TextlintRuleModule<Options> = function (context, options = {}) {
const helper = new RuleHelper(context);
// 最低間隔値
const minInterval = options.min_interval || defaultOptions.min_interval;
const isStrict = options.strict || defaultOptions.strict;
const allow = options.allow || defaultOptions.allow;
const separatorChars = options.separatorChars || defaultOptions.separatorChars;
const {Syntax, report, RuleError} = context;
return {
[Syntax.Paragraph](node) {
if (helper.isChildNode(node, [Syntax.Link, Syntax.Image, Syntax.BlockQuote, Syntax.Emphasis])) {
return;
}
const isSentenceNode = node => {
const isSentenceNode = (node: TxtNode): node is SentenceNode => {
return node.type === SentenceSyntax.Sentence;
};
const txtParentNode = splitSentences(node);
const sentences = txtParentNode.children.filter(isSentenceNode);
return getTokenizer().then(tokenizer => {
const checkSentence = (sentence) => {
return getTokenizer().then((tokenizer: any) => {
const checkSentence = (sentence: SentenceNode) => {
const sentenceSource = new StringSource(sentence);
const text = sentenceSource.toString();
const tokens = tokenizer.tokenizeForSentence(text);
Expand Down Expand Up @@ -115,7 +124,7 @@ module.exports = function (context, options = {}) {
}
*/
Object.keys(joshiTokenSurfaceKeyMap).forEach(key => {
const tokens = joshiTokenSurfaceKeyMap[key];
const tokens: KuromojiToken[] = joshiTokenSurfaceKeyMap[key];
const joshiName = restoreToSurfaceFromKey(key);
// check allow
if (allow.indexOf(joshiName) >= 0) {
Expand Down Expand Up @@ -148,8 +157,9 @@ module.exports = function (context, options = {}) {
});
});
};
sentences.forEach(checkSentence);
sentences.forEach(node => checkSentence(node))
});
}
}
};
export default report;
19 changes: 11 additions & 8 deletions src/token-utils.js → src/token-utils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
// LICENSE : MIT
"use strict";

import { KuromojiToken } from "kuromojin";

// 助詞どうか
export const is助詞Token = (token) => {
export const is助詞Token = (token: KuromojiToken) => {
// 結合しているtokenは助詞助詞のようになってるため先頭一致で見る
return token && /^助詞/.test(token.pos);
};

export const is読点Token = (token) => {
export const is読点Token = (token: KuromojiToken) => {
return token.surface_form === "、" && token.pos === "名詞";
};
/**
Expand All @@ -15,7 +18,7 @@ export const is読点Token = (token) => {
* @param {Object} bToken
* @returns {Object}
*/
const concatToken = (aToken, bToken) => {
const concatToken = (aToken: KuromojiToken, bToken: KuromojiToken) => {
aToken.surface_form += bToken.surface_form;
aToken.pos += bToken.pos;
aToken.pos_detail_1 += bToken.surface_form;
Expand All @@ -26,8 +29,8 @@ const concatToken = (aToken, bToken) => {
* @param {Array} tokens
* @returns {Array}
*/
export const concatJoishiTokens = (tokens) => {
const newTokens = [];
export const concatJoishiTokens = (tokens: KuromojiToken[]) => {
const newTokens: KuromojiToken[] = [];
tokens.forEach((token) => {
const prevToken = newTokens[newTokens.length - 1];
if (is助詞Token(token) && is助詞Token(prevToken)) {
Expand All @@ -41,11 +44,11 @@ export const concatJoishiTokens = (tokens) => {
// 助詞tokenから品詞細分類1までを元にしたkeyを作る
// http://www.unixuser.org/~euske/doc/postag/index.html#chasen
// http://chasen.naist.jp/snapshot/ipadic/ipadic/doc/ipadic-ja.pdf
export const createKeyFromKey = (token) => {
export const createKeyFromKey = (token: KuromojiToken) => {
// e.g.) "は:助詞.係助詞"
return `${token.surface_form}:${token.pos}.${token.pos_detail_1}`;
};
// keyからsurfaceを取り出す
export const restoreToSurfaceFromKey = (key) => {
export const restoreToSurfaceFromKey = (key: string) => {
return key.split(":")[0];
};
};
1 change: 0 additions & 1 deletion test/mocha.opts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import TextLintTester from "textlint-tester";
const rule = require("../src/no-doubled-joshi");
import rule from "../src/no-doubled-joshi";

const tester = new TextLintTester();
/*
`**`のような装飾は取り除かれてから評価されているので、
テストでの強調という意味合いのみで利用する。
*/
tester.run("no-double-joshi", rule, {

valid: [
"私は彼が好きだ",
"既存のコードの利用", // "の" の例外
Expand Down
22 changes: 22 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"compilerOptions": {
/* Basic Options */
"module": "commonjs",
"moduleResolution": "node",
"esModuleInterop": true,
"noEmit": true,
"skipLibCheck": true,
"target": "es2015",
/* Strict Type-Checking Options */
"strict": true,
/* Additional Checks */
/* Report errors on unused locals. */
"noUnusedLocals": true,
/* Report errors on unused parameters. */
"noUnusedParameters": true,
/* Report error when not all code paths in function return a value. */
"noImplicitReturns": true,
/* Report errors for fallthrough cases in switch statement. */
"noFallthroughCasesInSwitch": true
}
}
Loading