Skip to content
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
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@types/node": "^20.12.2",
"bun-types": "latest",
"esbuild": "^0.20.2",
"textlint-rule-preset-ja-technical-writing": "^12.0.2",
"textlint-scripts": "^14.0.4",
"textlint-tester": "^14.0.4",
"typescript": "^5.4.3",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
= textlint for Typst

== sentence-length

あいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえお。

== max-comma

組版処理システムの例としては、Tex (LaTeX), SATySFi, Typst, Twight, SILEなどがあります。

== max-ten

これは、これは、これは、これは、これはだめ。

== max-kanji-continuous-len

情報処理学会は、電気学会、照明学会、応用物理学会、映像情報メディア学会および電子情報通信学会とともに電気系6学会の1つに数えられる存在です。

== arabic-kanji-numbers

Fibonacci数列の十番目の項は55です。

1時的なファイルは`/tmp`に保存されます。

== no-mix-dearu-desumasu

今日はいい天気ですね。今日はいい天気である。

== no-mixed-period

これは問題ないです。

「これはセリフ」

english only

これは句点がありません

== no-double-negative-ja

それが事件の発端だったといえなくもない。

確かにそういった懸念はない事はない。

== no-dropping-the-ra

お刺身を食べれない。

== no-doubled-conjunctive-particle-ga

今日は早朝から出発したが、定刻には間に合わなかったが、無事会場に到着した。

== no-doubled-conjunction

かな漢字変換により漢字が多用される傾向がある。しかし漢字の多用が読みにくさをもたらす側面は否定できない。しかし、平仮名が多い文は間延びした印象を与える恐れもある。

== no-doubled-joshi

私は彼は好きだ。

== no-nfd

ホ゜ケット エンシ゛ン。

== no-exclamation-question-mark

技術文書では、感嘆符、疑問符は基本的には使用しないでください!

== no-hankaku-kana

半角カタカナを使用しないでください。

== no-weak-phrase

この表現には問題があるかもしれないです。

== no-successive-word

これは問題ない文章です。

これはは問題ある文章です。

これは問題あるある文章です。

== no-abusage

ウインドウ幅が可変すると、レイアウトが崩れる。

今朝起きた事件に法律を適応する。

== no-redundant-expression

これは省略することが可能です。

== ja-unnatural-alphabet

リイr−ス。

== no-unmatched-pair

これは(秘密)です。
174 changes: 174 additions & 0 deletions test/integration/linting.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import fs from "node:fs";
import path from "node:path";
import {
TextlintKernel,
type TextlintKernelRule,
type TextlintResult,
} from "@textlint/kernel";
// @ts-expect-error
import { rules, rulesConfig } from "textlint-rule-preset-ja-technical-writing";

import { beforeAll, describe, expect, it } from "vitest";

import typstPlugin from "../../src";

