ilib-lint 2.21.3 → 2.21.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -10
- package/package.json +3 -3
- package/src/index.js +2 -2
- package/src/plugins/BuiltinPlugin.js +1 -1
- package/src/rules/ResourceCamelCase.js +1 -1
- package/src/rules/ResourceKebabCase.js +1 -1
- package/src/rules/ResourceQuoteStyle.js +9 -2
- package/src/rules/ResourceReturnChar.js +1 -1
- package/src/rules/ResourceSentenceEnding.js +46 -4
- package/src/rules/ResourceSnakeCase.js +1 -1
package/README.md
CHANGED
|
@@ -608,17 +608,11 @@ ilib-lint plugins from v1 of ilib-lint to v2.
|
|
|
608
608
|
|
|
609
609
|
## License
|
|
610
610
|
|
|
611
|
-
Copyright © 2022-
|
|
611
|
+
Copyright © 2022-2026, JEDLSoft
|
|
612
612
|
|
|
613
|
-
|
|
614
|
-
you may not use this file except in compliance with the License.
|
|
615
|
-
You may obtain a copy of the License at
|
|
613
|
+
This package is released under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). The full license text is available in the [LICENSE](https://github.com/iLib-js/ilib-mono/blob/main/packages/ilib-lint/LICENSE) file in the ilib-mono repository on GitHub.
|
|
616
614
|
|
|
617
|
-
|
|
615
|
+
## Release Notes
|
|
618
616
|
|
|
619
|
-
|
|
620
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
621
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
617
|
+
See [CHANGELOG.md](https://github.com/iLib-js/ilib-mono/blob/main/packages/ilib-lint/CHANGELOG.md).
|
|
622
618
|
|
|
623
|
-
See the License for the specific language governing permissions and
|
|
624
|
-
limitations under the License.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ilib-lint",
|
|
3
|
-
"version": "2.21.
|
|
3
|
+
"version": "2.21.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"module": "./src/index.js",
|
|
@@ -82,9 +82,9 @@
|
|
|
82
82
|
"ilib-ctype": "^1.3.0",
|
|
83
83
|
"ilib-lint-common": "^3.7.0",
|
|
84
84
|
"ilib-locale": "^1.4.0",
|
|
85
|
-
"ilib-localematcher": "^1.3.
|
|
85
|
+
"ilib-localematcher": "^1.3.4",
|
|
86
86
|
"ilib-scriptinfo": "^1.0.0",
|
|
87
|
-
"ilib-tools-common": "^1.
|
|
87
|
+
"ilib-tools-common": "^1.22.0",
|
|
88
88
|
"ilib-xliff": "^1.4.1"
|
|
89
89
|
},
|
|
90
90
|
"scripts": {
|
package/src/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/*
|
|
3
3
|
* index.js - main program of ilib-lint
|
|
4
4
|
*
|
|
5
|
-
* Copyright © 2022-
|
|
5
|
+
* Copyright © 2022-2026 JEDLSoft
|
|
6
6
|
*
|
|
7
7
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
8
|
* you may not use this file except in compliance with the License.
|
|
@@ -178,7 +178,7 @@ if (options.opt.quiet) {
|
|
|
178
178
|
logger.level = "debug";
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
logger.info("ilib-lint - Copyright (c) 2022-
|
|
181
|
+
logger.info("ilib-lint - Copyright (c) 2022-2026 JEDLsoft, All rights reserved.");
|
|
182
182
|
|
|
183
183
|
let paths = options.args;
|
|
184
184
|
if (paths.length === 0) {
|
|
@@ -169,7 +169,7 @@ export const regexRules = [
|
|
|
169
169
|
regexps: [
|
|
170
170
|
"(\\p{L}+('\\p{L}+)+)" // word boundary + word chars + quote + word chars + word boundary (e.g., it's, don't, d'l'homme)
|
|
171
171
|
],
|
|
172
|
-
link: "https://github.com/iLib-js/ilib-
|
|
172
|
+
link: "https://github.com/iLib-js/ilib-mono/blob/main/packages/ilib-lint/docs/resource-apostrophe.md",
|
|
173
173
|
fixes: [
|
|
174
174
|
{ search: "'", replace: "\u2019" }
|
|
175
175
|
]
|
|
@@ -39,7 +39,7 @@ class ResourceCamelCase extends ResourceRule {
|
|
|
39
39
|
|
|
40
40
|
this.name = "resource-camel-case";
|
|
41
41
|
this.description = "Ensure that when source strings contain only camel case and no whitespace, then the targets are the same";
|
|
42
|
-
this.link = "https://
|
|
42
|
+
this.link = "https://github.com/iLib-js/ilib-mono/blob/main/packages/ilib-lint/docs/resource-camel-case.md";
|
|
43
43
|
this.regexps = [
|
|
44
44
|
"^\\s*[a-z\\d]+([A-Z][a-z\\d]+)+\\s*$",
|
|
45
45
|
"^\\s*[A-Z][a-z\\d]+([A-Z][a-z\\d]+)+\\s*$",
|
|
@@ -19,7 +19,7 @@ class ResourceKebabCase extends ResourceRule {
|
|
|
19
19
|
|
|
20
20
|
this.name = "resource-kebab-case";
|
|
21
21
|
this.description = "Ensure that when source strings contain only kebab case and no whitespace, then the targets are the same";
|
|
22
|
-
this.link = "https://
|
|
22
|
+
this.link = "https://github.com/iLib-js/ilib-mono/blob/main/packages/ilib-lint/docs/resource-kebab-case.md";
|
|
23
23
|
|
|
24
24
|
const param = this.getParam() || {};
|
|
25
25
|
this.exceptions = Array.isArray(param?.except) ? param.except : [];
|
|
@@ -236,14 +236,17 @@ class ResourceQuoteStyle extends ResourceRule {
|
|
|
236
236
|
}
|
|
237
237
|
let match;
|
|
238
238
|
let commands = [];
|
|
239
|
+
const startQuotePositions = new Set();
|
|
239
240
|
|
|
240
241
|
while ((match = startQuote.exec(tar)) !== null) {
|
|
241
242
|
// now that we have found a start quote, find it in the matched string so
|
|
242
243
|
// that we can get the index into that string
|
|
243
244
|
const offset = match[0].indexOf(match[3]);
|
|
245
|
+
const pos = match.index + offset;
|
|
246
|
+
startQuotePositions.add(pos);
|
|
244
247
|
|
|
245
248
|
commands.push(ResourceFixer.createStringCommand(
|
|
246
|
-
|
|
249
|
+
pos,
|
|
247
250
|
1,
|
|
248
251
|
correctQuoteStart
|
|
249
252
|
));
|
|
@@ -253,9 +256,13 @@ class ResourceQuoteStyle extends ResourceRule {
|
|
|
253
256
|
// now that we have found an end quote, find it in the matched string so
|
|
254
257
|
// that we can get the index into that string
|
|
255
258
|
const offset = match[0].indexOf(match[3]);
|
|
259
|
+
const pos = match.index + offset;
|
|
260
|
+
// skip positions already handled by startQuote to avoid overlapping commands
|
|
261
|
+
// (can occur when a quote char is surrounded by CJK letters on both sides)
|
|
262
|
+
if (startQuotePositions.has(pos)) continue;
|
|
256
263
|
|
|
257
264
|
commands.push(ResourceFixer.createStringCommand(
|
|
258
|
-
|
|
265
|
+
pos,
|
|
259
266
|
1,
|
|
260
267
|
correctQuoteEnd
|
|
261
268
|
));
|
|
@@ -34,7 +34,7 @@ export default class ResourceReturnChar extends ResourceRule {
|
|
|
34
34
|
super(options);
|
|
35
35
|
this.name = "resource-return-char";
|
|
36
36
|
this.description = "Checks that the number of return characters (CR, LF, CRLF) in the source matches the target";
|
|
37
|
-
this.link = "https://github.com/iLib-js/ilib-
|
|
37
|
+
this.link = "https://github.com/iLib-js/ilib-mono/blob/main/packages/ilib-lint/docs/resource-return-char.md";
|
|
38
38
|
this.type = "resource";
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -173,7 +173,7 @@ class ResourceSentenceEnding extends ResourceRule {
|
|
|
173
173
|
super(options);
|
|
174
174
|
this.name = "resource-sentence-ending";
|
|
175
175
|
this.description = "Checks that sentence-ending punctuation is appropriate for the locale of the target string and matches the punctuation in the source string";
|
|
176
|
-
this.link = "https://github.com/iLib-js/ilib-
|
|
176
|
+
this.link = "https://github.com/iLib-js/ilib-mono/blob/main/packages/ilib-lint/docs/resource-sentence-ending.md";
|
|
177
177
|
|
|
178
178
|
// Get the parameter from the options
|
|
179
179
|
const param = this.getParam() || {};
|
|
@@ -438,6 +438,40 @@ class ResourceSentenceEnding extends ResourceRule {
|
|
|
438
438
|
return stripped.endsWith(expected);
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
+
/**
|
|
442
|
+
* Detect whether a string uses "person quotation" style, where the quoted
|
|
443
|
+
* content is a direct speech quotation introduced by a comma.
|
|
444
|
+
*
|
|
445
|
+
* Person quotation: She said, "A quotation!"
|
|
446
|
+
* Call-out (default): select 'Manual Zoom.'
|
|
447
|
+
*
|
|
448
|
+
* @param {string} str
|
|
449
|
+
* @returns {boolean}
|
|
450
|
+
*/
|
|
451
|
+
static isPersonQuotation(str) {
|
|
452
|
+
if (!str) return false;
|
|
453
|
+
const trimmed = str.trim();
|
|
454
|
+
const quoteChars = ResourceSentenceEnding.allQuoteChars;
|
|
455
|
+
|
|
456
|
+
const lastChar = trimmed.charAt(trimmed.length - 1);
|
|
457
|
+
if (!quoteChars.includes(lastChar)) return false;
|
|
458
|
+
|
|
459
|
+
let openPos = -1;
|
|
460
|
+
for (let i = trimmed.length - 2; i >= 0; i--) {
|
|
461
|
+
if (quoteChars.includes(trimmed.charAt(i))) {
|
|
462
|
+
openPos = i;
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if (openPos <= 0) return false;
|
|
467
|
+
|
|
468
|
+
let beforeQuote = openPos - 1;
|
|
469
|
+
while (beforeQuote >= 0 && /\s/.test(trimmed.charAt(beforeQuote))) {
|
|
470
|
+
beforeQuote--;
|
|
471
|
+
}
|
|
472
|
+
return beforeQuote >= 0 && trimmed.charAt(beforeQuote) === ',';
|
|
473
|
+
}
|
|
474
|
+
|
|
441
475
|
/**
|
|
442
476
|
* Get the last quoted string in the input, or null if none found.
|
|
443
477
|
* Handles all quote types in allQuoteChars.
|
|
@@ -974,12 +1008,20 @@ class ResourceSentenceEnding extends ResourceRule {
|
|
|
974
1008
|
let highlight = '';
|
|
975
1009
|
let description = '';
|
|
976
1010
|
|
|
1011
|
+
const targetTrimmed = target?.trim() || '';
|
|
1012
|
+
const targetEndsWithQuote = quoteChars.includes(targetTrimmed.charAt(targetTrimmed.length - 1));
|
|
1013
|
+
|
|
977
1014
|
let lastSentence;
|
|
978
|
-
if (sourceEndsWithQuote
|
|
979
|
-
|
|
1015
|
+
if (sourceEndsWithQuote &&
|
|
1016
|
+
(ResourceSentenceEnding.isPersonQuotation(sourceTrimmed) || targetEndsWithQuote)) {
|
|
1017
|
+
// Person quotation (e.g. She said, "Hello!") or both source and target
|
|
1018
|
+
// end with a quote — compare quoted content
|
|
980
1019
|
lastSentence = ResourceSentenceEnding.getLastQuotedString(target) || target.trim();
|
|
1020
|
+
} else if (sourceEndsWithQuote) {
|
|
1021
|
+
// Call-out / reference where the target does not end with a quote —
|
|
1022
|
+
// compare overall target ending, not a sentence fragment
|
|
1023
|
+
lastSentence = target.trim();
|
|
981
1024
|
} else {
|
|
982
|
-
// Use the full target string
|
|
983
1025
|
lastSentence = this.getLastSentenceFromContent(target, targetLocaleObj);
|
|
984
1026
|
}
|
|
985
1027
|
|
|
@@ -39,7 +39,7 @@ class ResourceSnakeCase extends ResourceRule {
|
|
|
39
39
|
|
|
40
40
|
this.name = "resource-snake-case";
|
|
41
41
|
this.description = "Ensure that when source strings contain only snake case and no whitespace, then the targets are the same";
|
|
42
|
-
this.link = "https://
|
|
42
|
+
this.link = "https://github.com/iLib-js/ilib-mono/blob/main/packages/ilib-lint/docs/resource-snake-case.md";
|
|
43
43
|
this.regexps = [
|
|
44
44
|
"^\\s*[a-zA-Z0-9]*(_[a-zA-Z0-9]+)+\\s*$",
|
|
45
45
|
"^\\s*[a-zA-Z0-9]+(_[a-zA-Z0-9]+)*_\\s*$"
|