-
Notifications
You must be signed in to change notification settings - Fork 0
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
✨Feature/plugin non breaking spaces #55
Changes from 16 commits
31c06cb
1c41276
ec91cc7
294a74b
dd4e71d
a42ec5e
80a72a6
254b3cd
c44d623
7434060
860673d
18f1c88
9c8e6dc
5911d14
afe0141
195108e
0bfb12b
d1be30f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
tsconfig.json | ||
src/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# @lokse/plugin- | ||
|
||
Plugin for replacing white spaces after single letter characters with non-breking space. | ||
|
||
In some languages there are special chracters such as `§ or ¶` or even single letter words like `a` etc. | ||
These characters should not stay by the end of the lines, by the languge typographic rules, | ||
therefore we replace them with non-breking space, to force them appera on a new line. | ||
|
||
https://practicaltypography.com/nonbreaking-spaces.html | ||
|
||
## Installation | ||
|
||
```sh | ||
$ yarn add -D @lokse/plugin-non-breaking-spaces | ||
``` | ||
|
||
## Usage | ||
|
||
Add it into plugins section of lokse config | ||
|
||
### Default patterns | ||
|
||
This plugin is using regex patterns to find whitespaces before single-letter and other characters. | ||
|
||
Patterns names are matching languages defined in your google sheet. Keys are being lowercased by the plugin so even if you provide language `cs-CZ` it will result in `cs-cs` | ||
|
||
We currently provide these patterns as default: | ||
|
||
(Feel free to contribute with more) | ||
|
||
```js | ||
{ | ||
cs: /(\s|^)(a|i|k|o|s|u|v|z)(\s+)/gim, | ||
"cs-cz": /(\s|^)(a|i|k|o|s|u|v|z)(\s+)/gim, | ||
} | ||
``` | ||
### Options | ||
|
||
`useNbsp` — Replacese adds HTML entity for non-breking space instead regular non-breaking white space | ||
|
||
`customPatterns` — Adds the possibility to extend the default patterns with custom language patterns, please notice you dont have to pass space matching `(\\s|^)` and `(\\s+)` as it is included in the plugin by default. | ||
|
||
```json | ||
{ | ||
"plugins": [ | ||
{ | ||
"name": "@lokse/plugin-non-breaking-spaces", | ||
// options are optional ))) | ||
"options": { | ||
useNbsp: true; | ||
customPatterns: { | ||
// provide custom regex patter without flags | ||
// default flag is gim | ||
// use the language code as key (has to be the same as your lang in the spreadsheet) | ||
"ad-HD": "(a|i|k|o|s|u|v|z)" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
``` | ||
|
||
## License | ||
Lokse is licensed under the MIT License. | ||
Documentation is licensed under Creative Commons License. | ||
Created with ♥ by [@horaklukas](https://github.com/horaklukas) and all the great contributors. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{ | ||
"name": "@lokse/plugin-non-breaking-spaces", | ||
"description": "", | ||
"version": "1.0.0", | ||
"author": { | ||
"name": "Filip Kubík", | ||
"email": "filip.kubik.dev@gmail.com" | ||
}, | ||
"bugs": "https://github.com/AckeeCZ/lokse/issues", | ||
"dependencies": { | ||
"@lokse/core": "^2.0.0" | ||
}, | ||
"devDependencies": {}, | ||
"engines": { | ||
"node": ">=8.0.0" | ||
}, | ||
"homepage": "https://github.com/AckeeCZ/lokse", | ||
"keywords": [ | ||
"lokse", | ||
"lokse-plugin" | ||
], | ||
"license": "MIT", | ||
"main": "lib/index.js", | ||
"repository": "AckeeCZ/lokse", | ||
"scripts": { | ||
"build": "tsc -b" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,95 @@ | ||||||||||
import { Line } from "@lokse/core"; | ||||||||||
|
||||||||||
import nonBreakingSpacesPlugin from ".."; | ||||||||||
|
||||||||||
import Transformer from "../../../core/lib/transformer/json"; | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please don't break packages encapsulation 🙏
Suggested change
|
||||||||||
|
||||||||||
describe("Non-breaking spaces plugin", () => { | ||||||||||
const logger = { warn: jest.fn(), log: jest.fn() }; | ||||||||||
|
||||||||||
beforeEach(() => { | ||||||||||
logger.warn.mockReset(); | ||||||||||
}); | ||||||||||
|
||||||||||
describe("transformFullOutput hook", () => { | ||||||||||
it("should warn if language pattern is missing", async () => { | ||||||||||
const plugin = nonBreakingSpacesPlugin({ logger }); | ||||||||||
|
||||||||||
const language = "ad-HD"; | ||||||||||
|
||||||||||
const meta = { transformer: Transformer, language }; | ||||||||||
|
||||||||||
await plugin.transformFullOutput("some string", meta); | ||||||||||
|
||||||||||
expect(logger.warn).toHaveBeenCalledWith( | ||||||||||
expect.stringMatching( | ||||||||||
`Pattern for current language ${language} was not found` | ||||||||||
) | ||||||||||
); | ||||||||||
}); | ||||||||||
}); | ||||||||||
|
||||||||||
describe("transformLine hook", () => { | ||||||||||
it("should replace white spaces after single letter chars with non-breaking spaces in CS lang", async () => { | ||||||||||
const plugin = nonBreakingSpacesPlugin({ logger }); | ||||||||||
|
||||||||||
const initialValue = | ||||||||||
"A kdyby tady spadli marťani, tak je budeme schvalovat i třeba s marťany. Byly z divokých vajec. K večeři a obědu. O Vánocích. U tebe."; | ||||||||||
const targetValue = | ||||||||||
"A\u00A0kdyby tady spadli marťani, tak je budeme schvalovat i\u00A0třeba s\u00A0marťany. Byly z\u00A0divokých vajec. K\u00A0večeři a\u00A0obědu. O\u00A0Vánocích. U\u00A0tebe."; | ||||||||||
|
||||||||||
const line = new Line("test.key", initialValue); | ||||||||||
|
||||||||||
const meta = { key: line.key, language: "cs" }; | ||||||||||
|
||||||||||
const transformedLine = await plugin.transformLine(line, meta); | ||||||||||
|
||||||||||
expect(transformedLine.value).toBe(targetValue); | ||||||||||
|
||||||||||
expect(logger.warn).not.toHaveBeenCalled(); | ||||||||||
}); | ||||||||||
|
||||||||||
it("should work with custom pattern and lang provided", async () => { | ||||||||||
const plugin = nonBreakingSpacesPlugin({ | ||||||||||
logger, | ||||||||||
customPatterns: { "ad-HD": "(a|i|k|o|s|u|v|z)" }, | ||||||||||
}); | ||||||||||
|
||||||||||
const initialValue = | ||||||||||
"A kdyby tady spadli marťani, tak je budeme schvalovat i třeba s marťany. Byly z divokých vajec. K večeři a obědu. O Vánocích. U tebe."; | ||||||||||
const targetValue = | ||||||||||
"A\u00A0kdyby tady spadli marťani, tak je budeme schvalovat i\u00A0třeba s\u00A0marťany. Byly z\u00A0divokých vajec. K\u00A0večeři a\u00A0obědu. O\u00A0Vánocích. U\u00A0tebe."; | ||||||||||
|
||||||||||
const language = "ad-HD"; | ||||||||||
|
||||||||||
const line = new Line("test.key", initialValue); | ||||||||||
|
||||||||||
const meta = { key: line.key, language }; | ||||||||||
|
||||||||||
const transformedLine = await plugin.transformLine(line, meta); | ||||||||||
|
||||||||||
expect(transformedLine.value).toBe(targetValue); | ||||||||||
|
||||||||||
expect(logger.warn).not.toHaveBeenCalled(); | ||||||||||
}); | ||||||||||
|
||||||||||
it("should replace white spaces after single letter chars with HTML entity", async () => { | ||||||||||
const plugin = nonBreakingSpacesPlugin({ logger, useNbsp: true }); | ||||||||||
|
||||||||||
const initialValue = | ||||||||||
"A kdyby tady spadli marťani, tak je budeme schvalovat i třeba s marťany. Byly z divokých vajec. K večeři a obědu. O Vánocích. U tebe."; | ||||||||||
const targetValue = | ||||||||||
"A kdyby tady spadli marťani, tak je budeme schvalovat i třeba s marťany. Byly z divokých vajec. K večeři a obědu. O Vánocích. U tebe."; | ||||||||||
|
||||||||||
const line = new Line("test.key", initialValue); | ||||||||||
|
||||||||||
const meta = { key: line.key, language: "cs" }; | ||||||||||
|
||||||||||
const transformedLine = await plugin.transformLine(line, meta); | ||||||||||
|
||||||||||
expect(transformedLine.value).toBe(targetValue); | ||||||||||
|
||||||||||
expect(logger.warn).not.toHaveBeenCalled(); | ||||||||||
}); | ||||||||||
}); | ||||||||||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { createPlugin } from "@lokse/core"; | ||
import type { GeneralPluginOptions, LoksePlugin } from "@lokse/core"; | ||
|
||
import { lowerCaseKeys, regexifyValues } from "./utils"; | ||
|
||
export interface Patterns { | ||
[key: string]: RegExp | string; | ||
} | ||
export interface CustomPatterns { | ||
[key: string]: string; | ||
} | ||
|
||
const defaultPatterns: Patterns = { | ||
cs: /(\s|^)(a|i|k|o|s|u|v|z)(\s+)/gim, | ||
"cs-cz": /(\s|^)(a|i|k|o|s|u|v|z)(\s+)/gim, | ||
}; | ||
|
||
export interface PluginOptions extends GeneralPluginOptions { | ||
useNbsp?: boolean; | ||
customPatterns?: CustomPatterns; | ||
} | ||
|
||
// We have to do this in order to process the custom patterns from JSON plugin settings | ||
const normalizeCustomPatterns = (patterns: CustomPatterns) => { | ||
const lowerCasedCustomPatterns = lowerCaseKeys(patterns); | ||
const regexifiedValues = regexifyValues(lowerCasedCustomPatterns); | ||
|
||
return regexifiedValues; | ||
}; | ||
|
||
export default function (options: PluginOptions): LoksePlugin { | ||
const patterns: Patterns = { | ||
...defaultPatterns, | ||
...(options.customPatterns | ||
? normalizeCustomPatterns(options.customPatterns) | ||
: {}), | ||
}; | ||
|
||
return createPlugin({ | ||
transformFullOutput: async (output, meta) => { | ||
const { language } = meta; | ||
|
||
const pattern = patterns[language.toLowerCase()]; | ||
|
||
if (!pattern) { | ||
options.logger.warn( | ||
`Pattern for current language ${language} was not found` | ||
); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We could maybe provide default definitions for some most used languages like EN/DE. Please create an enhancement ticket for it 🙏 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alright, makes sense. |
||
} | ||
|
||
return output; | ||
}, | ||
transformLine: (line, meta) => { | ||
const { language } = meta; | ||
|
||
const pattern = patterns[language.toLowerCase()]; | ||
|
||
if (pattern) { | ||
const replacement = options.useNbsp ? "$1$2 " : "$1$2\u00A0"; | ||
line.setValue((value) => value.replace(pattern, replacement)); | ||
} | ||
|
||
return line; | ||
}, | ||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { mapKeys, mapValues } from "lodash"; | ||
|
||
import { CustomPatterns } from "."; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you sure about this import from |
||
|
||
export const lowerCaseKeys = (patterns: CustomPatterns) => | ||
mapKeys(patterns, (_, key) => key.toLowerCase()); | ||
|
||
const convertStringToRegex = (string: string) => | ||
new RegExp(`(\\s|^)${string}(\\s+)`, "gim"); | ||
|
||
export const regexifyValues = (patterns: CustomPatterns) => | ||
mapValues(patterns, (value) => convertStringToRegex(value)); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"extends": "../../tsconfig.json", | ||
"compilerOptions": { | ||
"outDir": "lib", | ||
"rootDir": "src", | ||
}, | ||
"include": [ | ||
"src/**/*", | ||
], | ||
"exclude": [ | ||
"src/**/__tests__/**" | ||
] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please document default patterns that work out of the box 🙏