ilib-lint 2.9.2 → 2.10.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ilib-lint",
3
- "version": "2.9.2",
3
+ "version": "2.10.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "module": "./src/index.js",
@@ -72,9 +72,9 @@
72
72
  "options-parser": "^0.4.0",
73
73
  "xml-js": "^1.6.11",
74
74
  "ilib-common": "^1.1.6",
75
- "ilib-lint-common": "^3.2.0",
75
+ "ilib-lint-common": "^3.4.0",
76
76
  "ilib-locale": "^1.2.4",
77
- "ilib-tools-common": "^1.15.0"
77
+ "ilib-tools-common": "^1.16.0"
78
78
  },
79
79
  "scripts": {
80
80
  "coverage": "pnpm test -- --coverage",
@@ -348,7 +348,7 @@ class LintableFile extends DirItem {
348
348
  const newIR = transformer.transform(this.irs[i], results);
349
349
  if (newIR) {
350
350
  this.irs[i] = newIR;
351
- this.dirty = true;
351
+ this.dirty = newIR.isDirty();
352
352
  }
353
353
  }
354
354
  });
package/src/Project.js CHANGED
@@ -668,7 +668,7 @@ class Project extends DirItem {
668
668
  errorsOnly : this.options.opt.errorsOnly || false
669
669
  });
670
670
  } else {
671
- results.forEach(result => {
671
+ resultAll = results.map(result => {
672
672
  const str = this.formatter.format(result);
673
673
  if (str) {
674
674
  if (result.severity === "error") {
@@ -683,7 +683,8 @@ class Project extends DirItem {
683
683
  }
684
684
  }
685
685
  }
686
- });
686
+ return str;
687
+ }).join("\n");
687
688
 
688
689
  logger.info(`Total Elapse Time: ${String(totalTime)} seconds`);
689
690
  logger.info(` ${`Average over`.padEnd(15, ' ')}${`Average over`.padEnd(15, ' ')}${`Average over`.padEnd(15, ' ')}`);
@@ -70,7 +70,8 @@ class JsonFormatter extends Formatter {
70
70
  return {
71
71
  pathName: result.pathName,
72
72
  rule: result.rule.getName(),
73
- severity: result.severity
73
+ severity: result.severity,
74
+ locale: result.locale
74
75
  };
75
76
  })
76
77
  };
@@ -86,6 +87,7 @@ class JsonFormatter extends Formatter {
86
87
  obj[name].stats.lines = fileStats.lines;
87
88
  obj[name].stats.bytes = fileStats.bytes;
88
89
  obj[name].stats.modules = fileStats.modules;
90
+ obj[name].stats.words = fileStats.words;
89
91
  }
90
92
 
91
93
  // write as compressed JSON to save space;
@@ -19,6 +19,7 @@
19
19
  */
20
20
 
21
21
  import { IntermediateRepresentation, Transformer, Result } from 'ilib-lint-common';
22
+ import { Resource } from 'ilib-tools-common';
22
23
 
23
24
  /**
24
25
  * Filter out errors from the intermediate representation.
@@ -46,12 +47,18 @@ class ErrorFilterTransformer extends Transformer {
46
47
  return ir;
47
48
  }
48
49
  const resources = ir.getRepresentation();
49
- const idsToExclude = results.filter(result => result.id && result.severity === 'error').map(result => result.id);
50
- const filteredResources = resources.filter(resource => !idsToExclude.includes(resource.getKey()));
50
+ const hashesToExclude = results.filter(result => result.id && result.severity === 'error').
51
+ map(result => [result.id, result.locale, result.pathName].join('_'));
52
+ const filteredResources = resources.filter(/** @type Resource */ resource => {
53
+ const filePath = resource.getResFile() ?? resource.getPath();
54
+ const hash = [resource.getKey(), resource.getTargetLocale(), filePath].join('_');
55
+ return !hashesToExclude.includes(hash);
56
+ });
51
57
  return new IntermediateRepresentation({
52
58
  type: ir.getType(),
53
59
  ir: filteredResources,
54
- sourceFile: ir.getSourceFile()
60
+ sourceFile: ir.getSourceFile(),
61
+ dirty: (filteredResources.length !== resources.length)
55
62
  });
56
63
  }
