ilib-lint 2.6.0 → 2.7.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.6.0",
3
+ "version": "2.7.0",
4
4
  "module": "./src/index.js",
5
5
  "type": "module",
6
6
  "bin": "./src/index.js",
@@ -155,6 +155,16 @@ Here is an example of a configuration file:
155
155
  // so this both includes the rule in the rule set and instantiates
156
156
  // it with the "localeOnly" option
157
157
  "resource-quote-matcher": "localeOnly"
158
+ },
159
+ "overrides": {
160
+ "resource-camel-case": {
161
+ // adds a list of exceptions for ResourceCamelCase rule
162
+ "except": ["SomeException"]
163
+ },
164
+ "resource-snake-case": {
165
+ // adds a list of exceptions for ResourceSnakeCase rule
166
+ "except": ["some_exception"]
167
+ }
158
168
  }
159
169
  },
160
170
  // defines common settings for a particular types of file
@@ -170,6 +180,9 @@ Here is an example of a configuration file:
170
180
  "jsx": {
171
181
  "ruleset": ["react-rules"]
172
182
  },
183
+ "xliff": {
184
+ "ruleset": ["overrides"]
185
+ },
173
186
  "sdl-xliff": {
174
187
  // these are actually special xliff files in our project,
175
188
  // but they have the same syntax as regular xliff, so we can
@@ -40,6 +40,8 @@ import ResourceSourceICUPluralParams from '../rules/ResourceSourceICUPluralParam
40
40
  import ResourceSourceICUPluralCategories from '../rules/ResourceSourceICUPluralCategories.js';
41
41
  import ResourceSourceICUUnexplainedParams from '../rules/ResourceSourceICUUnexplainedParams.js';
42
42
  import ResourceXML from '../rules/ResourceXML.js';
43
+ import ResourceCamelCase from '../rules/ResourceCamelCase.js';
44
+ import ResourceSnakeCase from '../rules/ResourceSnakeCase.js';
43
45
 
44
46
  // built-in declarative rules
45
47
  export const regexRules = [
@@ -231,30 +233,6 @@ export const regexRules = [
231
233
  link: "https://github.com/ilib-js/ilib-lint/blob/main/docs/source-no-manual-date-formatting.md",
232
234
  severity: "error"
233
235
  },
234
- {
235
- type: "resource-matcher",
236
- name: "resource-snake-case",
237
- description: "Ensure that when source strings contain only snake case (words and/or numbers separeated by underscores) and no whitespace, then the targets are the same",
238
- note: "Do not translate the source string if it consists solely of snake-cased strings and/or digits. Please update the target string so it matches the source string.",
239
- regexps: [
240
- "^\\s*[a-zA-Z0-9]*(_[a-zA-Z0-9]+)+\\s*$",
241
- "^\\s*[a-zA-Z0-9]+(_[a-zA-Z0-9]+)*_\\s*$"
242
- ],
243
- link: "https://github.com/ilib-js/ilib-lint/blob/main/docs/resource-snake-case.md",
244
- severity: "error"
245
- },
246
- {
247
- type: "resource-matcher",
248
- name: "resource-camel-case",
249
- description: "Ensure that when source strings contain only camel case and no whitespace, then the targets are the same",
250
- note: "Do not translate the source string if it consists solely of camel-cased strings and/or digits. Please update the target string so it matches the source string.",
251
- regexps: [
252
- "^\\s*[a-z\\d]+([A-Z][a-z\\d]+)+\\s*$", // camelCase and 6amelCaseWithD1g1t3
253
- "^\\s*[A-Z][a-z\\d]+([A-Z][a-z\\d]+)+\\s*$", // PascalCase and 4ascalCaseWithD1g1t3
254
- ],
255
- link: "https://github.com/ilib-js/ilib-lint/blob/main/docs/resource-camel-case.md",
256
- severity: "error"
257
- },
258
236
  ];
259
237
 
260
238
  // built-in ruleset that contains all the built-in rules
@@ -270,6 +248,8 @@ export const builtInRulesets = {
270
248
  "resource-no-translation": true,
271
249
  "resource-icu-plurals-translated": true,
272
250
  "resource-xml": true,
251
+ "resource-snake-case": true,
252
+ "resource-camel-case": true,
273
253
 
274
254
  // declarative rules from above
275
255
  "resource-url-match": true,
@@ -282,8 +262,6 @@ export const builtInRulesets = {
282
262
  "resource-no-halfwidth-kana-characters": true,
283
263
  "resource-no-double-byte-space": true,
284
264
  "resource-no-space-with-fullwidth-punctuation": true,
285
- "resource-snake-case": true,
286
- "resource-camel-case": true,
287
265
  },
288
266
 
289
267
  source: {
@@ -353,6 +331,8 @@ class BuiltinPlugin extends Plugin {
353
331
  ResourceSourceICUPluralCategories,
354
332
  ResourceSourceICUUnexplainedParams,
355
333
  ResourceXML,
334
+ ResourceCamelCase,
335
+ ResourceSnakeCase,
356
336
  ...regexRules
357
337
  ];
358
338
  }
@@ -0,0 +1,86 @@
1
+ import ResourceRule from './ResourceRule.js';
2
+ import {Result} from 'ilib-lint-common';
3
+
4
+ /** @ignore @typedef {import('ilib-tools-common').Resource} Resource */
5
+
6
+ /**
7
+ * @classdesc Class representing an ilib-lint programmatic rule for linting camel cased strings.
8
+ * @class
9
+ * @augments ResourceRule
10
+ */
11
+ class ResourceCamelCase extends ResourceRule {
12
+ /**
13
+ * Create a ResourceCamelCase rule instance.
14
+ * @param {object} options
15
+ * @param {object} [options.param]
16
+ * @param {string[]} [options.param.except] An array of strings to exclude from the rule.
17
+ */
18
+ constructor(options) {
19
+ super(options);
20
+
21
+ this.name = "resource-camel-case";
22
+ this.description = "Ensure that when source strings contain only camel case and no whitespace, then the targets are the same";
23
+ this.link = "https://gihub.com/ilib-js/ilib-lint/blob/main/docs/resource-camel-case.md";
24
+ this.regexps = [
25
+ "^\\s*[a-z\\d]+([A-Z][a-z\\d]+)+\\s*$",
26
+ "^\\s*[A-Z][a-z\\d]+([A-Z][a-z\\d]+)+\\s*$",
27
+ ];
28
+ this.exceptions = Array.isArray(options?.param?.except) ? options.param.except : [];
29
+ }
30
+
31
+ /**
32
+ * Check if a source string is in camel case and if the target string is the same as the source.
33
+ * @public
34
+ * @override ResourceRule.matchString
35
+ * @param {{source: (String|undefined), target: (String|undefined), file: String, resource: Resource}} params
36
+ * @returns {Result|undefined} A Result with severity 'error' if the source string is in camel case and target string is not the same as the source string, otherwise undefined.
37
+ */
38
+ matchString({source, target, file, resource}) {
39
+ if (!source || !target) {
40
+ return;
41
+ }
42
+
43
+ const isException = this.exceptions.includes(source);
44
+ if (isException) {
45
+ return;
46
+ }
47
+
48
+ const isCamelCase = this.isCamelCase(source);
49
+ if (!isCamelCase) {
50
+ return;
51
+ }
52
+
53
+ if (source !== target) {
54
+ return new Result({
55
+ severity: "error",
56
+ id: resource.getKey(),
57
+ source,
58
+ description: "Do not translate the source string if it consists solely of camel cased strings and/or digits. Please update the target string so it matches the source string.",
59
+ rule: this,
60
+ locale: resource.sourceLocale,
61
+ pathName: file,
62
+ highlight: `<e0>${target}</e0>`
63
+ })
64
+ }
65
+ }
66
+
67
+ /**
68
+ * @public
69
+ * @param {string} string A non-empty string to check.
70
+ * @returns {boolean} Returns true for a string that is in camel case (matches one of the regular expressions declared in the constructor).
71
+ * Otherwise, returns false.
72
+ */
73
+ isCamelCase(string) {
74
+ const trimmed = string.trim();
75
+ for (const regexp of this.regexps) {
76
+ const match = RegExp(regexp).test(trimmed);
77
+
78
+ if (match) {
79
+ return true;
80
+ }
81
+ }
82
+ return false;
83
+ }
84
+ }
85
+
86
+ export default ResourceCamelCase;
@@ -0,0 +1,86 @@
1
+ import ResourceRule from './ResourceRule.js';
2
+ import {Result} from 'ilib-lint-common';
3
+
4
+ /** @ignore @typedef {import('ilib-tools-common').Resource} Resource */
5
+
6
+ /**
7
+ * @classdesc Class representing an ilib-lint programmatic rule for linting snake cased strings.
8
+ * @class
9
+ * @augments ResourceRule
10
+ */
11
+ class ResourceSnakeCase extends ResourceRule {
12
+ /**
13
+ * Create a ResourceSnakeCase rule instance.
14
+ * @param {object} options
15
+ * @param {object} [options.param]
16
+ * @param {string[]} [options.param.except] An array of strings to exclude from the rule.
17
+ */
18
+ constructor(options) {
19
+ super(options);
20
+
21
+ this.name = "resource-snake-case";
22
+ this.description = "Ensure that when source strings contain only snake case and no whitespace, then the targets are the same";
23
+ this.link = "https://gihub.com/ilib-js/ilib-lint/blob/main/docs/resource-snake-case.md",
24
+ this.regexps = [
25
+ "^\\s*[a-zA-Z0-9]*(_[a-zA-Z0-9]+)+\\s*$",
26
+ "^\\s*[a-zA-Z0-9]+(_[a-zA-Z0-9]+)*_\\s*$"
27
+ ]
28
+ this.exceptions = Array.isArray(options?.param?.except) ? options.param.except : [];
29
+ }
30
+
31
+ /**
32
+ * Check if a source string is in snake case and if the target string is the same as the source.
33
+ * @public
34
+ * @override ResourceRule.matchString
35
+ * @param {{source: (String|undefined), target: (String|undefined), file: String, resource: Resource}} params
36
+ * @returns {Result|undefined} A Result with severity 'error' if the source string is in snake case and target string is not the same as the source string, otherwise undefined.
37
+ */
38
+ matchString({source, target, file, resource}) {
39
+ if (!source || !target) {
40
+ return;
41
+ }
42
+
43
+ const isException = this.exceptions.includes(source);
44
+ if (isException) {
45
+ return;
46
+ }
47
+
48
+ const isSnakeCase = this.isSnakeCase(source);
49
+ if (!isSnakeCase) {
50
+ return;
51
+ }
52
+
53
+ if (source !== target) {
54
+ return new Result({
55
+ severity: "error",
56
+ id: resource.getKey(),
57
+ source,
58
+ description: "Do not translate the source string if it consists solely of snake cased strings and/or digits. Please update the target string so it matches the source string.",
59
+ rule: this,
60
+ locale: resource.sourceLocale,
61
+ pathName: file,
62
+ highlight: `<e0>${target}</e0>`
63
+ })
64
+ }
65
+ }
66
+
67
+ /**
68
+ * @public
69
+ * @param {string} string A non-empty string to check.
70
+ * @returns {boolean} Returns true for a string that is in snake case (matches one of the regular expressions declared in the constructor).
71
+ * Otherwise, returns false.
72
+ */
73
+ isSnakeCase(string) {
74
+ const trimmed = string.trim();
75
+ for (const regexp of this.regexps) {
76
+ const match = RegExp(regexp).test(trimmed);
77
+
78
+ if (match) {
79
+ return true;
80
+ }
81
+ }
82
+ return false;
83
+ }
84
+ }
85
+
86
+ export default ResourceSnakeCase;
@@ -0,0 +1,180 @@
1
+ import {Result} from "ilib-lint-common";
2
+ import ResourceCamelCase from "../ResourceCamelCase.js";
3
+ import {ResourceString} from "ilib-tools-common";
4
+
5
+ describe("ResourceCamelCase", () => {
6
+ test("creates ResourceCamelCase rule instance", () => {
7
+ const rule = new ResourceCamelCase({})
8
+
9
+ expect(rule).toBeInstanceOf(ResourceCamelCase);
10
+ expect(rule.getName()).toBe("resource-camel-case");
11
+ });
12
+
13
+ test.each([
14
+ undefined,
15
+ null,
16
+ true,
17
+ 100,
18
+ 'string',
19
+ {},
20
+ () => {},
21
+ ])("handles invalid `except` parameter gracefully (and does not break in runtime)", (invalidExcept) => {
22
+ const rule = new ResourceCamelCase({param: {except: invalidExcept}});
23
+
24
+ const resource = createTestResourceString({source: "camelCaseException", target: "someCamelCaseTarget"});
25
+ const result = rule.matchString({
26
+ source: resource.source,
27
+ target: resource.target,
28
+ file: resource.pathName,
29
+ resource
30
+ });
31
+
32
+ expect(result).toBeInstanceOf(Result);
33
+ expect(result.rule).toBeInstanceOf(ResourceCamelCase);
34
+ expect(result.severity).toEqual("error");
35
+ });
36
+
37
+ test.each([
38
+ {source: ""},
39
+ {source: undefined},
40
+ {source: null},
41
+ ])("returns `undefined` if source string is empty ($source)", ({source}) => {
42
+ const rule = new ResourceCamelCase({});
43
+ const resource = createTestResourceString({source, target: "some_target"});
44
+
45
+ const result = rule.matchString({
46
+ source: resource.source,
47
+ target: resource.target,
48
+ file: resource.pathName,
49
+ resource
50
+ });
51
+
52
+ expect(result).toBeUndefined();
53
+ });
54
+
55
+ test.each([
56
+ {target: ""},
57
+ {target: undefined},
58
+ {target: null},
59
+ ])("returns `undefined` if target string is empty ($target)", ({target}) => {
60
+ const rule = new ResourceCamelCase({});
61
+ const resource = createTestResourceString({source: "some_source", target});
62
+
63
+ const result = rule.matchString({
64
+ source: resource.source,
65
+ target: resource.target,
66
+ file: resource.pathName,
67
+ resource
68
+ });
69
+
70
+ expect(result).toBeUndefined();
71
+ });
72
+
73
+ test("returns `undefined` if source string is an exception", () => {
74
+ const options = {param: {except: ["camelCaseException"]}}
75
+ const rule = new ResourceCamelCase(options);
76
+ const resource = createTestResourceString({source: "camelCaseException", target: "some_target"});
77
+
78
+ const result = rule.matchString({
79
+ source: resource.source,
80
+ target: resource.target,
81
+ file: resource.pathName,
82
+ resource
83
+ });
84
+
85
+ expect(result).toBeUndefined();
86
+ });
87
+
88
+ test("returns `undefined` if source string is NOT in camel case", () => {
89
+ const rule = new ResourceCamelCase({});
90
+ const resource = createTestResourceString({source: "some source", target: "some target"});
91
+
92
+ const result = rule.matchString({
93
+ source: resource.source,
94
+ target: resource.target,
95
+ file: resource.pathName,
96
+ resource
97
+ });
98
+
99
+ expect(result).toBeUndefined();
100
+ });
101
+
102
+ test("returns `undefined` if source is in camel case and target is the same", () => {
103
+ const rule = new ResourceCamelCase({});
104
+ const resource = createTestResourceString({source: "camelCase", target: "camelCase"});
105
+
106
+ const result = rule.matchString({
107
+ source: resource.source,
108
+ target: resource.target,
109
+ file: resource.pathName,
110
+ resource
111
+ });
112
+
113
+ expect(result).toBeUndefined();
114
+ });
115
+
116
+ test("returns error if source is in camel case and target is different", () => {
117
+ const rule = new ResourceCamelCase({});
118
+ const resource = createTestResourceString({source: "camelCase", target: "differentTarget"});
119
+
120
+ const result = rule.matchString({
121
+ source: resource.source,
122
+ target: resource.target,
123
+ file: resource.pathName,
124
+ resource
125
+ });
126
+
127
+ expect(result).toBeInstanceOf(Result);
128
+ expect(result.rule).toBeInstanceOf(ResourceCamelCase);
129
+ expect(result.severity).toEqual("error");
130
+ });
131
+ });
132
+
133
+ describe('ResourceCamelCase.isCamelCase', () => {
134
+ test.each(
135
+ [
136
+ {name: "lower camel case", source: "camelCase"},
137
+ {name: "upper camel case a.k.a. pascal case", source: "PascalCase"},
138
+ {name: "randomly mixed camel case", source: "cAmelCaSe"},
139
+
140
+ {name: "any camel case with leading and trailing whitespace", source: " AnyCamelCase "},
141
+ {name: "any camel case with digits at any position", source: "C4m3lC4s3W1thD1g1ts"},
142
+ ]
143
+ )("returns `true` if source string is $name", ({source}) => {
144
+ const rule = new ResourceCamelCase({});
145
+
146
+ const result = rule.isCamelCase(source);
147
+
148
+ expect(result).toBe(true);
149
+ });
150
+
151
+ test.each([
152
+ {name: "whitespace solely", source: " "},
153
+ {name: "digits solely", source: "123"},
154
+ {name: "lowercase letters word solely", source: "word"},
155
+ {name: "uppercase letters word solely", source: "WORD"},
156
+ {name: "uppercase letters word solely", source: "Word"},
157
+
158
+ {name: "text and whitespace", source: "camel Case"},
159
+ {name: "camel case and text", source: "camelCase and text"},
160
+
161
+ {name: "trailing capitalized letter", source: "CamelCasE"},
162
+ {name: "multiple consecutive uppercase letters", source: "CAmelCase"},
163
+ ])("returns `false` if source string is $name", ({source}) => {
164
+ const rule = new ResourceCamelCase({});
165
+
166
+ const result = rule.isCamelCase(source);
167
+
168
+ expect(result).toBe(false);
169
+ });
170
+ });
171
+
172
+ function createTestResourceString({source, target}) {
173
+ return new ResourceString({
174
+ source,
175
+ target,
176
+ key: "camel.case.test.string.id",
177
+ targetLocale: "xd-XD",
178
+ pathName: "tests/for/camelCase.xliff"
179
+ });
180
+ }
@@ -0,0 +1,187 @@
1
+ import {ResourceString} from 'ilib-tools-common';
2
+ import {Result} from 'ilib-lint-common';
3
+ import ResourceSnakeCase from "../ResourceSnakeCase.js";
4
+
5
+ describe("ResourceSnakeCase", () => {
6
+ test("creates ResourceSnakeCase rule instance", () => {
7
+ const rule = new ResourceSnakeCase({});
8
+
9
+ expect(rule).toBeInstanceOf(ResourceSnakeCase);
10
+ expect(rule.getName()).toEqual("resource-snake-case");
11
+ });
12
+
13
+ test.each([
14
+ undefined,
15
+ null,
16
+ true,
17
+ 100,
18
+ 'string',
19
+ {},
20
+ () => {},
21
+ ])("handles invalid `except` parameter gracefully (and does not break in runtime)", (invalidExcept) => {
22
+ const rule = new ResourceSnakeCase({param: {except: invalidExcept}});
23
+
24
+ const resource = createTestResourceString({source: "snake_case_exception", target: "some_target"});
25
+ const result = rule.matchString({
26
+ source: resource.source,
27
+ target: resource.target,
28
+ file: resource.pathName,
29
+ resource
30
+ });
31
+
32
+ expect(result).toBeInstanceOf(Result);
33
+ expect(result.rule).toBeInstanceOf(ResourceSnakeCase);
34
+ expect(result.severity).toEqual("error");
35
+ });
36
+
37
+ test.each([
38
+ {source: ""},
39
+ {source: undefined},
40
+ {source: null},
41
+ ])("returns `undefined` if source string is empty ($source)", ({source}) => {
42
+ const rule = new ResourceSnakeCase({});
43
+ const resource = createTestResourceString({source, target: "some_target"});
44
+
45
+ const result = rule.matchString({
46
+ source: resource.source,
47
+ target: resource.target,
48
+ file: resource.pathName,
49
+ resource
50
+ });
51
+
52
+ expect(result).toBeUndefined();
53
+
54
+ });
55
+
56
+ test.each([
57
+ {target: ""},
58
+ {target: undefined},
59
+ {target: null},
60
+ ])("returns `undefined` if target string is empty ($target)", ({target}) => {
61
+ const rule = new ResourceSnakeCase({});
62
+ const resource = createTestResourceString({source: "some_source", target});
63
+
64
+ const result = rule.matchString({
65
+ source: resource.source,
66
+ target: resource.target,
67
+ file: resource.pathName,
68
+ resource
69
+ });
70
+
71
+ expect(result).toBeUndefined();
72
+ });
73
+
74
+ test("returns `undefined` if source string is an exception", () => {
75
+ const options = {param: {except: ["snake_case_exception"]}}
76
+ const rule = new ResourceSnakeCase(options);
77
+ const resource = createTestResourceString({source: "snake_case_exception", target: "some_target"});
78
+
79
+ const result = rule.matchString({
80
+ source: resource.source,
81
+ target: resource.target,
82
+ file: resource.pathName,
83
+ resource
84
+ });
85
+
86
+ expect(result).toBeUndefined();
87
+ });
88
+
89
+ test("returns `undefined` if source string is NOT in snake case", () => {
90
+ const rule = new ResourceSnakeCase({});
91
+ const resource = createTestResourceString({source: "some source", target: "some target"});
92
+
93
+ const result = rule.matchString({
94
+ source: resource.source,
95
+ target: resource.target,
96
+ file: resource.pathName,
97
+ resource
98
+ });
99
+
100
+ expect(result).toBeUndefined();
101
+ });
102
+
103
+ test("returns `undefined` if source is in snake case and target is the same", () => {
104
+ const rule = new ResourceSnakeCase({});
105
+ const resource = createTestResourceString({source: "snake_case", target: "snake_case"});
106
+
107
+ const result = rule.matchString({
108
+ source: resource.source,
109
+ target: resource.target,
110
+ file: resource.pathName,
111
+ resource
112
+ });
113
+
114
+ expect(result).toBeUndefined();
115
+ });
116
+
117
+ test("returns error if source is in snake case and target is different", () => {
118
+ const rule = new ResourceSnakeCase({});
119
+ const resource = createTestResourceString({source: "snake_case", target: "different_target"});
120
+
121
+ const result = rule.matchString({
122
+ source: resource.source,
123
+ target: resource.target,
124
+ file: resource.pathName,
125
+ resource
126
+ });
127
+
128
+ expect(result).toBeInstanceOf(Result);
129
+ expect(result.rule).toBeInstanceOf(ResourceSnakeCase);
130
+ expect(result.severity).toEqual("error");
131
+ });
132
+ });
133
+
134
+ describe('ResourceSnakeCase.isSnakeCase', () => {
135
+ test.each(
136
+ [
137
+ {name: "snake case", source: "snake_case"},
138
+ {name: "snake case with leading and trailing whitespace", source: " snake_case "},
139
+ {name: "snake case with numbers (123)", source: " snake_case123 "},
140
+ {name: "snake case with underscored numbers (_123)", source: " snake_case_123 "},
141
+
142
+ {name: "screaming snake case", source: "SOME_SCREAMING_SNAKE_CASE"},
143
+ {name: "screaming snake case with leading and trailing whitespace", source: " SOME_SCREAMING_SNAKE_CASE "},
144
+ {name: "screaming snake case with numbers", source: "SOME_SCREAMING_SNAKE_CASE123 "},
145
+ {name: "screaming snake case with underscored numbers", source: "SOME_SCREAMING_SNAKE_CASE_123 "},
146
+
147
+ {name: "camel snake case", source: "camel_Snake_Case"},
148
+ {name: "came snake case with leading and trailing whitespace", source: " camel_Snake_Case "},
149
+ {name: "camel snake case with numbers", source: "camel_Snake_Case123 "},
150
+ {name: "camel snake case with underscored numbers", source: "camel_Snake_Case_123 "},
151
+ ]
152
+ )("returns `true` if source string is $name", ({source}) => {
153
+ const rule = new ResourceSnakeCase({});
154
+
155
+ const result = rule.isSnakeCase(source);
156
+
157
+ expect(result).toBe(true);
158
+ });
159
+
160
+ test.each(
161
+ [
162
+ {name: "whitespace (solely)", source: " "},
163
+ {name: "text and whitespace", source: "snake case"},
164
+ {name: "snake case and text", source: "snake_case and text"},
165
+ {name: "screaming snake case and text", source: "SCREAMING_SNAKE_CASE and text"},
166
+ {name: "mixed case", source: "mixed_CASE"},
167
+ ]
168
+ )("returns `false` if string is $name", ({name, source}) => {
169
+ const rule = new ResourceSnakeCase({});
170
+ const resource = createTestResourceString({source, target: "does not matter"});
171
+
172
+ const result = rule.matchString({source: resource.source});
173
+
174
+ expect(result).toBeUndefined();
175
+ });
176
+ });
177
+
178
+ function createTestResourceString({source, target}) {
179
+ return new ResourceString({
180
+ source,
181
+ target,
182
+ key: "snake.case.test.string.id",
183
+ targetLocale: "xd-XD",
184
+ pathName: "tests/for/snake_case.xliff"
185
+ });
186
+ }
187
+