• Stars
    star
    235
  • Rank 171,079 (Top 4 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 5 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A linting tool for Chinese language.

logo zhlint

A linting tool for Chinese text content.

How to install

You could easily install zhlint through npm or yarn:

# install through npm
npm install zhlint -g

# or through yarn
yarn global add zhlint

# or through pnpm
pnpm add zhlint -g

Usage

As CLI

# glob files, lint them, and print validation report,
# and exit with code `1` if there is any error found.
zhlint <file-pattern>

# glob files and fix their all possilbly found errors.
zhlint <file-pattern> --fix

# lint the file and output fixed content into another file
zhlint <input-file-path> --output=<output-file-path>

# print usage info
zhlint --help

The validation report might look like this:

Advanced usage

zhlint also supports rc and ignore config files for custom rules:

# .zhlintrc by default
zhlint --config <filepath>

# .zhlintignore by default
zhlint --ignore <filepath>

# current directory by default
zhlint --dir <path>

In the config file, you can write a JSON like:

{
  "preset": "default",
  "rules": {
    "adjustedFullWidthPunctuation": ""
  }
}

For more details, see supported rules.

In the ignore file, you can write some lines of ignored cases like:

( , )

For more details, see setup ignored cases.

As Node.js package

const { run, report } = require('zhlint')

const value = '自动在中文和English之间加入空格'
const options = { rules: { preset: 'default' } }
const output = run(value, options)

// print '自动在中文和 English 之间加入空格''
console.log(output.result)

// print validation report
report([output])

And the format of validation report is more like this:

1:6 - 此处中英文内容之间需要一个空格

自动在中文和English之间加入空格
      ^

1:13 - 此处中英文内容之间需要一个空格

自动在中文和English之间加入空格
             ^
Invalid files:
- foo.md

Found 2 errors.

Advanced usage

zhlint also supports rc and ignore config files for custom rules:

const { readRc, runWithConfig } = require('zhlint')

const value = '自动在中文和English之间加入空格'

const dir = '...' // the target directory path
const configPath = '...' // the config file path
const ignorePath = '...' // the ignore file path

const config = readRc(dir, configPath, ignorePath)
const output = runWithConfig(value, config)

// ... further actions

As a standalone package

You could find a JavaScript file dist/zhlint.js as a standalone version. To use it, for example, you can directly add it into your browser as a <script> tag. Then there would be a global variable zhlint for you.

API

  • run(str: string, options?: Options): Result: Lint a certain file.
    • parameters:
      • str: The text content you want to lint.
      • options: Some options to config.
    • returns:
      • The result of a single piece of input string. It contains fixed text content as value and the infor of all validations.
  • report(results: Result[], logger?: Console): void: Print out the validation reports for each file.
    • parameters:
      • results: An array for all linted results.
      • logger: The logger instance, by default it's console in Node.js/browser.
  • readRc: (dir: string, config: string, ignore: string, logger?: Console) => Config: Read config from rc file(s). For rc (run command).
  • runWithConfig(str: string, config: Config): Result: Lint a certain file with rc config. For rc (run command).

Options

Customize your own linting config and other advanced options.

type Options = {
  rules?: RuleOptions
  hyperParse?: string[]
  ignoredCases?: IgnoredCase[]
  logger?: Console
}
  • rules: customize the linting config. It could be undefined which means linting nothing. It could be { preset: 'default' } which just uses the default config. For more details of RuleOptions, please see supported rules
  • hyperParse: customize the hyper parser by their names. It could be undefined which means just use default ignored cases parser, Markdown parser and the Hexo tags parser.
  • ignoredCases: provide exception cases which you would like to skip.
  • logger: same to the parameter in report(...).

RC Config

  • preset: string (optional)
  • rules: RuleOptions without the preset field. (optional)
  • hyperParsers: string[] (optional)
  • ignores: string[] and the priority is lower than .zhlintignore. (optional)

Output

type Result = {
  // the basic info and availability of the file
  file?: string
  disabled: boolean

  // the original content of the file
  origin: string

  // all the error messages
  validations: Validation[]
}

type Validation = {
  message: string
  index: number
  length: number
}
  • Result
    • file: The file name. It's an optional field which is only used in CLI.
    • origin: the original text content.
    • result: the finally fixed text content.
    • validations: All the validation information.
  • Validation
    • index: The index of the target token in the input string.
    • length: The length of the target token in the input string.
    • message: The description of this validation in natural language.

Advanced usage

Features

Markdown syntax support

We support lint your text content in Markdown syntax by default. For example:

run('自动在_中文_和**English**之间加入空格', options)

It will analyse the Markdown syntax first and extract the pure text content and do the lint job. After that the fixed pure text content could be replaced back to the raw Markdown string and returned as the output value in result.

Hexo tags syntax support

Specially, we support Hexo tags syntax just because when we use Hexo to build Vue.js website, the markdown source files more or less include special tags like that so got the unpredictable result.

As a result, we additionally skip the Hexo-style tags by default. For example:

run(
  '现在过滤器只能用在插入文本中 (`{% raw %}{{ }}{% endraw %}` tags)。',
  options
)

Setup ignored cases

In some real cases we have special text contents not follow the rules by reason. So we could ues ignoredCases option to config that. For example we'd like to keep the spaces inside a pair of brackets, which is invalid by default. Then we could write one more line of HTML comment anywhere inside the file:

<!-- the good case -->

text before (text inside) text after

<!-- the bad case -->

vm.$on( event, callback )

<!-- then we could write this down below to make it work -->
<!-- zhlint ignore: ( , ) -->

or just pass it through as an option:

run(str, { ignoredCases: { textStart: '( ', textEnd: ' )' } })

If you want to ignore the whole file, you can also add this HTML comment:

<!-- zhlint disabled -->

Supported preproccessors (hyper parsers)

  • ignore: find all ignored pieces by the HTML comment <!-- zhlint ignore: ... -->
  • hexo: find all Hexo tags to avoid them being parsed.
  • markdown: parse by markdown syntax and find all block-level texts and inline-level marks.

Supported rules

Almost the rules come from the past translation experiences in W3C HTML Chinese interest group and Vue.js Chinese docsite.

... and this part might be controversial. So if you don't feel well at some point, we definitely would love to know and improve. Opening an issue is always welcome. Then we could discuss about the possible better option or decision.

type RuleOptions = {
  /* PRESET */

  // Custom preset, currently only support:
  // - `'default'`
  preset?: string

  /* PUNCTUATIONS */

  // Convert these punctuations into half-width.
  // default preset: `()`
  // e.g. `(文字)` -> `(文字)`
  halfWidthPunctuation?: string

  // Convert these punctuations into full-width.
  // default preset: `,。:;?!“”‘’`
  // e.g. `文字,文字.` -> `文字,文字。`
  fullWidthPunctuation?: string

  // Treat these full-width punctuations as half-fullWidthPunctuation
  // when processing the spaces issues around them.
  // Since something like quotes in morder Chinese fonts are
  // only rendered in half-width.
  // default preset: `“”‘’`
  adjustedFullWidthPunctuation?: string

  // Convert traditional Chinese punctuations into simplified ones or vice versa.
  // default preset: `simplified`
  // e.g. `「文字」` -> `“文字”`
  unifiedPunctuation?: 'traditional' | 'simplified'

  // Special case: skip `fullWidthPunctuation` for abbreviations.
  // default preset:
  // `['Mr.','Mrs.','Dr.','Jr.','Sr.','vs.','etc.','i.e.','e.g.','a.k.a']`
  skipAbbrs?: string[]

  /* SPACES AROUND LETTERS */

  // default preset: `true`
  // - `true`: one space
  // - `undefined`: do nothing
  // e.g. `foo  bar` -> `foo bar`
  spaceBetweenHalfWidthLetters?: boolean

  // default preset: `true`
  // - `true`: zero space
  // - `undefined`: do nothing
  // e.g. `文 字` -> `文字`
  noSpaceBetweenFullWidthLetters?: boolean

  // default preset: `true`
  // - `true`: one space
  // - `false`: zero space
  // - `undefined`: do nothing
  // e.g. `文字 foo文字` -> `文字 foo 文字` (`true`)
  // e.g. `文字foo 文字` -> `文字foo文字` (`false`)
  spaceBetweenMixedWidthLetters?: boolean

  // Special case: skip `spaceBetweenMixedWidthContent`
  // for numbers x Chinese units.
  // default preset: `年月日天号时分秒`
  skipZhUnits?: string

  /* SPACES AROUND PUNCTUATIONS */

  // default preset: `true`
  // - `true`: zero space
  // - `undefined`: do nothing
  // e.g. `文字 ,文字` -> `文字,文字`
  noSpaceBeforePunctuation?: boolean

  // default preset: `true`
  // - `true`: one space
  // - `false`: zero space
  // - `undefined`: do nothing
  // e.g. `文字,文字` -> `文字, 文字` (`true`)
  // e.g. `文字, 文字` -> `文字,文字` (`false`)
  spaceAfterHalfWidthPunctuation?: boolean

  // default preset: `true`
  // - `true`: zero space
  // - `undefined`: do nothing
  // e.g. `文字, 文字` -> `文字,文字`
  noSpaceAfterFullWidthPunctuation?: boolean

  /* SPACES AROUND QUOTES */

  // default preset: `true`
  // - `true`: one space
  // - `false`: zero space
  // - `undefined`: do nothing
  // e.g. `文字 "文字"文字` -> `文字 "文字" 文字` (`true`)
  // e.g. `文字"文字" 文字` -> `文字"文字"文字` (`false`)
  spaceOutsideHalfQuote?: boolean

  // default preset: `true`
  // - `true`: zero space
  // - `undefined`: do nothing
  // e.g. `文字 “文字” 文字` -> `文字“文字”文字`
  noSpaceOutsideFullQuote?: boolean

  // default preset: `true`
  // - `true`: zero space
  // - `undefined`: do nothing
  // e.g. `文字“ 文字 ”文字` -> `文字“文字”文字`
  noSpaceInsideQuote?: boolean

  /* SPACES AROUND BRACKETS */

  // default preset: `true`
  // - `true`: one space
  // - `false`: zero space
  // - `undefined`: do nothing
  spaceOutsideHalfBracket?: boolean

  // default preset: `true`
  // - `true`: zero space
  // - `undefined`: do nothing
  noSpaceOutsideFullBracket?: boolean

  // default preset: `true`
  // - `true`: zero space
  // - `undefined`: do nothing
  noSpaceInsideBracket?: boolean

  /* SPACES AROUND CODE */

  // default preset: `true`
  // - `true`: one space
  // - `false`: zero space
  // - `undefined`: do nothing
  // e.g. '文字 `code`文字' -> '文字 `code` 文字' ('true')
  // e.g. '文字`code` 文字' -> '文字`code`文字' ('false')
  spaceOutsideCode?: boolean

  /* SPACES AROUND MARKDOWN/HTML WRAPPERS */

  // default `true`
  // - `true`: zero space
  // - `undefined`: do nothing
  // e.g. `文字** foo **文字` -> `文字 **foo** 文字`
  noSpaceInsideWrapper?: boolean

  /* SPACES AT THE BEGINNING/END */

  // default `true`
  // e.g. ` 文字 ` -> `文字`
  trimSpace?: boolean
}

More information

zhlint is now open sourced on GitHub and issues welcome.

More Repositories

1

h5slides

A Slides App based on HTML5
JavaScript
858
star
2

vue-mark-display

A Vue Component for Markdown-based Slides.
Vue
311
star
3

px2rem-loader

Webpack loader for px2rem css file
JavaScript
204
star
4

vue-a11y-utils

Utilities for accessibility (a11y) in Vue.js
TypeScript
121
star
5

vlite

A lite demo server, inspired by Vite
TypeScript
77
star
6

weex-x

JavaScript
58
star
7

vue-simple-compiler

A lib to compile Vue Single-File Component into plain JavaScript & CSS.
TypeScript
54
star
8

weex-template

JavaScript
38
star
9

v-dynamic-island

A Vue (3.x) implementation of Dynamic Island
Vue
31
star
10

rich-game

JavaScript
28
star
11

vue-keyboard-over

A Vue component that display pressed keys on the keyboard by the user right now.
Vue
26
star
12

webcomponents-demo

All demos I wrote about Web Components
18
star
13

mark2slides

A markdown-to-slides generator.
JavaScript
15
star
14

html5-slides-20110512

如何制作简易的HTML5幻灯片
JavaScript
14
star
15

996.band

Homepage of 996 Band
HTML
14
star
16

slides

My slides (generated by mark2Slides)
JavaScript
12
star
17

vue-a11y-examples

Examples for vue-a11y-utils
Vue
11
star
18

html5-player-20110610

JavaScript
8
star
19

vue-computed-array

A JS library to create a two-way computed array in Vue easier.
JavaScript
7
star
20

jie

基于 Polymer 的一套组件库,开发代号暂定为 JIE
6
star
21

vue-mark-preview

A web app to preview a markdown URL as slides.
JavaScript
6
star
22

pic360

Show panorama pictures in 360 degrees.
JavaScript
6
star
23

grunt-combo-html-css-js

Combine css links and javscript files to html file with inline tags automatically
JavaScript
5
star
24

wcag20-techs-contents-cn

Techniques for WCAG 2.0 目录的中文翻译
4
star
25

jinjiang.github.io

Jinjiang's dev site
4
star
26

zorro

A web components framework & gallery
3
star
27

jie-dialog

3
star
28

vue-typed-style

JavaScript
3
star
29

jie-progress

2
star
30

source-map-view

A web app to view source code and source maps side-by-side.
TypeScript
2
star
31

try-nuxt

Vue
1
star
32

jie-btn

1
star
33

jie-icon

1
star
34

jie-dock

1
star
35

jiongks

My Chinese blog
JavaScript
1
star
36

translation-workflow-demo

JavaScript
1
star