1 | import { AnyJson } from '@salesforce/ts-types';
|
2 | import { SfError } from './sfError';
|
3 | export type Tokens = Array<string | boolean | number | null | undefined>;
|
4 | export type StructuredMessage = {
|
5 | message: string;
|
6 | name: string;
|
7 | actions?: string[];
|
8 | };
|
9 | /**
|
10 | * A loader function to return messages.
|
11 | *
|
12 | * @param locale The local set by the framework.
|
13 | */
|
14 | export type LoaderFunction<T extends string> = (locale: string) => Messages<T>;
|
15 | export type StoredMessage = string | string[] | {
|
16 | [s: string]: StoredMessage;
|
17 | };
|
18 | export type StoredMessageMap = Map<string, StoredMessage>;
|
19 | /**
|
20 | * The core message framework manages messages and allows them to be accessible by
|
21 | * all plugins and consumers of sfdx-core. It is set up to handle localization down
|
22 | * the road at no additional effort to the consumer. Messages can be used for
|
23 | * anything from user output (like the console), to error messages, to returned
|
24 | * data from a method.
|
25 | *
|
26 | * Messages are loaded from loader functions. The loader functions will only run
|
27 | * when a message is required. This prevents all messages from being loaded into memory at
|
28 | * application startup. The functions can load from memory, a file, or a server.
|
29 | *
|
30 | * In the beginning of your app or file, add the loader functions to be used later. If using
|
31 | * json or js files in a root messages directory (`<moduleRoot>/messages`), load the entire directory
|
32 | * automatically with {@link Messages.importMessagesDirectory}. Message files must be the following formates.
|
33 | *
|
34 | * A `.json` file:
|
35 | * ```json
|
36 | * {
|
37 | * "msgKey": "A message displayed in the user",
|
38 | * "msgGroup": {
|
39 | * "anotherMsgKey": "Another message displayed to the user"
|
40 | * },
|
41 | * "listOfMessage": ["message1", "message2"]
|
42 | * }
|
43 | * ```
|
44 | *
|
45 | * A `.js` file:
|
46 | * ```javascript
|
47 | * module.exports = {
|
48 | * msgKey: 'A message displayed in the user',
|
49 | * msgGroup: {
|
50 | * anotherMsgKey: 'Another message displayed to the user'
|
51 | * },
|
52 | * listOfMessage: ['message1', 'message2']
|
53 | * }
|
54 | * ```
|
55 | *
|
56 | * A `.md` file:
|
57 | * ```markdown
|
58 | * # msgKey
|
59 | * A message displayed in the user
|
60 | *
|
61 | * # msgGroup.anotherMsgKey
|
62 | * Another message displayed to the user
|
63 | *
|
64 | * # listOfMessage
|
65 | * - message1
|
66 | * - message2
|
67 | * ```
|
68 | *
|
69 | * The values support [util.format](https://nodejs.org/api/util.html#util_util_format_format_args) style strings
|
70 | * that apply the tokens passed into {@link Message.getMessage}
|
71 | *
|
72 | * **Note:** When running unit tests individually, you may see errors that the messages aren't found.
|
73 | * This is because `index.js` isn't loaded when tests run like they are when the package is required.
|
74 | * To allow tests to run, import the message directory in each test (it will only
|
75 | * do it once) or load the message file the test depends on individually.
|
76 | *
|
77 | * ```typescript
|
78 | * // Create loader functions for all files in the messages directory
|
79 | * Messages.importMessagesDirectory(__dirname);
|
80 | *
|
81 | * // Now you can use the messages from anywhere in your code or file.
|
82 | * // If using importMessageDirectory, the bundle name is the file name.
|
83 | * const messages: Messages = Messages.load(packageName, bundleName);
|
84 | *
|
85 | * // Messages now contains all the message in the bundleName file.
|
86 | * messages.getMessage('authInfoCreationError');
|
87 | * ```
|
88 | */
|
89 | export declare class Messages<T extends string> {
|
90 | private messages;
|
91 | private static loaders;
|
92 | private static bundles;
|
93 | /**
|
94 | * The locale of the messages in this bundle.
|
95 | */
|
96 | readonly locale: string;
|
97 | /**
|
98 | * The bundle name.
|
99 | */
|
100 | readonly bundleName: string;
|
101 | /**
|
102 | * Create a new messages bundle.
|
103 | *
|
104 | * **Note:** Use {Messages.load} unless you are writing your own loader function.
|
105 | *
|
106 | * @param bundleName The bundle name.
|
107 | * @param locale The locale.
|
108 | * @param messages The messages. Can not be modified once created.
|
109 | */
|
110 | constructor(bundleName: string, locale: string, messages: StoredMessageMap);
|
111 | /**
|
112 | * Internal readFile. Exposed for unit testing. Do not use util/fs.readFile as messages.js
|
113 | * should have no internal dependencies.
|
114 | *
|
115 | * @param filePath read file target.
|
116 | * @ignore
|
117 | */
|
118 | static readFile: (filePath: string) => AnyJson;
|
119 | /**
|
120 | * Get the locale. This will always return 'en_US' but will return the
|
121 | * machine's locale in the future.
|
122 | */
|
123 | static getLocale(): string;
|
124 | /**
|
125 | * Set a custom loader function for a package and bundle that will be called on { Messages.load}.
|
126 | *
|
127 | * packageName The npm package name.
|
128 | * bundle The name of the bundle.
|
129 | * function.
loader The loader |
130 | */
|
131 | static setLoaderFunction(packageName: string, bundle: string, loader: LoaderFunction<string>): void;
|
132 | /**
|
133 | * Generate a file loading function. Use {@link Messages.importMessageFile} unless
|
134 | * overriding the bundleName is required, then manually pass the loader
|
135 | * function to {@link Messages.setLoaderFunction}.
|
136 | *
|
137 | * @param bundleName The name of the bundle.
|
138 | * @param filePath The messages file path.
|
139 | */
|
140 | static generateFileLoaderFunction(bundleName: string, filePath: string): LoaderFunction<string>;
|
141 | /**
|
142 | * Add a single message file to the list of loading functions using the file name as the bundle name.
|
143 | * The loader will only be added if the bundle name is not already taken.
|
144 | *
|
145 | * @param packageName The npm package name.
|
146 | * @param filePath The path of the file.
|
147 | */
|
148 | static importMessageFile(packageName: string, filePath: string): void;
|
149 | /**
|
150 | * Import all json and js files in a messages directory. Use the file name as the bundle key when
|
151 | * {@link Messages.load} is called. By default, we're assuming the moduleDirectoryPart is a
|
152 | * typescript project and will truncate to root path (where the package.json file is). If your messages
|
153 | * directory is in another spot or you are not using typescript, pass in false for truncateToProjectPath.
|
154 | *
|
155 | * ```
|
156 | * // e.g. If your message directory is in the project root, you would do:
|
157 | * Messages.importMessagesDirectory(__dirname);
|
158 | * ```
|
159 | *
|
160 | * @param moduleDirectoryPath The path to load the messages folder.
|
161 | * @param truncateToProjectPath Will look for the messages directory in the project root (where the package.json file is located).
|
162 | * i.e., the module is typescript and the messages folder is in the top level of the module directory.
|
163 | * @param packageName The npm package name. Figured out from the root directory's package.json.
|
164 | */
|
165 | static importMessagesDirectory(moduleDirectoryPath: string, truncateToProjectPath?: boolean, packageName?: string): void;
|
166 | /**
|
167 | * Load messages for a given package and bundle. If the bundle is not already cached, use the loader function
|
168 | * created from {@link Messages.setLoaderFunction} or {@link Messages.importMessagesDirectory}.
|
169 | *
|
170 | * **NOTE: Use {@link Messages.load} instead for safe message validation and usage.**
|
171 | *
|
172 | * ```typescript
|
173 | * Messages.importMessagesDirectory(__dirname);
|
174 | * const messages = Messages.load('packageName', 'bundleName');
|
175 | * ```
|
176 | *
|
177 | * @param packageName The name of the npm package.
|
178 | * @param bundleName The name of the bundle to load.
|
179 | */
|
180 | static loadMessages(packageName: string, bundleName: string): Messages<string>;
|
181 | /**
|
182 | * Load messages for a given package and bundle. If the bundle is not already cached, use the loader function
|
183 | * created from {@link Messages.setLoaderFunction} or {@link Messages.importMessagesDirectory}.
|
184 | *
|
185 | * The message keys that will be used must be passed in for validation. This prevents runtime errors if messages are used but not defined.
|
186 | *
|
187 | * **NOTE: This should be defined at the top of the file so validation is done at load time rather than runtime.**
|
188 | *
|
189 | * ```typescript
|
190 | * Messages.importMessagesDirectory(__dirname);
|
191 | * const messages = Messages.load('packageName', 'bundleName', [
|
192 | * 'messageKey1',
|
193 | * 'messageKey2',
|
194 | * ]);
|
195 | * ```
|
196 | *
|
197 | * @param packageName The name of the npm package.
|
198 | * @param bundleName The name of the bundle to load.
|
199 | * @param keys The message keys that will be used.
|
200 | */
|
201 | static load<T extends string>(packageName: string, bundleName: string, keys: [T, ...T[]]): Messages<T>;
|
202 | /**
|
203 | * Check if a bundle already been loaded.
|
204 | *
|
205 | * @param packageName The npm package name.
|
206 | * @param bundleName The bundle name.
|
207 | */
|
208 | static isCached(packageName: string, bundleName: string): boolean;
|
209 | /**
|
210 | * Get a message using a message key and use the tokens as values for tokenization.
|
211 | *
|
212 | * If the key happens to be an array of messages, it will combine with OS.EOL.
|
213 | *
|
214 | * @param key The key of the message.
|
215 | * @param tokens The values to substitute in the message.
|
216 | *
|
217 | * **See** https://nodejs.org/api/util.html#util_util_format_format_args
|
218 | */
|
219 | getMessage(key: T, tokens?: Tokens): string;
|
220 | /**
|
221 | * Get messages using a message key and use the tokens as values for tokenization.
|
222 | *
|
223 | * This will return all messages if the key is an array in the messages file.
|
224 | *
|
225 | * ```json
|
226 | * {
|
227 | * "myKey": [ "message1", "message2" ]
|
228 | * }
|
229 | * ```
|
230 | *
|
231 | * ```markdown
|
232 | * # myKey
|
233 | * * message1
|
234 | * * message2
|
235 | * ```
|
236 | *
|
237 | * @param key The key of the messages.
|
238 | * @param tokens The values to substitute in the message.
|
239 | *
|
240 | * **See** https://nodejs.org/api/util.html#util_util_format_format_args
|
241 | */
|
242 | getMessages(key: T, tokens?: Tokens): string[];
|
243 | /**
|
244 | * Convenience method to create errors using message labels.
|
245 | *
|
246 | * `error.name` will be the upper-cased key, remove prefixed `error.` and will always end in Error.
|
247 | * `error.actions` will be loaded using `${key}.actions` if available.
|
248 | *
|
249 | * @param key The key of the error message.
|
250 | * @param tokens The error message tokens.
|
251 | * @param actionTokens The action messages tokens.
|
252 | * @param exitCodeOrCause The exit code which will be used by SfdxCommand or the underlying error that caused this error to be raised.
|
253 | * @param cause The underlying error that caused this error to be raised.
|
254 | */
|
255 | createError(key: T, tokens?: Tokens, actionTokens?: Tokens, exitCodeOrCause?: number | Error, cause?: Error): SfError;
|
256 | /**
|
257 | * SfError wants error names to end with the suffix Error. Use this to create errors while preserving their existing name (for compatibility reasons).
|
258 | *
|
259 | * @deprecated Use `createError` instead unless you need to preserver the error name to avoid breaking changes.
|
260 | * `error.name` will be the upper-cased key, remove prefixed `error.`.
|
261 | * `error.actions` will be loaded using `${key}.actions` if available.
|
262 | *
|
263 | * @param key The key of the error message.
|
264 | * @param tokens The error message tokens.
|
265 | * @param actionTokens The action messages tokens.
|
266 | * @param exitCodeOrCause The exit code which will be used by SfdxCommand or the underlying error that caused this error to be raised.
|
267 | * @param cause The underlying error that caused this error to be raised.
|
268 | */
|
269 | createErrorButPreserveName(key: T, tokens?: Tokens, actionTokens?: Tokens, exitCodeOrCause?: number | Error, cause?: Error): SfError;
|
270 | /**
|
271 | * Convenience method to create warning using message labels.
|
272 | *
|
273 | * `warning.name` will be the upper-cased key, remove prefixed `warning.` and will always end in Warning.
|
274 | * `warning.actions` will be loaded using `${key}.actions` if available.
|
275 | *
|
276 | * @param key The key of the warning message.
|
277 | * @param tokens The warning message tokens.
|
278 | * @param actionTokens The action messages tokens.
|
279 | */
|
280 | createWarning(key: T, tokens?: Tokens, actionTokens?: Tokens): StructuredMessage;
|
281 | /**
|
282 | * Convenience method to create info using message labels.
|
283 | *
|
284 | * `info.name` will be the upper-cased key, remove prefixed `info.` and will always end in Info.
|
285 | * `info.actions` will be loaded using `${key}.actions` if available.
|
286 | *
|
287 | * @param key The key of the warning message.
|
288 | * @param tokens The warning message tokens.
|
289 | * @param actionTokens The action messages tokens.
|
290 | */
|
291 | createInfo(key: T, tokens?: Tokens, actionTokens?: Tokens): StructuredMessage;
|
292 | /**
|
293 | * Formats message contents given a message type, key, tokens and actions tokens
|
294 | *
|
295 | * `<type>.name` will be the upper-cased key, remove prefixed `<type>.` and will always end in 'Error | Warning | Info.
|
296 | * `<type>.actions` will be loaded using `${key}.actions` if available.
|
297 | *
|
298 | * @param type The type of the message set must 'error' | 'warning' | 'info'.
|
299 | * @param key The key of the warning message.
|
300 | * @param tokens The warning message tokens.
|
301 | * @param actionTokens The action messages tokens.
|
302 | * @param preserveName Do not require that the name end in the type ('error' | 'warning' | 'info').
|
303 | */
|
304 | private formatMessageContents;
|
305 | private getMessageWithMap;
|
306 | }
|