@discord/eslint-plugin-discord-intl 0.27.2 → 0.27.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/lib/native-validation.js +65 -33
- package/lib/traverse.js +1 -1
- package/package.json +2 -2
package/lib/native-validation.js
CHANGED
|
@@ -4,29 +4,38 @@
|
|
|
4
4
|
/** @typedef {import('eslint').Rule.ReportDescriptorLocation} ReportDescriptorLocation */
|
|
5
5
|
/** @typedef {import('eslint').AST.SourceLocation} SourceLocation */
|
|
6
6
|
/** @typedef {import('eslint').SourceCode} SourceCode */
|
|
7
|
-
/** @typedef {import("@discord/intl-
|
|
7
|
+
/** @typedef {import("@discord/intl-message-database").IntlDiagnostic} IntlDiagnostic */
|
|
8
8
|
|
|
9
9
|
const crypto = require('node:crypto');
|
|
10
|
-
const
|
|
11
|
-
processDefinitionsFile,
|
|
12
|
-
database,
|
|
13
|
-
processAllMessagesFiles,
|
|
14
|
-
findAllMessagesFiles,
|
|
15
|
-
} = require('@discord/intl-loader-core');
|
|
10
|
+
const path = require('node:path');
|
|
16
11
|
const { traverseMessageDefinitions, isDefinitionsFile } = require('./traverse');
|
|
12
|
+
const {
|
|
13
|
+
IntlMessagesDatabase,
|
|
14
|
+
IntlDatabaseInsertStrategy,
|
|
15
|
+
} = require('@discord/intl-message-database');
|
|
17
16
|
/** @type {Map<SourceCode, Record<string, IntlDiagnostic[]>>} */
|
|
18
17
|
const FILE_VALIDATIONS = new Map();
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
/** @type {Map<string, IntlMessagesDatabase>} */
|
|
20
|
+
const PROJECT_DATABASE_MAP = new Map();
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* @param {string} directory
|
|
24
|
+
* @returns {IntlMessagesDatabase}
|
|
24
25
|
*/
|
|
25
26
|
function ensureInitialized(directory) {
|
|
26
|
-
|
|
27
|
+
const key = path.resolve(directory);
|
|
28
|
+
const existing = PROJECT_DATABASE_MAP.get(key);
|
|
29
|
+
if (existing != null) return existing;
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
const database = new IntlMessagesDatabase();
|
|
32
|
+
database.processAllMessagesFiles(
|
|
33
|
+
database.findAllMessagesFiles([directory], 'en-US'),
|
|
34
|
+
IntlDatabaseInsertStrategy.Create,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
PROJECT_DATABASE_MAP.set(key, database);
|
|
38
|
+
return database;
|
|
30
39
|
}
|
|
31
40
|
|
|
32
41
|
/**
|
|
@@ -37,12 +46,13 @@ function ensureInitialized(directory) {
|
|
|
37
46
|
* validations, allowing them to be reused across multiple rules without wasting work validating
|
|
38
47
|
* the same messages multiple times.
|
|
39
48
|
*
|
|
49
|
+
* @param {IntlMessagesDatabase} database
|
|
40
50
|
* @param {SourceCode} sourceCode
|
|
41
51
|
* @param {string} fileName
|
|
42
52
|
* @param {string} content
|
|
43
53
|
* @return {Record<string, IntlDiagnostic[]>}
|
|
44
54
|
*/
|
|
45
|
-
function processAndValidateNative(sourceCode, fileName, content) {
|
|
55
|
+
function processAndValidateNative(database, sourceCode, fileName, content) {
|
|
46
56
|
const fileKey = crypto.hash('sha1', content);
|
|
47
57
|
const existing = FILE_VALIDATIONS.get(sourceCode);
|
|
48
58
|
if (existing != null) return existing;
|
|
@@ -51,30 +61,31 @@ function processAndValidateNative(sourceCode, fileName, content) {
|
|
|
51
61
|
// native database that this is a JS message definition _somehow_, so we'll make a random
|
|
52
62
|
// name that should be relatively unique.
|
|
53
63
|
const processingFileName = fileName === '<input>' ? `${fileKey}.messages.js` : fileName;
|
|
54
|
-
const processResult =
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
const processResult = database.processDefinitionsFileContent(
|
|
65
|
+
processingFileName,
|
|
66
|
+
content,
|
|
67
|
+
'en-US',
|
|
68
|
+
IntlDatabaseInsertStrategy.Update,
|
|
69
|
+
);
|
|
57
70
|
|
|
58
71
|
/** @type {Record<string, IntlDiagnostic[]>} */
|
|
59
72
|
const validations = {};
|
|
60
73
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
});
|
|
77
|
-
}
|
|
74
|
+
for (const error of processResult.errors) {
|
|
75
|
+
const key = error.key ?? 'file';
|
|
76
|
+
(validations[key] ??= []).push({
|
|
77
|
+
name: 'Processing::' + error.name,
|
|
78
|
+
description: error.message,
|
|
79
|
+
key: error.key ?? 'file',
|
|
80
|
+
file: error.file ?? processingFileName,
|
|
81
|
+
messageLine: error.line ?? 0,
|
|
82
|
+
messageCol: error.col ?? 0,
|
|
83
|
+
start: 0,
|
|
84
|
+
end: 2,
|
|
85
|
+
locale: error.locale ?? 'definition',
|
|
86
|
+
category: 'correctness',
|
|
87
|
+
fixes: [],
|
|
88
|
+
});
|
|
78
89
|
}
|
|
79
90
|
|
|
80
91
|
for (const diagnostic of database.validateMessages()) {
|
|
@@ -97,8 +108,11 @@ function processAndValidateNative(sourceCode, fileName, content) {
|
|
|
97
108
|
*/
|
|
98
109
|
function traverseAndReportMatchingNativeValidations(context, predicate) {
|
|
99
110
|
if (!isDefinitionsFile(context.filename, context.sourceCode.text)) return {};
|
|
100
|
-
|
|
111
|
+
|
|
112
|
+
const projectDirectory = context.settings['intl']?.['projectDirectory'] ?? context.cwd;
|
|
113
|
+
const database = ensureInitialized(projectDirectory);
|
|
101
114
|
const validations = processAndValidateNative(
|
|
115
|
+
database,
|
|
102
116
|
context.sourceCode,
|
|
103
117
|
context.filename,
|
|
104
118
|
context.sourceCode.text,
|
|
@@ -114,6 +128,24 @@ function traverseAndReportMatchingNativeValidations(context, predicate) {
|
|
|
114
128
|
column: diagnostic.messageCol,
|
|
115
129
|
});
|
|
116
130
|
|
|
131
|
+
// Sometimes we get a diagnostic pointing to a different file than the
|
|
132
|
+
// current source code. Not totally sure why for now, so lets just noisily
|
|
133
|
+
// log the diagnostic to be able to investigate further when it happens.
|
|
134
|
+
const textLen = context.sourceCode.text.length;
|
|
135
|
+
if (
|
|
136
|
+
diagnostic.file !== context.physicalFilename ||
|
|
137
|
+
messageOffset + diagnostic.start > textLen ||
|
|
138
|
+
messageOffset + diagnostic.end > textLen
|
|
139
|
+
) {
|
|
140
|
+
console.error('Invalid diagnostic span from intl vs eslint:');
|
|
141
|
+
console.log('ESLint source filename:', context.filename);
|
|
142
|
+
console.log(diagnostic);
|
|
143
|
+
return {
|
|
144
|
+
start: context.sourceCode.getLocFromIndex(1),
|
|
145
|
+
end: context.sourceCode.getLocFromIndex(1),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
117
149
|
return {
|
|
118
150
|
start: context.sourceCode.getLocFromIndex(messageOffset + diagnostic.start),
|
|
119
151
|
end: context.sourceCode.getLocFromIndex(messageOffset + diagnostic.end),
|
package/lib/traverse.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { isMessageDefinitionsFile } = require('@discord/intl-
|
|
1
|
+
const { isMessageDefinitionsFile } = require('@discord/intl-message-database');
|
|
2
2
|
|
|
3
3
|
/** @typedef {import('eslint').Rule.NodeParentExtension} NodeParentExtension */
|
|
4
4
|
/** @typedef {import('eslint').SourceCode} SourceCode */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@discord/eslint-plugin-discord-intl",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"description": "ESLint plugin for validating and linting messages and translations using @discord/intl",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@typescript-eslint/scope-manager": "^8.8.1",
|
|
14
|
-
"@discord/intl-
|
|
14
|
+
"@discord/intl-message-database": "0.27.4"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@types/eslint": "^8.56.12",
|