57
64
  };
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * XliffParser.js - Parser for XLIFF files
3
3
  *
4
- * Copyright © 2022-2024 JEDLSoft
4
+ * Copyright © 2022-2025 JEDLSoft
5
5
  *
6
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
7
  * you may not use this file except in compliance with the License.
@@ -17,9 +17,39 @@
17
17
  * limitations under the License.
18
18
  */
19
19
 
20
- import { ResourceXliff } from 'ilib-tools-common';
20
+ import { ResourceXliff, Resource } from 'ilib-tools-common';
21
21
  import { FileStats, Parser, IntermediateRepresentation, SourceFile } from 'ilib-lint-common';
22
22
 
23
+ /**
24
+ * Count the number of words in the source strings of the resources.
25
+ * This is a very simple word count that splits the source string
26
+ * on whitespace and counts the number of resulting pieces. We can replace it
27
+ * later with a more sophisticated word count if needed.
28
+ *
29
+ * @param {Array.<Resource>} resources the resources to count words in
30
+ * @returns {Number} the total number of words in the source strings
31
+ */
32
+ function countSourceWords(resources) {
33
+ return resources.reduce((sum, res) =>
34
+ sum + (res.getSource() ? res.getSource().split(/\s+/).length : 0), 0);
35
+ }
36
+
37
+ /**
38
+ * Count the number of bytes in the source strings of the resources.
39
+ * This is a simple byte count that counts the number of characters in the
40
+ * source string, assuming that each character is one byte. This is not
41
+ * necessarily accurate for all languages, but it is a good enough approximation
42
+ * for most cases. We can replace it later with a more sophisticated byte count
43
+ * if needed.
44
+ *
45
+ * @param {Array.<Resource>} resources the resources to count bytes in
46
+ * @returns {Number} the total number of bytes in the source strings
47
+ */
48
+ function countSourceBytes(resources) {
49
+ return resources.reduce((sum, res) =>
50
+ sum + (res.getSource() ? res.getSource().length : 0), 0);
51
+ }
52
+
23
53
  /**
24
54
  * @class Parser for XLIFF files based on the ilib-xliff library.
25
55
  */
@@ -49,15 +79,17 @@ class XliffParser extends Parser {
49
79
  });
50
80
 
51
81
  xliff.parse(data);
52
- const resources = xliff.getResources();
82
+ const resources = xliff.getResources() ?? [];
53
83
  return [new IntermediateRepresentation({
54
84
  type: "resource",
55
85
  ir: resources,
56
86
  sourceFile,
57
87
  stats: new FileStats({
58
88
  lines: xliff.getLines(),
59
- bytes: xliff.size(),
60
- modules: resources.length
89
+ files: 1,
90
+ bytes: countSourceBytes(resources),
91
+ modules: resources.length,
92
+ words: countSourceWords(resources)
61
93
  })
62
94
  })];
63
95
  }
@@ -66,7 +66,8 @@ class ResourceCompleteness extends ResourceRule {
66
66
  return new Result({
67
67
  ...resultMetaProps,
68
68
  severity: "error",
69
- description: "Missing target string in resource"
69
+ description: "Missing target string in resource",
70
+ locale: resource.getTargetLocale()
70
71
  });
71
72
  }
72
73
  // if there's an extra translation string for which there is no source, just warn
@@ -75,7 +76,8 @@ class ResourceCompleteness extends ResourceRule {
75
76
  ...resultMetaProps,
76
77
  severity: "warning",
77
78
  description: "Extra target string in resource",
78
- highlight: `<e0>${target}</e0>`
79
+ highlight: `<e0>${target}</e0>`,
80
+ locale: resource.getTargetLocale()
79
81
  });
80
82
  }
81
83
  else return /* no error */;
