Skip to content

Commit

Permalink
feat: no perion on paragraph end (#4)
Browse files Browse the repository at this point in the history
* feat: no perion on paragraph end

* fix: implementation
  • Loading branch information
kazupon authored May 22, 2024
1 parent cb793c3 commit 829a865
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 60 deletions.
57 changes: 45 additions & 12 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
- [Pull Request Guidelines](#pull-request-guidelines)
- [Work Step Example](#work-step-example)
- [Development Setup](#development-setup)
- [Commonly used NPM scripts](#commonly-used-npm-scripts)
- [Lint](#lint)
- [Code Auto fix](#code-auto-fix)
- [Build](#build)
- [Tests](#tests)
- [Other script tasks](#other-script-tasks)

## Issue Reporting Guidelines

Expand All @@ -27,7 +31,7 @@

- It's OK to have multiple small commits as you work on the PR - we will let GitHub automatically squash it before merging.

- Make sure `npm test` passes. (see [development setup](#development-setup))
- Make sure all script tasks passes. (see [development setup](#development-setup))

- If adding new feature:

Expand All @@ -51,19 +55,48 @@

After cloning the repo, run:

$ npm install
```sh
npm install
```

### Commonly used NPM scripts
### Lint

# lint source codes
$ npm run lint
lint checks for the following:

# code auto fix
$ npm run fix
- Prettier follows the format of this project
- ESLint follows the rules of this project

# run the full test suite, include linting
$ npm test
```sh
npm run lint
```

There are some other scripts available in the `scripts` section of the `package.json` file.
### Code Auto fix

The following commands fix those detected by Prettier and ESLint described earlier, using their respective fix functions.

```sh
npm run fix
```

### Build

Builds source codes for publish to the `lib` folder.

You can write ES2015+ source codes in `src/` folder.

**Please make sure to have this pass successfully before submitting a PR.** Although the same tests will be run against your PR on the CI server, it is better to have it working locally beforehand.
```sh
npm run build
```

### Tests

Run test code in `test` folder.
Test textlint rule by [textlint-tester](https://github.com/textlint/textlint-tester):

```sh
npm test
```

### Other script tasks

There are some other scripts available in the `scripts` section of the `package.json` file.
59 changes: 57 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,63 @@

textlint rule for no period on paragraph end

> [!WARNING]
> This textlint rule is WIP
## 📖 Rule Details

This rule does not allow punctuation at the end of a paragraph. This use case is used, for example, when you want to express rhythm or lingering phrases in a sentence, such as in the Japanese word "体言止め"(ending a sentence with a noun).

### NG ✗

```
This is simple paragraph.
This paragraph has multiple sentences. First sentence is here. And the last sentence is here.
これはシンプルな段落。
この段落には複数の文がある。これが最初、そしてこれが最後の文。
```

### OK ✓

```
This is simple paragraph
This paragraph has multiple sentences. First sentence is here. And the last sentence is here
これはシンプルな段落
この段落には複数の文がある。これが最初、そしてこれが最後の文
```

## 💿 Installlation

Install with [npm](https://www.npmjs.com/):

```sh
npm install textlint-rule-no-period-on-paragraph-end
```

## 🚀 Usages

Via `.textlintrc.json`(Recommended):

```json
{
"rules": {
"no-period-on-paragraph-end": true
}
}
```

Via CLI

```sh
textlint --rule no-period-on-paragraph-end README.md
```

## 🙌 Contributing guidelines

If you are interested in contributing to `textlint-rule-no-period-on-paragraph-end`, I highly recommend checking out [the contributing guidelines](/CONTRIBUTING.md) here. You'll find all the relevant information such as [how to make a PR](/CONTRIBUTING.md#pull-request-guidelines), [how to setup development](/CONTRIBUTING.md#development-setup)) etc., there.

## ©️ License

Expand Down
14 changes: 14 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@ export default [
project: true,
tsconfigRootDir: import.meta.dirname
}
},
rules: {
'@typescript-eslint/no-unused-vars': [
'error',
{
args: 'all',
argsIgnorePattern: '^_',
caughtErrors: 'all',
caughtErrorsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_',
varsIgnorePattern: '^_',
ignoreRestSiblings: true
}
]
}
}
]
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@
},
"lint-staged": {
"*.{json,md,yml}": [
"prettier --write"
"prettier --write --ignore-unknown"
],
"*.{js,mjs,cjs}": [
"prettier --write",
"prettier --write --ignore-unknown",
"eslint --fix"
],
"*.ts?(x)": [
"prettier --parser=typescript --write",
"prettier --parser=typescript --write --ignore-unknown",
"eslint --fix"
]
}
Expand Down
35 changes: 15 additions & 20 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
import type { TextlintRuleModule } from '@textlint/types'

export interface Options {
// If node's text includes allowed text, does not report.
allows?: string[]
}
interface Options {}

const PERIODS = ['.', '。'] as const

const report: TextlintRuleModule<Options> = (context, options = {}) => {
const report: TextlintRuleModule<Options> = (context, _options = {}) => {
const { Syntax, RuleError, report, getSource, locator } = context
const allows = options.allows ?? []
return {
[Syntax.Str](node) {
// "Str" node
const text = getSource(node) // Get text
if (allows.some(allow => text.includes(allow))) {
return
}
const matches = text.matchAll(/bugs/g)
for (const match of matches) {
const index = match.index ?? 0
const matchRange = [index, index + match[0].length] as const
const ruleError = new RuleError('Found bugs.', {
padding: locator.range(matchRange)
})
report(node, ruleError)
[Syntax.Paragraph](node) {
const text = getSource(node)
const period = PERIODS.find(period => text.endsWith(period))
if (period) {
const targetRange = [text.length - 1, text.length] as const
report(
node,
new RuleError('The paragraph has a period.', {
padding: locator.range(targetRange)
})
)
}
}
}
Expand Down
66 changes: 43 additions & 23 deletions test/index-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,62 @@ import TextLintTester from 'textlint-tester'
import rule from '../src/index'

const tester = new TextLintTester()
// ruleName, rule, { valid, invalid }
tester.run('rule', rule, {

tester.run('no-period-on-paragraph-end', rule, {
valid: [
// no problem
'text',
{
text: 'It is bugs, but it should be ignored',
options: {
allows: ['it should be ignored']
}
}
'This is simple paragraph',
'This paragraph has multiple sentences. First sentence is here. And the last sentence is here',
'これはシンプルな段落',
'この段落には複数の文がある。これが最初、そしてこれが最後の文'
],
invalid: [
// single match
// simple paragraph
{
text: 'It is bugs.',
text: 'This is simple paragraph.',
errors: [
{
message: 'Found bugs.',
range: [6, 10]
message: 'The paragraph has a period.',
range: [24, 25]
}
]
},
// multiple match
// multiple sentences in paragraph
{
text: `It has many bugs.
One more bugs`,
text: 'This paragraph has multiple sentences. First sentence is here. And the last sentence is here.',
errors: [
{
message: 'Found bugs.',
range: [12, 16]
},
message: 'The paragraph has a period.',
range: [92, 93]
}
]
},
// simple paragraph in Japanese
{
text: 'これはシンプルな段落。',
errors: [
{
message: 'The paragraph has a period.',
range: [10, 11]
}
]
},
// multiple sentences in paragraph in Japanese
{
text: 'この段落には複数の文がある。これが最初、そしてこれが最後の文。',
errors: [
{
message: 'The paragraph has a period.',
range: [30, 31]
}
]
},
// mixing English and Japanese
{
text: 'この段落には複数の文がある。First sentence is here. そしてこれが最後の文。',
errors: [
{
message: 'Found bugs.',
range: [28, 32]
message: 'The paragraph has a period.',
range: [48, 49]
}
]
}
Expand Down

0 comments on commit 829a865

Please sign in to comment.