@discord/intl-loader-core 0.11.2-rc.3 → 0.11.2
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 +2 -3
- package/src/processing.js +13 -0
- package/src/watcher.js +102 -61
- package/types/src/processing.d.ts +10 -0
- package/types/src/watcher.d.ts +33 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@discord/intl-loader-core",
|
|
3
|
-
"version": "0.11.2
|
|
3
|
+
"version": "0.11.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Core utilities for writing loaders and transformers using @discord/intl",
|
|
6
6
|
"author": "Jon Egeland",
|
|
@@ -28,8 +28,7 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"chokidar": "^3.6.0",
|
|
30
30
|
"debug": "^4.3.6",
|
|
31
|
-
"
|
|
32
|
-
"@discord/intl-message-database": "0.11.2-rc.3"
|
|
31
|
+
"@discord/intl-message-database": "0.11.2"
|
|
33
32
|
},
|
|
34
33
|
"devDependencies": {
|
|
35
34
|
"@types/debug": "^4.1.12",
|
package/src/processing.js
CHANGED
|
@@ -54,6 +54,18 @@ function buildTranslationsLocaleMap(sourcePath, sourceFile, translationsPath) {
|
|
|
54
54
|
function findAllMessagesFiles(directories, defaultLocale = 'en-US') {
|
|
55
55
|
return database.findAllMessagesFiles(directories, defaultLocale);
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Given an arbitrary list of `files`, keep only those that can be treated as messages files, either
|
|
59
|
+
* definitions or translations. The returned list is a set of descriptors that can be processed by
|
|
60
|
+
* `processAllMessagesFiles`.
|
|
61
|
+
*
|
|
62
|
+
* @param {string[]} files
|
|
63
|
+
* @param {string} defaultLocale
|
|
64
|
+
* @returns {import('../types').IntlMessagesFileDescriptor[]}
|
|
65
|
+
*/
|
|
66
|
+
function filterAllMessagesFiles(files, defaultLocale = 'en-US') {
|
|
67
|
+
return database.filterAllMessagesFiles(files, defaultLocale);
|
|
68
|
+
}
|
|
57
69
|
|
|
58
70
|
/**
|
|
59
71
|
* Iterate the given `files`, processing each one's content into the database. Processing is done
|
|
@@ -217,6 +229,7 @@ function generateTypeDefinitions(sourcePath, outputFile, allowNullability = fals
|
|
|
217
229
|
|
|
218
230
|
module.exports = {
|
|
219
231
|
findAllMessagesFiles,
|
|
232
|
+
filterAllMessagesFiles,
|
|
220
233
|
processAllMessagesFiles,
|
|
221
234
|
generateTypeDefinitions,
|
|
222
235
|
precompileFileForLocale,
|
package/src/watcher.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const path = require('node:path');
|
|
2
2
|
|
|
3
3
|
const chokidar = require('chokidar');
|
|
4
|
-
const fg = require('fast-glob');
|
|
5
4
|
const debug = require('debug')('intl:loader-core:watcher');
|
|
6
5
|
const {
|
|
7
6
|
isMessageDefinitionsFile,
|
|
@@ -9,93 +8,135 @@ const {
|
|
|
9
8
|
} = require('@discord/intl-message-database');
|
|
10
9
|
|
|
11
10
|
const { database } = require('./database');
|
|
12
|
-
const {
|
|
11
|
+
const {
|
|
12
|
+
processDefinitionsFile,
|
|
13
|
+
precompileFileForLocale,
|
|
14
|
+
generateTypeDefinitions,
|
|
15
|
+
findAllMessagesFiles,
|
|
16
|
+
filterAllMessagesFiles,
|
|
17
|
+
processAllMessagesFiles,
|
|
18
|
+
} = require('./processing');
|
|
13
19
|
|
|
14
20
|
const ALWAYS_IGNORE_PATTERNS = [
|
|
15
21
|
// Ignore our own compiled message files, even though they shouldn't have a matching extension.
|
|
16
22
|
'*.compiled.messages.*',
|
|
23
|
+
'*.d.ts',
|
|
24
|
+
'*.d.ts.map',
|
|
17
25
|
];
|
|
18
26
|
// TODO: This should come from the database extension? Or Utilities? Unsure, but the extensions
|
|
19
27
|
// should have some centralized location in general
|
|
20
|
-
const
|
|
28
|
+
const MESSAGES_FILE_PATTERNS = ['**/*.messages.*'];
|
|
21
29
|
const DEFAULT_LOCALE = 'en-US';
|
|
22
30
|
|
|
23
31
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
32
|
+
* Start a new filesystem watcher to discover and monitor messages files, allowing consumers to
|
|
33
|
+
* react to changes in a single, consistent way.
|
|
34
|
+
*
|
|
35
|
+
* @param {string[]} watchedFolders List of folders to watch recursively.
|
|
36
|
+
* @param {{
|
|
37
|
+
* ignore?: string[],
|
|
38
|
+
* skipInitial?: boolean,
|
|
39
|
+
* persistent?: boolean,
|
|
40
|
+
* }} options
|
|
27
41
|
*/
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
42
|
+
async function watchMessagesFiles(
|
|
43
|
+
watchedFolders,
|
|
44
|
+
{ ignore = [], skipInitial = false, persistent = true } = {},
|
|
45
|
+
) {
|
|
46
|
+
debug('Pre-initializing database with all discoverable messages files');
|
|
47
|
+
processAllMessagesFiles(findAllMessagesFiles(watchedFolders));
|
|
35
48
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
precompileFileForLocale(filePath, result.locale, undefined, {
|
|
41
|
-
format,
|
|
42
|
-
bundleSecrets,
|
|
43
|
-
});
|
|
49
|
+
const ignoredPatterns = ignore.concat(ALWAYS_IGNORE_PATTERNS);
|
|
50
|
+
const globs = watchedFolders.flatMap((folder) =>
|
|
51
|
+
MESSAGES_FILE_PATTERNS.map((pattern) => path.join(folder, pattern)),
|
|
52
|
+
);
|
|
44
53
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
debug(`Initializing watch for patterns:\n- ${globs.join('\n- ')}`);
|
|
55
|
+
const watcher = chokidar.watch(globs, {
|
|
56
|
+
ignored: ignoredPatterns,
|
|
57
|
+
ignoreInitial: skipInitial,
|
|
58
|
+
persistent,
|
|
59
|
+
});
|
|
60
|
+
watcher.on('all', (event, path) => {
|
|
61
|
+
processAllMessagesFiles(filterAllMessagesFiles([path]));
|
|
62
|
+
debug(`watcher got event: ${event}, for path ${path}`);
|
|
63
|
+
});
|
|
64
|
+
for (const signal of ['SIGINT', 'SIGTERM', 'SIGQUIT']) {
|
|
65
|
+
process.on(signal, async () => {
|
|
66
|
+
debug(`Stopping watch due to`, signal);
|
|
67
|
+
await watcher.close();
|
|
68
|
+
debug('Watch stopped');
|
|
49
69
|
});
|
|
50
|
-
debug(`Wrote definitions to: ${outputPath}`);
|
|
51
|
-
} catch (e) {
|
|
52
|
-
debug('[INTL Error] Failed to compile messages');
|
|
53
|
-
console.error(e);
|
|
54
70
|
}
|
|
71
|
+
|
|
72
|
+
return watcher;
|
|
55
73
|
}
|
|
56
74
|
|
|
57
75
|
/**
|
|
58
|
-
*
|
|
76
|
+
* Watch the file system for any changes to message files and regenerate their types.
|
|
77
|
+
*
|
|
78
|
+
* @param {chokidar.FSWatcher} watcher
|
|
79
|
+
* @param {{
|
|
80
|
+
* allowNullability?: boolean
|
|
81
|
+
* }} options
|
|
82
|
+
*/
|
|
83
|
+
async function generateMessageTypes(watcher, { allowNullability }) {
|
|
84
|
+
watcher.on('all', (_, filePath) => {
|
|
85
|
+
if (!isMessageDefinitionsFile(filePath)) return;
|
|
86
|
+
debug(`Regenerating types for ${filePath}`);
|
|
87
|
+
generateTypeDefinitions(filePath, undefined, allowNullability);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Watch the file system for changes to message _definitions_ files, and pre-process them into
|
|
93
|
+
* compiled assets (with the extension `.compiled.messages.${assetExtension}`).
|
|
94
|
+
*
|
|
95
|
+
* @param {chokidar.FSWatcher} watcher
|
|
59
96
|
* @param {{
|
|
60
|
-
* watch?: boolean,
|
|
61
97
|
* ignore?: string[],
|
|
62
98
|
* assetExtension?: string
|
|
63
99
|
* precompileOptions?: import('./processing').IntlPrecompileOptions,
|
|
64
100
|
* }} options
|
|
65
101
|
*/
|
|
66
|
-
async function
|
|
67
|
-
|
|
68
|
-
{
|
|
102
|
+
async function precompileMessageDefinitionsFiles(
|
|
103
|
+
watcher,
|
|
104
|
+
{ assetExtension = 'json', precompileOptions = {} } = {},
|
|
69
105
|
) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
debug(`Configured message file patterns:\n- ${globs.join('\n- ')}`);
|
|
106
|
+
watcher.on('all', (_, filePath) => {
|
|
107
|
+
const { format = IntlCompiledMessageFormat.KeylessJson, bundleSecrets = false } =
|
|
108
|
+
precompileOptions;
|
|
109
|
+
if (!isMessageDefinitionsFile(filePath)) return;
|
|
75
110
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
111
|
+
debug(`Processing file: ${filePath}`);
|
|
112
|
+
try {
|
|
113
|
+
// Convert the file name from `.messages.js` to `.compiled.messages.jsona` for output.
|
|
114
|
+
const outputPath = filePath.replace(
|
|
115
|
+
/\.messages\.js$/,
|
|
116
|
+
`.compiled.messages.${assetExtension}`,
|
|
117
|
+
);
|
|
118
|
+
const result = processDefinitionsFile(filePath);
|
|
119
|
+
precompileFileForLocale(filePath, result.locale, undefined, {
|
|
120
|
+
format,
|
|
121
|
+
bundleSecrets,
|
|
122
|
+
});
|
|
87
123
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
.on('all', (event, filePath) => {
|
|
93
|
-
debug(`Got event ${event} for ${filePath}`);
|
|
94
|
-
processFile(filePath, assetExtension, precompileOptions);
|
|
124
|
+
database.processDefinitionsFile(filePath);
|
|
125
|
+
database.precompile(filePath, DEFAULT_LOCALE, outputPath, {
|
|
126
|
+
format: IntlCompiledMessageFormat.KeylessJson,
|
|
127
|
+
bundleSecrets,
|
|
95
128
|
});
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
129
|
+
debug(`Wrote definitions to: ${outputPath}`);
|
|
130
|
+
} catch (e) {
|
|
131
|
+
debug('[INTL Error] Failed to compile messages');
|
|
132
|
+
console.error(e);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
99
135
|
}
|
|
100
136
|
|
|
101
|
-
module.exports = {
|
|
137
|
+
module.exports = {
|
|
138
|
+
watchMessagesFiles,
|
|
139
|
+
precompileMessageDefinitionsFiles,
|
|
140
|
+
generateMessageTypes,
|
|
141
|
+
ALWAYS_IGNORE_PATTERNS,
|
|
142
|
+
};
|
|
@@ -11,6 +11,16 @@ export type IntlPrecompileOptions = {
|
|
|
11
11
|
* @returns {import('../types').IntlMessagesFileDescriptor[]}
|
|
12
12
|
*/
|
|
13
13
|
export function findAllMessagesFiles(directories: string[], defaultLocale?: string): import("../types").IntlMessagesFileDescriptor[];
|
|
14
|
+
/**
|
|
15
|
+
* Given an arbitrary list of `files`, keep only those that can be treated as messages files, either
|
|
16
|
+
* definitions or translations. The returned list is a set of descriptors that can be processed by
|
|
17
|
+
* `processAllMessagesFiles`.
|
|
18
|
+
*
|
|
19
|
+
* @param {string[]} files
|
|
20
|
+
* @param {string} defaultLocale
|
|
21
|
+
* @returns {import('../types').IntlMessagesFileDescriptor[]}
|
|
22
|
+
*/
|
|
23
|
+
export function filterAllMessagesFiles(files: string[], defaultLocale?: string): import("../types").IntlMessagesFileDescriptor[];
|
|
14
24
|
/**
|
|
15
25
|
* Iterate the given `files`, processing each one's content into the database. Processing is done
|
|
16
26
|
* in parallel using native acceleration, and returns the list of all file names that were used.
|
package/types/src/watcher.d.ts
CHANGED
|
@@ -1,16 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Start a new filesystem watcher to discover and monitor messages files, allowing consumers to
|
|
3
|
+
* react to changes in a single, consistent way.
|
|
4
|
+
*
|
|
5
|
+
* @param {string[]} watchedFolders List of folders to watch recursively.
|
|
6
|
+
* @param {{
|
|
7
|
+
* ignore?: string[],
|
|
8
|
+
* skipInitial?: boolean,
|
|
9
|
+
* persistent?: boolean,
|
|
10
|
+
* }} options
|
|
11
|
+
*/
|
|
12
|
+
export function watchMessagesFiles(watchedFolders: string[], { ignore, skipInitial, persistent }?: {
|
|
13
|
+
ignore?: string[];
|
|
14
|
+
skipInitial?: boolean;
|
|
15
|
+
persistent?: boolean;
|
|
16
|
+
}): Promise<chokidar.FSWatcher>;
|
|
17
|
+
/**
|
|
18
|
+
* Watch the file system for changes to message _definitions_ files, and pre-process them into
|
|
19
|
+
* compiled assets (with the extension `.compiled.messages.${assetExtension}`).
|
|
20
|
+
*
|
|
21
|
+
* @param {chokidar.FSWatcher} watcher
|
|
3
22
|
* @param {{
|
|
4
|
-
* watch?: boolean,
|
|
5
23
|
* ignore?: string[],
|
|
6
24
|
* assetExtension?: string
|
|
7
25
|
* precompileOptions?: import('./processing').IntlPrecompileOptions,
|
|
8
26
|
* }} options
|
|
9
27
|
*/
|
|
10
|
-
export function
|
|
11
|
-
watch?: boolean;
|
|
28
|
+
export function precompileMessageDefinitionsFiles(watcher: chokidar.FSWatcher, { assetExtension, precompileOptions }?: {
|
|
12
29
|
ignore?: string[];
|
|
13
30
|
assetExtension?: string;
|
|
14
31
|
precompileOptions?: import("./processing").IntlPrecompileOptions;
|
|
15
32
|
}): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Watch the file system for any changes to message files and regenerate their types.
|
|
35
|
+
*
|
|
36
|
+
* @param {chokidar.FSWatcher} watcher
|
|
37
|
+
* @param {{
|
|
38
|
+
* allowNullability?: boolean
|
|
39
|
+
* }} options
|
|
40
|
+
*/
|
|
41
|
+
export function generateMessageTypes(watcher: chokidar.FSWatcher, { allowNullability }: {
|
|
42
|
+
allowNullability?: boolean;
|
|
43
|
+
}): Promise<void>;
|
|
16
44
|
export const ALWAYS_IGNORE_PATTERNS: string[];
|
|
45
|
+
import chokidar = require("chokidar");
|