describe("linting", () => {
describe("smoke tests", () => {
describe("textlint-rule-preset-ja-technical-writing", () => {
let textlintResult: TextlintResult;

beforeAll(async () => {
const kernel = new TextlintKernel();
textlintResult = await kernel.lintText(
fs.readFileSync(
path.join(
__dirname,
"./fixtures/smoke/textlint-rule-preset-ja-technical-writing/main.typ",
),
"utf-8",
),
{
ext: ".typ",
plugins: [
{
pluginId: "typst",
plugin: typstPlugin,
},
],
rules: [
// Set each rule in the preset individually
...Object.entries(rules).map(
([id, rule]) =>
({
ruleId: `ja-technical-writing/${id}`,
rule: rule,
options: rulesConfig[id] || true,
}) as TextlintKernelRule,
),
],
},
);
});

// Rule test configurations
const ruleTests = [
{
ruleId: "sentence-length",
expectedMessage: "exceeds the maximum sentence length",
},
{
ruleId: "max-ten",
expectedMessage: '一つの文で"、"を4つ以上使用',
},
{
ruleId: "max-kanji-continuous-len",
expectedMessage: "漢字が7つ以上連続",
},
{
ruleId: "no-mix-dearu-desumasu",
expectedMessage: '"ですます"調 でなければなりません',
},
{
ruleId: "ja-no-mixed-period",
expectedMessage: '文末が"。"で終わっていません',
},
{
ruleId: "no-doubled-joshi",
expectedMessage: "一文に二回以上利用されている助詞",
},
{
ruleId: "no-dropping-the-ra",
expectedMessage: "ら抜き言葉を使用",
},
{
ruleId: "no-doubled-conjunctive-particle-ga",
expectedMessage: '逆接の接続助詞 "が" が二回以上使われています',
},
{
ruleId: "no-doubled-conjunction",
expectedMessage: "同じ接続詞(しかし)が連続",
},
{
ruleId: "no-exclamation-question-mark",
expectedMessage: 'Disallow to use "!"',
},
{
ruleId: "no-hankaku-kana",
expectedMessage: "Disallow to use 半角カタカナ",
},
{
ruleId: "ja-no-weak-phrase",
expectedMessage: '弱い表現: "かも" が使われています',
},
{
ruleId: "ja-no-successive-word",
expectedMessage: "が連続して2回使われています",
},
{
ruleId: "ja-no-redundant-expression",
expectedMessage: 'することが可能です"は冗長な表現',
},
{
ruleId: "ja-unnatural-alphabet",
expectedMessage: "不自然なアルファベット",
},
{
ruleId: "no-unmatched-pair",
expectedMessage: "Cannot find a pairing character for (",
},
];

// Special cases with multiple expected messages
const multiMessageTests = [
{
ruleId: "arabic-kanji-numbers",
expectedMessages: ["十番目 => 10番目", "1時的 => 一時的"],
},
{
ruleId: "no-double-negative-ja",
expectedMessages: [
"二重否定: 〜なくもない",
"二重否定: 〜ないことはない",
],
},
{
ruleId: "no-nfd",
expectedMessages: ['ホ゜" => "ポ"', 'シ゛" => "ジ"'],
},
{
ruleId: "ja-no-abusage",
expectedMessages: ["可変する", "適用"],
},
];

const getViolations = (ruleId: string) => {
return textlintResult.messages.filter(
(message) => message.ruleId === `ja-technical-writing/${ruleId}`,
);
};

// Single message tests
for (const { ruleId, expectedMessage } of ruleTests) {
it(`should detect ${ruleId} violations`, () => {
const violations = getViolations(ruleId);
expect(violations.length).toBeGreaterThan(0);
expect(violations[0].message).toContain(expectedMessage);
});
}

// Multi-message tests
for (const { ruleId, expectedMessages } of multiMessageTests) {
it(`should detect ${ruleId} violations`, () => {
const violations = getViolations(ruleId);
expect(violations.length).toBeGreaterThan(0);

for (const expectedMessage of expectedMessages) {
expect(
violations.some((v) => v.message.includes(expectedMessage)),
).toBe(true);
}
});
}
});
});
});
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion test/parsing.test.ts → test/unit/parsing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import path from "node:path";
// parse all fixture and should has
import { test } from "@textlint/ast-tester";
import { describe, expect, it } from "vitest";
import { convertTypstSourceToTextlintAstObject } from "../src/typstToTextlintAst";
import { convertTypstSourceToTextlintAstObject } from "../../src/typstToTextlintAst";

describe("parsing", () => {
const fixtureDir = path.join(__dirname, "fixtures");
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
extractRawSourceByLocation,
getRawTypstAstString,
paragraphizeTextlintAstObject,
} from "../src/typstToTextlintAst";
} from "../../src/typstToTextlintAst";

const typstSource = fs.readFileSync(
path.join(__dirname, "example.typ"),
Expand Down
2 changes: 1 addition & 1 deletion test/update-fixtures.ts → test/unit/update-fixtures.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from "node:fs";
import path from "node:path";
import { test } from "@textlint/ast-tester";
import { convertTypstSourceToTextlintAstObject } from "../src/typstToTextlintAst";
import { convertTypstSourceToTextlintAstObject } from "../../src/typstToTextlintAst";

const fixtureDir = path.join(__dirname, "fixtures");
for (const filePath of fs.readdirSync(fixtureDir)) {
Expand Down