@@ -25,7 +25,7 @@ import { Rule } from 'ilib-lint-common';
25
25
  class ResourceRule extends Rule {
26
26
  /**
27
27
  * Construct a new resource checker rule.
28
- *
28
+ *
29
29
  * If a subclass defines a property "locales" with the
30
30
  * value being a Set of locale lang-specs, then this
31
31
  * class will ensure that the rule is only applied to
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * ResourceSourceICUPluralCategories.js
3
3
  *
4
- * Copyright © 2023-2024 JEDLSoft
4
+ * Copyright © 2023-2025 JEDLSoft
5
5
  *
6
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
7
  * you may not use this file except in compliance with the License.
@@ -116,6 +116,7 @@ export class ResourceSourceICUPluralCategories extends ResourceRule {
116
116
  highlight: `<e0>${this.substringForLocation(source, partialResult.location)}</e0>`,
117
117
  severity: partialResult.severity,
118
118
  description: partialResult.description,
119
+ locale: resource.getTargetLocale(),
119
120
  })
120
121
  )
121
122
  );
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * ResourceSourceICUPluralParams.js
3
3
  *
4
- * Copyright © 2023-2024 JEDLSoft
4
+ * Copyright © 2023-2025 JEDLSoft
5
5
  *
6
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
7
  * you may not use this file except in compliance with the License.
@@ -117,6 +117,7 @@ export class ResourceSourceICUPluralParams extends ResourceRule {
117
117
  highlight: `<e0>${this.substringForLocation(source, partialResult.location)}</e0>`,
118
118
  severity: partialResult.severity,
119
119
  description: partialResult.description,
120
+ locale: resource.getTargetLocale(),
120
121
  });
121
122
  }
122
123
  return undefined;
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * ResourceSourceICUPluralSyntax.js
3
3
  *
4
- * Copyright © 2023-2024 JEDLSoft
4
+ * Copyright © 2023-2025 JEDLSoft
5
5
  *
6
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
7
  * you may not use this file except in compliance with the License.
@@ -74,6 +74,7 @@ export class ResourceSourceICUPluralSyntax extends ResourceRule {
74
74
  id: resource.getKey(),
75
75
  pathName: file,
76
76
  lineNumber,
77
+ locale: resource.getSourceLocale(),
77
78
  });
78
79
  }
79
80
  return undefined;
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * ResourceSourceICUUnexplainedParams.js
3
3
  *
4
- * Copyright © 2023-2024 JEDLSoft
4
+ * Copyright © 2023-2025 JEDLSoft
5
5
  *
6
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
7
  * you may not use this file except in compliance with the License.
@@ -136,7 +136,8 @@ export class ResourceSourceICUUnexplainedParams extends ResourceRule {
136
136
  source: source,
137
137
  severity: "warning",
138
138
  description: `Replacement parameter "${name}" is not mentioned in the string's comment for translators.`,
139
- highlight: this.highlightLocation(source, location)
139
+ highlight: this.highlightLocation(source, location),
140
+ locale: resource.getTargetLocale()
140
141
  })
141
142
  );
142
143
  }
@@ -64,12 +64,13 @@ class ResourceUniqueKeys extends Rule {
64
64
 
65
65
  if (other) {
66
66
  logger.trace(`hash '${hash}' already found in the translation set!`);
67
+ const otherFile = other.getResFile() ?? other.getPath();
67
68
  let value = {
68
69
  severity: "error",
69
70
  id: resource.getKey(),
70
71
  rule: this,
71
72
  pathName: file,
72
- highlight: `Key is also defined in this file: ${other.resfile}`,
73
+ highlight: `Key is also defined in this file: ${otherFile}`,
73
74
  description: `Key is not unique within locale ${locale}.`,
74
75
  locale
75
76
  };
@@ -79,7 +80,6 @@ class ResourceUniqueKeys extends Rule {
79
80
  return new Result(value);
80
81
  }
81
82
 
82
- resource.resfile = file;
83
83
  this.ts.add(resource);
84
84
 
85
85
  // no result
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * SourceRegexpChecker.js - rule to check if regexps match in the source
3
3
  *
4
- * Copyright © 2023-2024 JEDLSoft
4
+ * Copyright © 2023-2025 JEDLSoft
5
5
  *
6
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
7
  * you may not use this file except in compliance with the License.
@@ -126,7 +126,8 @@ class SourceRegexpChecker extends Rule {
126
126
  pathName: ir.getSourceFile().getPath(),
127
127
  highlight: snippet,
128
128
  description: this.note.replace(/\{matchString\}/g, match[0]),
129
- lineNumber
129
+ lineNumber,
130
+ locale: ir.getSourceFile().sourceLocale || this.sourceLocale
130
131
  }));
131
132
  match = re.exec(src);
132
133
  }