@nxgt/mail-i18n 0.1.0 → 0.3.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/README.md CHANGED
@@ -51,7 +51,7 @@ Peers:
51
51
  ```
52
52
 
53
53
  The plugin writes one generated file per template and locale under
54
- `.maizzle/i18n/`. They are rewritten on every run, never edited, and never
54
+ `.maizzle/emails/`. They are rewritten on every run, never edited, and never
55
55
  committed.
56
56
 
57
57
  ```css
@@ -88,7 +88,8 @@ file is how the editor learns them. See
88
88
  | `createTranslator(catalogues, getLanguage)` | `t(key, args?, language?)` outside templates, shaped like `@nxgt/i18n`, but it throws on a missing key |
89
89
  | `emailKey(email)` | Where an e-mail's messages live: `auth/reset-password` → `auth.resetPassword` |
90
90
  | `MANIFEST_FILE` | `'mail-manifest.json'`, the manifest's name in the output folder |
91
- | `WRAPPERS_DIR` | `'.maizzle/i18n'`, where the generated files go |
91
+ | `MANIFEST_FORMAT` | `1`, the manifest format this version writes as `formatVersion`: it changes only with the manifest's shape, and `@nxgt/mail`'s renderer reads every format up to its own within 0.x |
92
+ | `WRAPPERS_DIR` | `'.maizzle/emails'`, where the generated files go |
92
93
  | `I18nOptions`, `Layout`, `TemplateSource` | The plugin's options, `'nested' \| 'flat'`, and a package's folder of templates for `templates` |
93
94
  | `Catalogue`, `Catalogues`, `ArgumentKind` | A catalogue as written, catalogues by locale, and `'string' \| 'number' \| 'date'` |
94
95
  | `Translate`, `LanguageProvider`, `MessageArgs` | What `createTranslator` answers and takes |
@@ -260,11 +261,13 @@ catalogues`. See [Catalogues](docs/guide/catalogues.md#the-subject).
260
261
  ### The manifest
261
262
 
262
263
  `dist/mail-manifest.json` is written by `maizzle build`, for the code that
263
- sends. For each e-mail, it records its placeholders, the ones a link or an
264
- image URL starts with, its subject in each locale, and its files:
264
+ sends. It starts with its format; then, for each e-mail, it records its
265
+ placeholders, the ones a link or an image URL starts with, its subject in each
266
+ locale, and its files:
265
267
 
266
268
  ```json
267
269
  {
270
+ "formatVersion": 1,
268
271
  "locales": ["en", "fr"],
269
272
  "fallbackLocale": "en",
270
273
  "emails": {
@@ -286,11 +289,15 @@ image URL starts with, its subject in each locale, and its files:
286
289
 
287
290
  `createMailRenderer` from `@nxgt/mail/renderer` reads it at send time:
288
291
  `createMailRenderer({ dir: 'dist' }).render('verify-email', { name, link })`
289
- answers the subject, HTML and text, every value escaped.
292
+ answers the subject, HTML and text, every value escaped. Within 0.x, a newer
293
+ `@nxgt/mail` reads a build from any earlier `@nxgt/mail-i18n`: see
294
+ [The manifest — `formatVersion`](docs/guide/manifest.md#formatversion).
290
295
 
291
296
  After the manifest, each build writes `generated/mail.ts`, in the project — the manifest's e-mails
292
- and variables as a type, rewritten only when they change. **Commit it**: the
293
- code that sends then type-checks without running a build.
297
+ and variables as a type, rewritten only when they change. **Git-ignore it**
298
+ and build before type-checking — `"typecheck": "maizzle build && tsc
299
+ --noEmit"` — as you do for `dist/`: it is output of the build, like the
300
+ e-mails it describes.
294
301
 
295
302
  ```ts
296
303
  // generated/mail.ts — never edited
@@ -378,7 +385,7 @@ not affected. See [Editor and type checking](docs/guide/editor.md).
378
385
  `content` in your config replaces that, and each template then fails with
379
386
  `… is not built through the i18n plugin`.
380
387
 
381
- **Run `maizzle` from the project root.** `dir`, `emails` and `.maizzle/i18n`
388
+ **Run `maizzle` from the project root.** `dir`, `emails` and `.maizzle/emails`
382
389
  are resolved against the directory `maizzle` runs in.
383
390
 
384
391
  **Nest keys; never dot them.** `{ "verifyEmail": { "title": "…" } }`, not
package/dist/index.d.ts CHANGED
@@ -17,7 +17,7 @@
17
17
  */
18
18
  import './vue';
19
19
  export type { ArgumentKind, Catalogue, Catalogues, } from './catalogues';
20
- export { emailKey, type Manifest, type ManifestEmail, } from './manifest';
20
+ export { emailKey, MANIFEST_FORMAT, type Manifest, type ManifestEmail, } from './manifest';
21
21
  export { type I18nOptions, i18n, MANIFEST_FILE, WRAPPERS_DIR, } from './plugin';
22
22
  export type { TemplateSource } from './sources';
23
23
  export { createTranslator, type LanguageProvider, type MessageArgs, type Translate, } from './translator';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,OAAO,CAAC;AAEf,YAAY,EACX,YAAY,EACZ,SAAS,EACT,UAAU,GACV,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,QAAQ,EACR,KAAK,QAAQ,EACb,KAAK,aAAa,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,KAAK,WAAW,EAChB,IAAI,EACJ,aAAa,EACb,YAAY,GACZ,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EACN,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,SAAS,GACd,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AACzE,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,OAAO,CAAC;AAEf,YAAY,EACX,YAAY,EACZ,SAAS,EACT,UAAU,GACV,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,QAAQ,EACR,eAAe,EACf,KAAK,QAAQ,EACb,KAAK,aAAa,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,KAAK,WAAW,EAChB,IAAI,EACJ,aAAa,EACb,YAAY,GACZ,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EACN,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,SAAS,GACd,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AACzE,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -186,6 +186,7 @@ function watchTemplates(emailsDir, regenerate) {
186
186
  }
187
187
 
188
188
  // src/manifest.ts
189
+ var MANIFEST_FORMAT = 1;
189
190
  var PLACEHOLDER = /\{\{\s*([a-z][a-zA-Z0-9]*)\s*\}\}/g;
190
191
  var URL_ATTRIBUTE = /\s(?:href|src|background|poster|action)\s*=\s*(?:"\s*(\{\{[^"]*)"|'\s*(\{\{[^']*)')/gi;
191
192
  var placeholderMark = (name) => `{{ ${name} }}`;
@@ -267,6 +268,7 @@ function buildManifest(options) {
267
268
  };
268
269
  }
269
270
  return {
271
+ formatVersion: MANIFEST_FORMAT,
270
272
  locales: [...locales],
271
273
  fallbackLocale: options.fallbackLocale,
272
274
  emails
@@ -516,7 +518,7 @@ function rendererTypes(manifest) {
516
518
  });
517
519
  return [
518
520
  `${RENDERER_TYPES_HEADER}, after each maizzle build.`,
519
- "// Never edited; committed, so the code that sends type-checks without a build.",
521
+ "// Never edited, never committed: git-ignore it, and build before type-checking.",
520
522
  "",
521
523
  "/** The e-mails of the build, each with the variables it takes when it is sent. */",
522
524
  "export interface MailEmails {",
@@ -540,7 +542,7 @@ function writeIfChanged(file, source) {
540
542
  }
541
543
 
542
544
  // src/plugin.ts
543
- var WRAPPERS_DIR = ".maizzle/i18n";
545
+ var WRAPPERS_DIR = ".maizzle/emails";
544
546
  var MANIFEST_FILE = "mail-manifest.json";
545
547
  var LOCALE = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;
546
548
  var isObject3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -665,11 +667,12 @@ function i18n(options) {
665
667
  }
666
668
  export {
667
669
  MANIFEST_FILE,
670
+ MANIFEST_FORMAT,
668
671
  WRAPPERS_DIR,
669
672
  createTranslator,
670
673
  emailKey,
671
674
  i18n
672
675
  };
673
676
 
674
- //# debugId=874EDA850D792EF364756E2164756E21
677
+ //# debugId=3C814EA0EFDDBF5664756E2164756E21
675
678
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -2,16 +2,16 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/manifest.ts", "../src/translator.ts", "../src/wrappers.ts", "../src/plugin.ts", "../src/catalogues.ts", "../src/sources.ts", "../src/template.ts", "../src/types.ts"],
4
4
  "sourcesContent": [
5
- "import { readFileSync } from 'node:fs';\nimport { isAbsolute, join, relative, sep } from 'node:path';\nimport type { Messages } from './catalogues';\nimport { createFormatter } from './translator';\nimport { type Entry, entryPath, type Layout, parseEntry } from './wrappers';\n\n/** One e-mail, as the renderer reads it. */\nexport interface ManifestEmail {\n\t/** Every placeholder of the e-mail, in any locale, sorted. */\n\treadonly variables: readonly string[];\n\t/**\n\t * The placeholders a URL attribute starts with — `href`, `src`,\n\t * `background`, `poster`, `action`: they decide the scheme, so a URL fills\n\t * them. One later in the value, as `?token={{ token }}`, is not one.\n\t */\n\treadonly urlVariables: readonly string[];\n\t/** The subject per locale, its placeholders kept as `{{ name }}`. */\n\treadonly subject: Readonly<Record<string, string>>;\n\t/** The built files per locale, relative to the output folder. */\n\treadonly files: Readonly<\n\t\tRecord<string, { readonly html: string; readonly text: string | null }>\n\t>;\n}\n\n/** `dist/mail-manifest.json`: what the build wrote, for the renderer. */\nexport interface Manifest {\n\treadonly locales: readonly string[];\n\treadonly fallbackLocale: string;\n\treadonly emails: Readonly<Record<string, ManifestEmail>>;\n}\n\n// Copied in packages/mail/src/renderer.ts, which reads this manifest: change both.\nconst PLACEHOLDER = /\\{\\{\\s*([a-z][a-zA-Z0-9]*)\\s*\\}\\}/g;\n/** An attribute that holds a URL, its value starting with a placeholder: that placeholder is the whole scheme. */\nconst URL_ATTRIBUTE =\n\t/\\s(?:href|src|background|poster|action)\\s*=\\s*(?:\"\\s*(\\{\\{[^\"]*)\"|'\\s*(\\{\\{[^']*)')/gi;\n\n/** `{{ name }}` — what `placeholder('name')` writes. */\nexport const placeholderMark = (name: string) => `{{ ${name} }}`;\n\nconst placeholdersIn = (text: string) =>\n\t[...text.matchAll(PLACEHOLDER)].map((match) => match[1] as string);\n\n/** `auth/reset-password` → `auth.resetPassword`: where its messages live. */\nexport const emailKey = (email: string) =>\n\temail\n\t\t.split('/')\n\t\t.map((segment) =>\n\t\t\tsegment.replace(/-([a-z0-9])/g, (_, char: string) => char.toUpperCase()),\n\t\t)\n\t\t.join('.');\n\n/**\n * The subject of `email` in `locale`: the message `<emailKey>.subject`, each\n * argument a placeholder. A missing subject, or one with an argument that is\n * not a string, **throws**.\n */\nfunction subjectOf(\n\temail: string,\n\tlocale: string,\n\tmessages: Messages,\n\tformat: ReturnType<typeof createFormatter>,\n): string {\n\tconst key = `${emailKey(email)}.subject`;\n\tconst message = messages.get(key);\n\tif (message === undefined) {\n\t\tthrow new Error(\n\t\t\t`i18n: ${email} has no subject — add ${key} to the catalogues`,\n\t\t);\n\t}\n\tconst args: Record<string, string> = {};\n\tfor (const [name, kind] of message.args) {\n\t\tif (message.selects.has(name)) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${locale}: ${key} chooses on {${name}} with a select — a subject's arguments are placeholders, which always choose other`,\n\t\t\t);\n\t\t}\n\t\tif (kind !== 'string') {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${locale}: ${key} uses {${name}} as a ${kind} — a subject's arguments are placeholders, filled at send time as strings`,\n\t\t\t);\n\t\t}\n\t\targs[name] = placeholderMark(name);\n\t}\n\treturn format(locale, key, message.text, args);\n}\n\n/** One e-mail in one locale, as found in the build's files. */\ninterface Built {\n\treadonly entry: Entry;\n\thtml: string | null;\n\ttext: string | null;\n}\n\nconst sorted = (values: Iterable<string>) => [...new Set(values)].sort();\n\n/**\n * Reads what the build wrote — `files`, absolute, under `outputDir` — and\n * answers the manifest: for each e-mail its placeholders, those in a URL, its\n * subject per locale and its files.\n */\nexport function buildManifest(options: {\n\treadonly files: readonly string[];\n\treadonly outputDir: string;\n\treadonly htmlExtension: string;\n\treadonly layout: Layout;\n\treadonly locales: readonly string[];\n\treadonly fallbackLocale: string;\n\treadonly messages: ReadonlyMap<string, Messages>;\n}): Manifest {\n\tconst { layout, locales } = options;\n\tconst format = createFormatter('i18n');\n\tconst found = new Map<string, Built>();\n\tfor (const file of options.files) {\n\t\tconst path = relative(options.outputDir, file).split(sep).join('/');\n\t\tif (path.startsWith('../') || isAbsolute(path)) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${path} was written outside the output folder — the i18n plugin lays out every e-mail; set no plaintext.destination and no output path in a template`,\n\t\t\t);\n\t\t}\n\t\tconst dot = path.lastIndexOf('.');\n\t\tconst base = path.slice(0, Math.max(dot, 0));\n\t\tconst entry = dot > 0 ? parseEntry(base, layout, locales) : null;\n\t\tif (entry === null) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${path} is not where the i18n plugin puts an e-mail — set no output path in a template`,\n\t\t\t);\n\t\t}\n\t\tconst seen = found.get(base) ?? { entry, html: null, text: null };\n\t\tif (path.slice(dot + 1) === options.htmlExtension) seen.html = path;\n\t\telse seen.text = path;\n\t\tfound.set(base, seen);\n\t}\n\n\tconst emails: Record<string, ManifestEmail> = {};\n\tfor (const email of sorted(\n\t\t[...found.values()].map((seen) => seen.entry.email),\n\t)) {\n\t\tconst variables: string[] = [];\n\t\tconst urlVariables: string[] = [];\n\t\tconst subject: Record<string, string> = {};\n\t\tconst files: Record<string, { html: string; text: string | null }> = {};\n\t\tfor (const locale of locales) {\n\t\t\tconst seen = found.get(entryPath({ email, locale }, layout));\n\t\t\tif (seen?.html == null) {\n\t\t\t\tthrow new Error(`i18n: ${email} was not built in ${locale}`);\n\t\t\t}\n\t\t\tconst html = readFileSync(join(options.outputDir, seen.html), 'utf8');\n\t\t\t// Vue renders an unresolved component as nothing, and Maizzle still\n\t\t\t// writes the doctype: the build would pass with an empty e-mail.\n\t\t\tif (html.replace(/<!doctype[^>]*>/i, '').trim() === '') {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`i18n: ${seen.html} is empty — a tag of its template resolved to no component; list the plugin that brings it, as ui()`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tvariables.push(...placeholdersIn(html));\n\t\t\tfor (const match of html.matchAll(URL_ATTRIBUTE)) {\n\t\t\t\turlVariables.push(\n\t\t\t\t\t...placeholdersIn(match[1] ?? match[2] ?? '').slice(0, 1),\n\t\t\t\t);\n\t\t\t}\n\t\t\t// A <Plaintext> block is in the text part only.\n\t\t\tif (seen.text !== null) {\n\t\t\t\tconst text = readFileSync(join(options.outputDir, seen.text), 'utf8');\n\t\t\t\tvariables.push(...placeholdersIn(text));\n\t\t\t}\n\t\t\tsubject[locale] = subjectOf(\n\t\t\t\temail,\n\t\t\t\tlocale,\n\t\t\t\toptions.messages.get(locale) as Messages,\n\t\t\t\tformat,\n\t\t\t);\n\t\t\tvariables.push(...placeholdersIn(subject[locale]));\n\t\t\tfiles[locale] = { html: seen.html, text: seen.text };\n\t\t}\n\t\temails[email] = {\n\t\t\tvariables: sorted(variables),\n\t\t\turlVariables: sorted(urlVariables),\n\t\t\tsubject,\n\t\t\tfiles,\n\t\t};\n\t}\n\treturn {\n\t\tlocales: [...locales],\n\t\tfallbackLocale: options.fallbackLocale,\n\t\temails,\n\t};\n}\n",
5
+ "import { readFileSync } from 'node:fs';\nimport { isAbsolute, join, relative, sep } from 'node:path';\nimport type { Messages } from './catalogues';\nimport { createFormatter } from './translator';\nimport { type Entry, entryPath, type Layout, parseEntry } from './wrappers';\n\n/** One e-mail, as the renderer reads it. */\nexport interface ManifestEmail {\n\t/** Every placeholder of the e-mail, in any locale, sorted. */\n\treadonly variables: readonly string[];\n\t/**\n\t * The placeholders a URL attribute starts with — `href`, `src`,\n\t * `background`, `poster`, `action`: they decide the scheme, so a URL fills\n\t * them. One later in the value, as `?token={{ token }}`, is not one.\n\t */\n\treadonly urlVariables: readonly string[];\n\t/** The subject per locale, its placeholders kept as `{{ name }}`. */\n\treadonly subject: Readonly<Record<string, string>>;\n\t/** The built files per locale, relative to the output folder. */\n\treadonly files: Readonly<\n\t\tRecord<string, { readonly html: string; readonly text: string | null }>\n\t>;\n}\n\n/**\n * The manifest's format. It changes only with the manifest's shape, and\n * `@nxgt/mail`'s renderer reads every format up to its own within 0.x: a\n * build from an older `@nxgt/mail-i18n` keeps working with a newer renderer.\n * Copied in packages/mail/src/renderer.ts: change both.\n */\nexport const MANIFEST_FORMAT = 1;\n\n/** `dist/mail-manifest.json`: what the build wrote, for the renderer. */\nexport interface Manifest {\n\t/**\n\t * {@link MANIFEST_FORMAT} when built, and the first key written. This type\n\t * is what this version writes: a manifest from `@nxgt/mail-i18n` 0.1 or\n\t * 0.2 has no such field, and the renderer reads it as format 1.\n\t */\n\treadonly formatVersion: number;\n\treadonly locales: readonly string[];\n\treadonly fallbackLocale: string;\n\treadonly emails: Readonly<Record<string, ManifestEmail>>;\n}\n\n// Copied in packages/mail/src/renderer.ts, which reads this manifest: change both.\nconst PLACEHOLDER = /\\{\\{\\s*([a-z][a-zA-Z0-9]*)\\s*\\}\\}/g;\n/** An attribute that holds a URL, its value starting with a placeholder: that placeholder is the whole scheme. */\nconst URL_ATTRIBUTE =\n\t/\\s(?:href|src|background|poster|action)\\s*=\\s*(?:\"\\s*(\\{\\{[^\"]*)\"|'\\s*(\\{\\{[^']*)')/gi;\n\n/** `{{ name }}` — what `placeholder('name')` writes. */\nexport const placeholderMark = (name: string) => `{{ ${name} }}`;\n\nconst placeholdersIn = (text: string) =>\n\t[...text.matchAll(PLACEHOLDER)].map((match) => match[1] as string);\n\n/** `auth/reset-password` → `auth.resetPassword`: where its messages live. */\nexport const emailKey = (email: string) =>\n\temail\n\t\t.split('/')\n\t\t.map((segment) =>\n\t\t\tsegment.replace(/-([a-z0-9])/g, (_, char: string) => char.toUpperCase()),\n\t\t)\n\t\t.join('.');\n\n/**\n * The subject of `email` in `locale`: the message `<emailKey>.subject`, each\n * argument a placeholder. A missing subject, or one with an argument that is\n * not a string, **throws**.\n */\nfunction subjectOf(\n\temail: string,\n\tlocale: string,\n\tmessages: Messages,\n\tformat: ReturnType<typeof createFormatter>,\n): string {\n\tconst key = `${emailKey(email)}.subject`;\n\tconst message = messages.get(key);\n\tif (message === undefined) {\n\t\tthrow new Error(\n\t\t\t`i18n: ${email} has no subject — add ${key} to the catalogues`,\n\t\t);\n\t}\n\tconst args: Record<string, string> = {};\n\tfor (const [name, kind] of message.args) {\n\t\tif (message.selects.has(name)) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${locale}: ${key} chooses on {${name}} with a select — a subject's arguments are placeholders, which always choose other`,\n\t\t\t);\n\t\t}\n\t\tif (kind !== 'string') {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${locale}: ${key} uses {${name}} as a ${kind} — a subject's arguments are placeholders, filled at send time as strings`,\n\t\t\t);\n\t\t}\n\t\targs[name] = placeholderMark(name);\n\t}\n\treturn format(locale, key, message.text, args);\n}\n\n/** One e-mail in one locale, as found in the build's files. */\ninterface Built {\n\treadonly entry: Entry;\n\thtml: string | null;\n\ttext: string | null;\n}\n\nconst sorted = (values: Iterable<string>) => [...new Set(values)].sort();\n\n/**\n * Reads what the build wrote — `files`, absolute, under `outputDir` — and\n * answers the manifest: for each e-mail its placeholders, those in a URL, its\n * subject per locale and its files.\n */\nexport function buildManifest(options: {\n\treadonly files: readonly string[];\n\treadonly outputDir: string;\n\treadonly htmlExtension: string;\n\treadonly layout: Layout;\n\treadonly locales: readonly string[];\n\treadonly fallbackLocale: string;\n\treadonly messages: ReadonlyMap<string, Messages>;\n}): Manifest {\n\tconst { layout, locales } = options;\n\tconst format = createFormatter('i18n');\n\tconst found = new Map<string, Built>();\n\tfor (const file of options.files) {\n\t\tconst path = relative(options.outputDir, file).split(sep).join('/');\n\t\tif (path.startsWith('../') || isAbsolute(path)) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${path} was written outside the output folder — the i18n plugin lays out every e-mail; set no plaintext.destination and no output path in a template`,\n\t\t\t);\n\t\t}\n\t\tconst dot = path.lastIndexOf('.');\n\t\tconst base = path.slice(0, Math.max(dot, 0));\n\t\tconst entry = dot > 0 ? parseEntry(base, layout, locales) : null;\n\t\tif (entry === null) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${path} is not where the i18n plugin puts an e-mail — set no output path in a template`,\n\t\t\t);\n\t\t}\n\t\tconst seen = found.get(base) ?? { entry, html: null, text: null };\n\t\tif (path.slice(dot + 1) === options.htmlExtension) seen.html = path;\n\t\telse seen.text = path;\n\t\tfound.set(base, seen);\n\t}\n\n\tconst emails: Record<string, ManifestEmail> = {};\n\tfor (const email of sorted(\n\t\t[...found.values()].map((seen) => seen.entry.email),\n\t)) {\n\t\tconst variables: string[] = [];\n\t\tconst urlVariables: string[] = [];\n\t\tconst subject: Record<string, string> = {};\n\t\tconst files: Record<string, { html: string; text: string | null }> = {};\n\t\tfor (const locale of locales) {\n\t\t\tconst seen = found.get(entryPath({ email, locale }, layout));\n\t\t\tif (seen?.html == null) {\n\t\t\t\tthrow new Error(`i18n: ${email} was not built in ${locale}`);\n\t\t\t}\n\t\t\tconst html = readFileSync(join(options.outputDir, seen.html), 'utf8');\n\t\t\t// Vue renders an unresolved component as nothing, and Maizzle still\n\t\t\t// writes the doctype: the build would pass with an empty e-mail.\n\t\t\tif (html.replace(/<!doctype[^>]*>/i, '').trim() === '') {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`i18n: ${seen.html} is empty — a tag of its template resolved to no component; list the plugin that brings it, as ui()`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tvariables.push(...placeholdersIn(html));\n\t\t\tfor (const match of html.matchAll(URL_ATTRIBUTE)) {\n\t\t\t\turlVariables.push(\n\t\t\t\t\t...placeholdersIn(match[1] ?? match[2] ?? '').slice(0, 1),\n\t\t\t\t);\n\t\t\t}\n\t\t\t// A <Plaintext> block is in the text part only.\n\t\t\tif (seen.text !== null) {\n\t\t\t\tconst text = readFileSync(join(options.outputDir, seen.text), 'utf8');\n\t\t\t\tvariables.push(...placeholdersIn(text));\n\t\t\t}\n\t\t\tsubject[locale] = subjectOf(\n\t\t\t\temail,\n\t\t\t\tlocale,\n\t\t\t\toptions.messages.get(locale) as Messages,\n\t\t\t\tformat,\n\t\t\t);\n\t\t\tvariables.push(...placeholdersIn(subject[locale]));\n\t\t\tfiles[locale] = { html: seen.html, text: seen.text };\n\t\t}\n\t\temails[email] = {\n\t\t\tvariables: sorted(variables),\n\t\t\turlVariables: sorted(urlVariables),\n\t\t\tsubject,\n\t\t\tfiles,\n\t\t};\n\t}\n\treturn {\n\t\tformatVersion: MANIFEST_FORMAT,\n\t\tlocales: [...locales],\n\t\tfallbackLocale: options.fallbackLocale,\n\t\temails,\n\t};\n}\n",
6
6
  "import { IntlMessageFormat } from 'intl-messageformat';\nimport type { Catalogue, Catalogues } from './catalogues';\n\n/** The values a message's arguments take: `{ name: 'Ada', count: 3 }`. */\nexport type MessageArgs = Readonly<Record<string, string | number | Date>>;\n\n/** A locale, or a function that answers it at each call — as in `@nxgt/i18n`. */\nexport type LanguageProvider = string | (() => string);\n\n/** `t(key, args?, language?)`: the message `key`, formatted in the language. */\nexport type Translate = (\n\tkey: string,\n\targs?: MessageArgs,\n\tlanguage?: LanguageProvider,\n) => string;\n\nfunction lookup(catalogue: Catalogue, key: string): string | null {\n\tlet node: string | Catalogue | undefined = catalogue;\n\tfor (const segment of key.split('.')) {\n\t\tif (typeof node !== 'object' || !Object.hasOwn(node, segment)) return null;\n\t\tnode = node[segment];\n\t}\n\treturn typeof node === 'string' ? node : null;\n}\n\nconst resolveLanguage = (language: LanguageProvider): unknown =>\n\ttypeof language === 'function' ? language() : language;\n\n/**\n * Formats with a cache of compiled messages, one per locale and key. A\n * message that does not format **throws**, the formatter's error as the\n * cause.\n */\nexport function createFormatter(prefix: string) {\n\tconst compiled = new Map<string, IntlMessageFormat>();\n\treturn (locale: string, key: string, text: string, args?: MessageArgs) => {\n\t\tconst id = `${locale}\\u0000${key}`;\n\t\ttry {\n\t\t\tlet format = compiled.get(id);\n\t\t\tif (format === undefined) {\n\t\t\t\tformat = new IntlMessageFormat(text, locale, undefined, {\n\t\t\t\t\tignoreTag: true,\n\t\t\t\t});\n\t\t\t\tcompiled.set(id, format);\n\t\t\t}\n\t\t\treturn String(format.format(args));\n\t\t} catch (cause) {\n\t\t\tthrow new Error(`${prefix}: ${locale}: ${key} could not be formatted`, {\n\t\t\t\tcause,\n\t\t\t});\n\t\t}\n\t};\n}\n\n/**\n * The translator of `@nxgt/i18n`, for mail: `createTranslator(catalogues,\n * getLanguage)` answers `t(key, args?, language?)`.\n *\n * Where `@nxgt/i18n` answers the key, this **throws**: a key the language's\n * catalogue does not have, a language with no catalogue, and a message that\n * does not format. An e-mail is not sent with a key in it.\n *\n * ```ts\n * import en from './locales/en.json';\n * import fr from './locales/fr.json';\n *\n * const t = createTranslator({ en, fr }, () => pickLocale(user.locale, ['en', 'fr'], 'en'));\n * t('verifyEmail.subject');\n * ```\n */\nexport function createTranslator(\n\tcatalogues: Catalogues,\n\tgetLanguage: LanguageProvider,\n): Translate {\n\tif (typeof catalogues !== 'object' || catalogues === null) {\n\t\tthrow new TypeError(\n\t\t\t'createTranslator: catalogues must be an object of catalogues by locale, as { en, fr }',\n\t\t);\n\t}\n\tif (typeof getLanguage !== 'string' && typeof getLanguage !== 'function') {\n\t\tthrow new TypeError(\n\t\t\t'createTranslator: getLanguage must be a locale or a function that answers one',\n\t\t);\n\t}\n\tconst format = createFormatter('t');\n\treturn (key, args, language = getLanguage) => {\n\t\tconst locale = resolveLanguage(language);\n\t\tif (typeof locale !== 'string' || !Object.hasOwn(catalogues, locale)) {\n\t\t\tthrow new Error(\n\t\t\t\t't: the language is not a locale of the catalogues — pick one with pickLocale',\n\t\t\t);\n\t\t}\n\t\tconst text = lookup(catalogues[locale] as Catalogue, key);\n\t\tif (text === null) throw new Error(`t: ${locale}: ${key} is not a key`);\n\t\treturn format(locale, key, text, args);\n\t};\n}\n",
7
7
  "import {\n\texistsSync,\n\tmkdirSync,\n\treaddirSync,\n\treadFileSync,\n\trmSync,\n\twriteFileSync,\n} from 'node:fs';\nimport { dirname, join, relative, sep } from 'node:path';\n\n/**\n * Where each locale's output goes: `nested` writes `en/verify-email.html`,\n * `flat` writes `verify-email.en.html`.\n */\nexport type Layout = 'nested' | 'flat';\n\n/** One e-mail in one locale: `{ email: 'auth/reset-password', locale: 'fr' }`. */\nexport interface Entry {\n\treadonly email: string;\n\treadonly locale: string;\n}\n\nconst NAME = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;\n\nconst posix = (path: string) => path.split(sep).join('/');\n\n/** Every `.vue` file under `dir`, as a slash-separated path without `.vue`. */\nfunction listEmails(dir: string, label: string): string[] {\n\tif (!existsSync(dir)) return [];\n\treturn readdirSync(dir, { recursive: true, encoding: 'utf8' })\n\t\t.filter((file) => file.endsWith('.vue'))\n\t\t.map((file) => {\n\t\t\tconst email = posix(file).slice(0, -'.vue'.length);\n\t\t\tfor (const segment of email.split('/')) {\n\t\t\t\tif (!NAME.test(segment)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`i18n: ${label}/${email}.vue is not a kebab-case name — name a template as verify-email.vue`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn email;\n\t\t})\n\t\t.sort();\n}\n\n/** The path of `entry`'s file under a folder laid out as `layout`, without an extension. */\nexport function entryPath(entry: Entry, layout: Layout): string {\n\treturn layout === 'nested'\n\t\t? `${entry.locale}/${entry.email}`\n\t\t: `${entry.email}.${entry.locale}`;\n}\n\n/**\n * Reads back what {@link entryPath} wrote — `path` relative to its folder,\n * slash-separated, without an extension — or `null` for a path that is not\n * one e-mail in one of `locales`.\n */\nexport function parseEntry(\n\tpath: string,\n\tlayout: Layout,\n\tlocales: readonly string[],\n): Entry | null {\n\tif (layout === 'nested') {\n\t\tconst [locale, ...rest] = path.split('/');\n\t\tif (locale === undefined || rest.length === 0) return null;\n\t\treturn locales.includes(locale) ? { email: rest.join('/'), locale } : null;\n\t}\n\tconst dot = path.lastIndexOf('.');\n\tconst locale = path.slice(dot + 1);\n\treturn dot > 0 && locales.includes(locale)\n\t\t? { email: path.slice(0, dot), locale }\n\t\t: null;\n}\n\nfunction wrapperSource(wrapper: string, template: string): string {\n\tconst from = posix(relative(dirname(wrapper), template));\n\treturn [\n\t\t'<!-- Generated by @nxgt/mail-i18n: one per template and locale. Never edited, never committed. -->',\n\t\t'<script setup>',\n\t\t`import Email from '${from.startsWith('.') ? from : `./${from}`}';`,\n\t\t'</script>',\n\t\t'<template><Email /></template>',\n\t\t'',\n\t].join('\\n');\n}\n\n/** Every file under `dir`, absolute. */\nfunction listFiles(dir: string): string[] {\n\tif (!existsSync(dir)) return [];\n\treturn readdirSync(dir, { recursive: true, encoding: 'utf8' })\n\t\t.map((file) => join(dir, file))\n\t\t.filter((file) => file.endsWith('.vue'));\n}\n\n/**\n * A folder of templates. `label` names it in an error: `emails`, or\n * `templates[0]` for a package's. `only`, when given, keeps those e-mails of\n * the folder and no other. A `packaged` folder — a package's — must hold\n * templates, and shares no name with another package's.\n */\nexport interface TemplateFolder {\n\treadonly dir: string;\n\treadonly label: string;\n\treadonly only?: readonly string[];\n\treadonly packaged?: boolean;\n}\n\n/** The e-mails of `folder`, the ones it keeps, checked. */\nfunction folderEmails({\n\tdir,\n\tlabel,\n\tonly,\n\tpackaged,\n}: TemplateFolder): string[] {\n\tconst emails = listEmails(dir, label);\n\tif (packaged && emails.length === 0) {\n\t\tthrow new Error(\n\t\t\t`i18n: ${label} holds no template — is ${dir} the folder of a package's e-mails?`,\n\t\t);\n\t}\n\tfor (const email of only ?? []) {\n\t\tif (!emails.includes(email)) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${label} has no template ${email}.vue — name one of its e-mails`,\n\t\t\t);\n\t\t}\n\t}\n\treturn [...(only ?? emails)];\n}\n\n/**\n * Each e-mail of `folders` and its file. The project's folder, first, wins\n * over a package's; two packages with the same e-mail **throw**, since\n * neither would be the obvious one.\n */\nfunction collectTemplates(\n\tfolders: readonly TemplateFolder[],\n): Map<string, string> {\n\tconst templates = new Map<string, string>();\n\tconst owners = new Map<string, TemplateFolder>();\n\tfor (const folder of folders) {\n\t\tfor (const email of folderEmails(folder)) {\n\t\t\tconst owner = owners.get(email);\n\t\t\tif (owner === undefined) {\n\t\t\t\towners.set(email, folder);\n\t\t\t\ttemplates.set(email, join(folder.dir, `${email}.vue`));\n\t\t\t} else if (owner.packaged) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`i18n: ${owner.label} and ${folder.label} both have ${email}.vue — keep one with emails: [...], or write the project's own in its folder`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\treturn templates;\n}\n\n/**\n * Writes one wrapper per template of `folders` and locale under\n * `wrappersDir` — the project's folder first, so its template replaces a\n * package's of the same name — each only when its text changed, and removes\n * the wrappers of templates that are gone, so a running dev server sees a\n * change only where there is one. Answers the e-mails, sorted.\n */\nexport function writeWrappers(options: {\n\treadonly folders: readonly TemplateFolder[];\n\treadonly wrappersDir: string;\n\treadonly locales: readonly string[];\n\treadonly layout: Layout;\n}): string[] {\n\tconst { wrappersDir, locales, layout } = options;\n\tconst templates = collectTemplates(options.folders);\n\tconst wanted = new Set<string>();\n\tfor (const [email, template] of templates) {\n\t\tfor (const locale of locales) {\n\t\t\tconst wrapper = join(\n\t\t\t\twrappersDir,\n\t\t\t\t`${entryPath({ email, locale }, layout)}.vue`,\n\t\t\t);\n\t\t\twanted.add(wrapper);\n\t\t\tconst source = wrapperSource(wrapper, template);\n\t\t\tif (existsSync(wrapper) && readFileSync(wrapper, 'utf8') === source) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmkdirSync(dirname(wrapper), { recursive: true });\n\t\t\twriteFileSync(wrapper, source);\n\t\t}\n\t}\n\tfor (const file of listFiles(wrappersDir)) {\n\t\tif (!wanted.has(file)) rmSync(file);\n\t}\n\treturn [...templates.keys()].sort();\n}\n\n/** The part of Vite's dev server the watcher uses. */\ninterface WatchedServer {\n\treadonly watcher: {\n\t\tadd(path: string): void;\n\t\ton(event: 'add' | 'unlink', listener: (file: string) => void): void;\n\t};\n}\n\n/**\n * A Vite plugin for Maizzle's renderer: under `maizzle serve`, a template\n * added to or removed from `emailsDir` gets its wrappers at once, so the\n * preview lists it without a restart. A template the build would refuse is\n * reported, never thrown: an error in a watcher would stop the server.\n */\nexport function watchTemplates(emailsDir: string, regenerate: () => void) {\n\treturn {\n\t\tname: 'nxgt-mail-i18n:wrappers',\n\t\tconfigureServer(server: WatchedServer) {\n\t\t\tserver.watcher.add(emailsDir);\n\t\t\tconst onTemplate = (file: string) => {\n\t\t\t\tif (!file.startsWith(emailsDir + sep) || !file.endsWith('.vue')) return;\n\t\t\t\ttry {\n\t\t\t\t\tregenerate();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error(error instanceof Error ? error.message : error);\n\t\t\t\t}\n\t\t\t};\n\t\t\tserver.watcher.on('add', onTemplate);\n\t\t\tserver.watcher.on('unlink', onTemplate);\n\t\t},\n\t};\n}\n",
8
- "import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join, relative, resolve, sep } from 'node:path';\nimport { isMainThread } from 'node:worker_threads';\nimport { defineMailPlugin, type MailPlugin } from '@nxgt/mail-config';\nimport {\n\ttype Catalogue,\n\ttype Catalogues,\n\tcheckCatalogues,\n\tlayerCatalogues,\n\ttype Messages,\n} from './catalogues';\nimport { buildManifest } from './manifest';\nimport {\n\tcheckTemplates,\n\ttype TemplateSource,\n\ttemplateFolders,\n} from './sources';\nimport { templateProperties } from './template';\nimport { createFormatter } from './translator';\nimport {\n\tRENDERER_TYPES_FILE,\n\trendererTypes,\n\tTYPES_FILE,\n\ttemplateTypes,\n\twriteIfChanged,\n\twriteRendererTypes,\n} from './types';\nimport {\n\ttype Layout,\n\tparseEntry,\n\twatchTemplates,\n\twriteWrappers,\n} from './wrappers';\n\nexport interface I18nOptions {\n\t/** Every locale the project writes, as BCP 47 tags: `['en', 'fr']`. */\n\treadonly locales: readonly string[];\n\t/** The reference every other locale is checked against. Default the first locale. */\n\treadonly fallbackLocale?: string;\n\t/** The folder of `<locale>.json` catalogues. Default `locales`. */\n\treadonly dir?: string;\n\t/** The folder of templates. Default `emails`. */\n\treadonly emails?: string;\n\t/** `nested` writes `dist/en/verify-email.html`; `flat` writes `dist/verify-email.en.html`. Default `nested`. */\n\treadonly layout?: Layout;\n\t/**\n\t * Catalogues under the project's own, as a package ships them —\n\t * `[uiCatalogues]` from `@nxgt/mail-ui`. Each is merged key by key under\n\t * the next, and the project's `<locale>.json` over all of them.\n\t */\n\treadonly catalogues?: readonly Catalogues[];\n\t/**\n\t * Folders of templates under the project's own, as a package ships them —\n\t * `presets().templates` from `@nxgt/mail-presets`. A template in the\n\t * project's `emails/` replaces a package's of the same name.\n\t */\n\treadonly templates?: readonly TemplateSource[];\n\t/**\n\t * The module typing the renderer, written after each build: `MailEmails`,\n\t * for `createMailRenderer<MailEmails>(…)` in the code that sends. A path\n\t * from where `maizzle` runs — outside the project too, as\n\t * `../api/src/generated/mail.ts` — or `false` to write none. Default\n\t * `generated/mail.ts`.\n\t */\n\treadonly rendererTypes?: string | false;\n}\n\n/** Where the wrappers go, under the project. */\nexport const WRAPPERS_DIR = '.maizzle/i18n';\n\n/** The manifest's name, in the output folder. */\nexport const MANIFEST_FILE = 'mail-manifest.json';\n\nconst LOCALE = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value);\n\nfunction checkOptions(options: I18nOptions): void {\n\tif (typeof options !== 'object' || options === null) {\n\t\tthrow new TypeError(\n\t\t\t\"i18n: options must be an object, as { locales: ['en', 'fr'] }\",\n\t\t);\n\t}\n\tconst { locales } = options;\n\tif (!Array.isArray(locales) || locales.length === 0) {\n\t\tthrow new TypeError(\n\t\t\t\"i18n: locales must hold at least one locale, as ['en', 'fr']\",\n\t\t);\n\t}\n\tfor (const locale of locales) {\n\t\tif (typeof locale !== 'string' || !LOCALE.test(locale)) {\n\t\t\tthrow new TypeError(\n\t\t\t\t'i18n: locales holds something that is not a locale — write each as a BCP 47 tag, as en or pt-BR',\n\t\t\t);\n\t\t}\n\t}\n\tif (new Set(locales).size !== locales.length) {\n\t\tthrow new TypeError('i18n: locales holds the same locale twice');\n\t}\n\tif (\n\t\toptions.fallbackLocale !== undefined &&\n\t\t!locales.includes(options.fallbackLocale)\n\t) {\n\t\tthrow new TypeError('i18n: fallbackLocale must be one of locales');\n\t}\n\tfor (const key of ['dir', 'emails'] as const) {\n\t\tconst value = options[key];\n\t\tif (value !== undefined && (typeof value !== 'string' || value === '')) {\n\t\t\tthrow new TypeError(`i18n: ${key} must be a folder of the project`);\n\t\t}\n\t}\n\tif (\n\t\toptions.layout !== undefined &&\n\t\toptions.layout !== 'nested' &&\n\t\toptions.layout !== 'flat'\n\t) {\n\t\tthrow new TypeError(\"i18n: layout must be 'nested' or 'flat'\");\n\t}\n\tconst { catalogues } = options;\n\tif (\n\t\tcatalogues !== undefined &&\n\t\t(!Array.isArray(catalogues) ||\n\t\t\t!catalogues.every(\n\t\t\t\t(source) => isObject(source) && Object.values(source).every(isObject),\n\t\t\t))\n\t) {\n\t\tthrow new TypeError(\n\t\t\t'i18n: catalogues must be a list of catalogues by locale, as [{ en: {...}, fr: {...} }]',\n\t\t);\n\t}\n\tconst typesPath = options.rendererTypes;\n\tif (\n\t\ttypesPath !== undefined &&\n\t\ttypesPath !== false &&\n\t\t(typeof typesPath !== 'string' || !typesPath.endsWith('.ts'))\n\t) {\n\t\tthrow new TypeError(\n\t\t\t'i18n: rendererTypes must be the path of a .ts file, as generated/mail.ts, or false',\n\t\t);\n\t}\n\tcheckTemplates(options.templates);\n}\n\n/** Reads `<dir>/<locale>.json` for each locale. A missing or broken file **throws**. */\nfunction readCatalogues(\n\tdir: string,\n\tdirName: string,\n\tlocales: readonly string[],\n): Record<string, Catalogue> {\n\tconst out: Record<string, Catalogue> = {};\n\tfor (const locale of locales) {\n\t\tconst file = join(dir, `${locale}.json`);\n\t\tconst name = `${dirName}/${locale}.json`;\n\t\tif (!existsSync(file)) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${name} is missing — every locale has a catalogue`,\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\tout[locale] = JSON.parse(readFileSync(file, 'utf8'));\n\t\t} catch {\n\t\t\tthrow new Error(`i18n: ${name} is not valid JSON`);\n\t\t}\n\t}\n\treturn out;\n}\n\n/**\n * The i18n plugin, for `defineMailConfig`:\n *\n * ```ts\n * defineMailConfig({ plugins: [i18n({ locales: ['en', 'fr'] })] });\n * ```\n *\n * It checks `locales/<locale>.json`, writes one wrapper per template and\n * locale under `.maizzle/i18n/` so one build writes every locale, gives each\n * template `t`, `locale` and `placeholder`, and writes\n * `dist/mail-manifest.json`. A catalogue or a template that cannot be right\n * **fails the build**, naming the locale and the key.\n */\nexport function i18n(options: I18nOptions): MailPlugin {\n\tcheckOptions(options);\n\tconst { locales } = options;\n\tconst fallbackLocale = options.fallbackLocale ?? (locales[0] as string);\n\tconst layout = options.layout ?? 'nested';\n\tconst dirName = options.dir ?? 'locales';\n\tconst emailsName = options.emails ?? 'emails';\n\tconst cwd = process.cwd();\n\tconst emailsDir = resolve(cwd, emailsName);\n\tconst wrappersDir = resolve(cwd, WRAPPERS_DIR);\n\n\tconst messages = checkCatalogues(\n\t\tlayerCatalogues(\n\t\t\toptions.catalogues ?? [],\n\t\t\treadCatalogues(resolve(cwd, dirName), dirName, locales),\n\t\t),\n\t\tlocales,\n\t\tfallbackLocale,\n\t);\n\tconst reference = messages.get(fallbackLocale) as Messages;\n\tconst format = createFormatter('i18n');\n\tconst regenerate = () =>\n\t\twriteWrappers({\n\t\t\tfolders: templateFolders(\n\t\t\t\t{ dir: emailsDir, name: emailsName },\n\t\t\t\toptions.templates ?? [],\n\t\t\t),\n\t\t\twrappersDir,\n\t\t\tlocales,\n\t\t\tlayout,\n\t\t});\n\t// A parallel build loads the config again in each worker: only the main\n\t// thread writes, so two workers never write the same file.\n\tif (isMainThread) {\n\t\tregenerate();\n\t\twriteIfChanged(\n\t\t\tresolve(cwd, TYPES_FILE),\n\t\t\ttemplateTypes(reference, fallbackLocale),\n\t\t);\n\t}\n\n\treturn defineMailPlugin({\n\t\tname: 'i18n',\n\t\tcontent: [`${wrappersDir}/**/*.vue`],\n\t\t// `maizzle serve` watches locales/ already; another folder is added.\n\t\t...(dirName === 'locales' ? {} : { server: { watch: [`${dirName}/**`] } }),\n\t\tvite: { plugins: [watchTemplates(emailsDir, regenerate)] },\n\t\tbeforeRender({ config, template }) {\n\t\t\tconst path = relative(\n\t\t\t\twrappersDir,\n\t\t\t\tjoin(template.path.dir, template.path.name),\n\t\t\t)\n\t\t\t\t.split(sep)\n\t\t\t\t.join('/');\n\t\t\tconst entry = parseEntry(path, layout, locales);\n\t\t\tif (entry === null) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`i18n: ${relative(cwd, join(template.path.dir, template.path.base))} is not built through the i18n plugin — leave content to it, and put templates in ${emailsName}/`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconfig.vue ??= {};\n\t\t\tconfig.vue.globalProperties = {\n\t\t\t\t...config.vue.globalProperties,\n\t\t\t\t...templateProperties({\n\t\t\t\t\t...entry,\n\t\t\t\t\tmessages: messages.get(entry.locale) as Messages,\n\t\t\t\t\treference,\n\t\t\t\t\tformat,\n\t\t\t\t}),\n\t\t\t};\n\t\t},\n\t\tafterBuild({ files, config }) {\n\t\t\tconst outputDir = resolve(cwd, config.output?.path ?? 'dist');\n\t\t\tconst manifest = buildManifest({\n\t\t\t\tfiles,\n\t\t\t\toutputDir,\n\t\t\t\thtmlExtension: config.output?.extension ?? 'html',\n\t\t\t\tlayout,\n\t\t\t\tlocales,\n\t\t\t\tfallbackLocale,\n\t\t\t\tmessages,\n\t\t\t});\n\t\t\twriteFileSync(\n\t\t\t\tjoin(outputDir, MANIFEST_FILE),\n\t\t\t\t`${JSON.stringify(manifest, null, '\\t')}\\n`,\n\t\t\t);\n\t\t\tconst typesFile = options.rendererTypes ?? RENDERER_TYPES_FILE;\n\t\t\tif (typesFile !== false) {\n\t\t\t\twriteRendererTypes(\n\t\t\t\t\tresolve(cwd, typesFile),\n\t\t\t\t\ttypesFile,\n\t\t\t\t\trendererTypes(manifest),\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t});\n}\n",
8
+ "import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join, relative, resolve, sep } from 'node:path';\nimport { isMainThread } from 'node:worker_threads';\nimport { defineMailPlugin, type MailPlugin } from '@nxgt/mail-config';\nimport {\n\ttype Catalogue,\n\ttype Catalogues,\n\tcheckCatalogues,\n\tlayerCatalogues,\n\ttype Messages,\n} from './catalogues';\nimport { buildManifest } from './manifest';\nimport {\n\tcheckTemplates,\n\ttype TemplateSource,\n\ttemplateFolders,\n} from './sources';\nimport { templateProperties } from './template';\nimport { createFormatter } from './translator';\nimport {\n\tRENDERER_TYPES_FILE,\n\trendererTypes,\n\tTYPES_FILE,\n\ttemplateTypes,\n\twriteIfChanged,\n\twriteRendererTypes,\n} from './types';\nimport {\n\ttype Layout,\n\tparseEntry,\n\twatchTemplates,\n\twriteWrappers,\n} from './wrappers';\n\nexport interface I18nOptions {\n\t/** Every locale the project writes, as BCP 47 tags: `['en', 'fr']`. */\n\treadonly locales: readonly string[];\n\t/** The reference every other locale is checked against. Default the first locale. */\n\treadonly fallbackLocale?: string;\n\t/** The folder of `<locale>.json` catalogues. Default `locales`. */\n\treadonly dir?: string;\n\t/** The folder of templates. Default `emails`. */\n\treadonly emails?: string;\n\t/** `nested` writes `dist/en/verify-email.html`; `flat` writes `dist/verify-email.en.html`. Default `nested`. */\n\treadonly layout?: Layout;\n\t/**\n\t * Catalogues under the project's own, as a package ships them —\n\t * `[uiCatalogues]` from `@nxgt/mail-ui`. Each is merged key by key under\n\t * the next, and the project's `<locale>.json` over all of them.\n\t */\n\treadonly catalogues?: readonly Catalogues[];\n\t/**\n\t * Folders of templates under the project's own, as a package ships them —\n\t * `presets().templates` from `@nxgt/mail-presets`. A template in the\n\t * project's `emails/` replaces a package's of the same name.\n\t */\n\treadonly templates?: readonly TemplateSource[];\n\t/**\n\t * The module typing the renderer, written after each build: `MailEmails`,\n\t * for `createMailRenderer<MailEmails>(…)` in the code that sends. A path\n\t * from where `maizzle` runs — outside the project too, as\n\t * `../api/src/generated/mail.ts` — or `false` to write none. Default\n\t * `generated/mail.ts`.\n\t */\n\treadonly rendererTypes?: string | false;\n}\n\n/** Where the wrappers go, under the project. */\nexport const WRAPPERS_DIR = '.maizzle/emails';\n\n/** The manifest's name, in the output folder. */\nexport const MANIFEST_FILE = 'mail-manifest.json';\n\nconst LOCALE = /^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value);\n\nfunction checkOptions(options: I18nOptions): void {\n\tif (typeof options !== 'object' || options === null) {\n\t\tthrow new TypeError(\n\t\t\t\"i18n: options must be an object, as { locales: ['en', 'fr'] }\",\n\t\t);\n\t}\n\tconst { locales } = options;\n\tif (!Array.isArray(locales) || locales.length === 0) {\n\t\tthrow new TypeError(\n\t\t\t\"i18n: locales must hold at least one locale, as ['en', 'fr']\",\n\t\t);\n\t}\n\tfor (const locale of locales) {\n\t\tif (typeof locale !== 'string' || !LOCALE.test(locale)) {\n\t\t\tthrow new TypeError(\n\t\t\t\t'i18n: locales holds something that is not a locale — write each as a BCP 47 tag, as en or pt-BR',\n\t\t\t);\n\t\t}\n\t}\n\tif (new Set(locales).size !== locales.length) {\n\t\tthrow new TypeError('i18n: locales holds the same locale twice');\n\t}\n\tif (\n\t\toptions.fallbackLocale !== undefined &&\n\t\t!locales.includes(options.fallbackLocale)\n\t) {\n\t\tthrow new TypeError('i18n: fallbackLocale must be one of locales');\n\t}\n\tfor (const key of ['dir', 'emails'] as const) {\n\t\tconst value = options[key];\n\t\tif (value !== undefined && (typeof value !== 'string' || value === '')) {\n\t\t\tthrow new TypeError(`i18n: ${key} must be a folder of the project`);\n\t\t}\n\t}\n\tif (\n\t\toptions.layout !== undefined &&\n\t\toptions.layout !== 'nested' &&\n\t\toptions.layout !== 'flat'\n\t) {\n\t\tthrow new TypeError(\"i18n: layout must be 'nested' or 'flat'\");\n\t}\n\tconst { catalogues } = options;\n\tif (\n\t\tcatalogues !== undefined &&\n\t\t(!Array.isArray(catalogues) ||\n\t\t\t!catalogues.every(\n\t\t\t\t(source) => isObject(source) && Object.values(source).every(isObject),\n\t\t\t))\n\t) {\n\t\tthrow new TypeError(\n\t\t\t'i18n: catalogues must be a list of catalogues by locale, as [{ en: {...}, fr: {...} }]',\n\t\t);\n\t}\n\tconst typesPath = options.rendererTypes;\n\tif (\n\t\ttypesPath !== undefined &&\n\t\ttypesPath !== false &&\n\t\t(typeof typesPath !== 'string' || !typesPath.endsWith('.ts'))\n\t) {\n\t\tthrow new TypeError(\n\t\t\t'i18n: rendererTypes must be the path of a .ts file, as generated/mail.ts, or false',\n\t\t);\n\t}\n\tcheckTemplates(options.templates);\n}\n\n/** Reads `<dir>/<locale>.json` for each locale. A missing or broken file **throws**. */\nfunction readCatalogues(\n\tdir: string,\n\tdirName: string,\n\tlocales: readonly string[],\n): Record<string, Catalogue> {\n\tconst out: Record<string, Catalogue> = {};\n\tfor (const locale of locales) {\n\t\tconst file = join(dir, `${locale}.json`);\n\t\tconst name = `${dirName}/${locale}.json`;\n\t\tif (!existsSync(file)) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${name} is missing — every locale has a catalogue`,\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\tout[locale] = JSON.parse(readFileSync(file, 'utf8'));\n\t\t} catch {\n\t\t\tthrow new Error(`i18n: ${name} is not valid JSON`);\n\t\t}\n\t}\n\treturn out;\n}\n\n/**\n * The i18n plugin, for `defineMailConfig`:\n *\n * ```ts\n * defineMailConfig({ plugins: [i18n({ locales: ['en', 'fr'] })] });\n * ```\n *\n * It checks `locales/<locale>.json`, writes one wrapper per template and\n * locale under `.maizzle/emails/` so one build writes every locale, gives each\n * template `t`, `locale` and `placeholder`, and writes\n * `dist/mail-manifest.json`. A catalogue or a template that cannot be right\n * **fails the build**, naming the locale and the key.\n */\nexport function i18n(options: I18nOptions): MailPlugin {\n\tcheckOptions(options);\n\tconst { locales } = options;\n\tconst fallbackLocale = options.fallbackLocale ?? (locales[0] as string);\n\tconst layout = options.layout ?? 'nested';\n\tconst dirName = options.dir ?? 'locales';\n\tconst emailsName = options.emails ?? 'emails';\n\tconst cwd = process.cwd();\n\tconst emailsDir = resolve(cwd, emailsName);\n\tconst wrappersDir = resolve(cwd, WRAPPERS_DIR);\n\n\tconst messages = checkCatalogues(\n\t\tlayerCatalogues(\n\t\t\toptions.catalogues ?? [],\n\t\t\treadCatalogues(resolve(cwd, dirName), dirName, locales),\n\t\t),\n\t\tlocales,\n\t\tfallbackLocale,\n\t);\n\tconst reference = messages.get(fallbackLocale) as Messages;\n\tconst format = createFormatter('i18n');\n\tconst regenerate = () =>\n\t\twriteWrappers({\n\t\t\tfolders: templateFolders(\n\t\t\t\t{ dir: emailsDir, name: emailsName },\n\t\t\t\toptions.templates ?? [],\n\t\t\t),\n\t\t\twrappersDir,\n\t\t\tlocales,\n\t\t\tlayout,\n\t\t});\n\t// A parallel build loads the config again in each worker: only the main\n\t// thread writes, so two workers never write the same file.\n\tif (isMainThread) {\n\t\tregenerate();\n\t\twriteIfChanged(\n\t\t\tresolve(cwd, TYPES_FILE),\n\t\t\ttemplateTypes(reference, fallbackLocale),\n\t\t);\n\t}\n\n\treturn defineMailPlugin({\n\t\tname: 'i18n',\n\t\tcontent: [`${wrappersDir}/**/*.vue`],\n\t\t// `maizzle serve` watches locales/ already; another folder is added.\n\t\t...(dirName === 'locales' ? {} : { server: { watch: [`${dirName}/**`] } }),\n\t\tvite: { plugins: [watchTemplates(emailsDir, regenerate)] },\n\t\tbeforeRender({ config, template }) {\n\t\t\tconst path = relative(\n\t\t\t\twrappersDir,\n\t\t\t\tjoin(template.path.dir, template.path.name),\n\t\t\t)\n\t\t\t\t.split(sep)\n\t\t\t\t.join('/');\n\t\t\tconst entry = parseEntry(path, layout, locales);\n\t\t\tif (entry === null) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`i18n: ${relative(cwd, join(template.path.dir, template.path.base))} is not built through the i18n plugin — leave content to it, and put templates in ${emailsName}/`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconfig.vue ??= {};\n\t\t\tconfig.vue.globalProperties = {\n\t\t\t\t...config.vue.globalProperties,\n\t\t\t\t...templateProperties({\n\t\t\t\t\t...entry,\n\t\t\t\t\tmessages: messages.get(entry.locale) as Messages,\n\t\t\t\t\treference,\n\t\t\t\t\tformat,\n\t\t\t\t}),\n\t\t\t};\n\t\t},\n\t\tafterBuild({ files, config }) {\n\t\t\tconst outputDir = resolve(cwd, config.output?.path ?? 'dist');\n\t\t\tconst manifest = buildManifest({\n\t\t\t\tfiles,\n\t\t\t\toutputDir,\n\t\t\t\thtmlExtension: config.output?.extension ?? 'html',\n\t\t\t\tlayout,\n\t\t\t\tlocales,\n\t\t\t\tfallbackLocale,\n\t\t\t\tmessages,\n\t\t\t});\n\t\t\twriteFileSync(\n\t\t\t\tjoin(outputDir, MANIFEST_FILE),\n\t\t\t\t`${JSON.stringify(manifest, null, '\\t')}\\n`,\n\t\t\t);\n\t\t\tconst typesFile = options.rendererTypes ?? RENDERER_TYPES_FILE;\n\t\t\tif (typesFile !== false) {\n\t\t\t\twriteRendererTypes(\n\t\t\t\t\tresolve(cwd, typesFile),\n\t\t\t\t\ttypesFile,\n\t\t\t\t\trendererTypes(manifest),\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t});\n}\n",
9
9
  "import {\n\ttype MessageFormatElement,\n\tparse,\n\tTYPE,\n} from '@formatjs/icu-messageformat-parser';\n\n/**\n * A catalogue as written: nested objects whose leaves are ICU messages, the\n * conventions of `@nxgt/i18n`.\n *\n * ```json\n * { \"verifyEmail\": { \"subject\": \"Confirm your e-mail address\" } }\n * ```\n */\nexport interface Catalogue {\n\treadonly [key: string]: string | Catalogue;\n}\n\n/** A catalogue per locale: `{ en: {...}, fr: {...} }`. */\nexport type Catalogues = Readonly<Record<string, Catalogue>>;\n\n/**\n * What an argument is, from the way a message uses it: `{n, number}` and\n * `{n, plural, …}` a number, `{at, date}` a date, anything else a string.\n */\nexport type ArgumentKind = 'string' | 'number' | 'date';\n\n/** One message, checked, with the kind of each argument it uses. */\nexport interface Message {\n\treadonly text: string;\n\treadonly args: ReadonlyMap<string, ArgumentKind>;\n\t/** The arguments a `{x, select, …}` chooses on: a placeholder would always choose `other`. */\n\treadonly selects: ReadonlySet<string>;\n}\n\n/** Every message of one locale, by dotted key: `verifyEmail.subject`. */\nexport type Messages = ReadonlyMap<string, Message>;\n\nconst SEGMENT = /^[a-z][a-zA-Z0-9]*$/;\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value);\n\n/** `over` merged into `under` key by key: an object is merged, anything else replaces. */\nfunction mergeCatalogue(under: Catalogue, over: Catalogue): Catalogue {\n\tconst out: Record<string, string | Catalogue> = { ...under };\n\tfor (const [key, value] of Object.entries(over)) {\n\t\tconst below = Object.hasOwn(out, key) ? out[key] : undefined;\n\t\t// Defined, not assigned: `out.__proto__ = …` would set the prototype and\n\t\t// hide the key from the check that refuses it.\n\t\tObject.defineProperty(out, key, {\n\t\t\tvalue:\n\t\t\t\tisObject(below) && isObject(value)\n\t\t\t\t\t? mergeCatalogue(below, value)\n\t\t\t\t\t: value,\n\t\t\tenumerable: true,\n\t\t\twritable: true,\n\t\t\tconfigurable: true,\n\t\t});\n\t}\n\treturn out;\n}\n\n/**\n * Each of `project`'s locales, with `sources` merged under it in order: a\n * source's locale the project does not have is left out.\n */\nexport function layerCatalogues(\n\tsources: readonly Catalogues[],\n\tproject: Record<string, Catalogue>,\n): Record<string, Catalogue> {\n\tconst out: Record<string, Catalogue> = {};\n\tfor (const [locale, catalogue] of Object.entries(project)) {\n\t\tout[locale] = [...sources.map((source) => source[locale]), catalogue]\n\t\t\t.filter((layer): layer is Catalogue => layer !== undefined)\n\t\t\t.reduce(mergeCatalogue, {});\n\t}\n\treturn out;\n}\n\nfunction flatten(\n\tcatalogue: unknown,\n\tlocale: string,\n\tprefix: string,\n\tinto: Map<string, string>,\n): void {\n\tif (!isObject(catalogue)) {\n\t\tthrow new Error(\n\t\t\t`i18n: ${locale}: ${prefix || 'the catalogue'} must be an object of messages`,\n\t\t);\n\t}\n\tfor (const [segment, value] of Object.entries(catalogue)) {\n\t\tconst key = prefix === '' ? segment : `${prefix}.${segment}`;\n\t\tif (!SEGMENT.test(segment)) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${locale}: ${key} is not camelCase — every segment of a key is camelCase, and nested rather than dotted, as verifyEmail.title`,\n\t\t\t);\n\t\t}\n\t\tif (typeof value === 'string') into.set(key, value);\n\t\telse if (isObject(value)) flatten(value, locale, key, into);\n\t\telse {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${locale}: ${key} must be a message (a string) or an object of messages`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction collect(\n\telements: readonly MessageFormatElement[],\n\tuses: Map<string, Set<ArgumentKind | 'plain' | 'select'>>,\n): void {\n\tconst use = (name: string, kind: ArgumentKind | 'plain' | 'select') =>\n\t\tuses.set(name, (uses.get(name) ?? new Set()).add(kind));\n\tfor (const element of elements) {\n\t\tif (element.type === TYPE.argument) use(element.value, 'plain');\n\t\telse if (element.type === TYPE.number) use(element.value, 'number');\n\t\telse if (element.type === TYPE.date || element.type === TYPE.time) {\n\t\t\tuse(element.value, 'date');\n\t\t} else if (element.type === TYPE.select || element.type === TYPE.plural) {\n\t\t\tuse(element.value, element.type === TYPE.plural ? 'number' : 'select');\n\t\t\tfor (const option of Object.values(element.options)) {\n\t\t\t\tcollect(option.value, uses);\n\t\t\t}\n\t\t} else if (element.type === TYPE.tag) collect(element.children, uses);\n\t}\n}\n\n/**\n * Parses a message and types its arguments. The parser's own error is not\n * kept as the cause: it carries the text of the message, and a build failure\n * names a key, never a text.\n */\nfunction analyse(text: string, locale: string, key: string): Message {\n\tlet ast: MessageFormatElement[];\n\ttry {\n\t\tast = parse(text, { ignoreTag: true, shouldParseSkeletons: true });\n\t} catch (cause) {\n\t\tconst reason = cause instanceof Error ? cause.message : 'refused';\n\t\tthrow new Error(\n\t\t\t`i18n: ${locale}: ${key} is not a valid ICU message (${reason})`,\n\t\t);\n\t}\n\tconst uses = new Map<string, Set<ArgumentKind | 'plain' | 'select'>>();\n\tcollect(ast, uses);\n\tconst args = new Map<string, ArgumentKind>();\n\tconst selects = new Set<string>();\n\tfor (const [name, kinds] of uses) {\n\t\tif (!SEGMENT.test(name)) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${locale}: ${key} uses {${name}}, which is not camelCase — an argument is a camelCase name, as {firstName}`,\n\t\t\t);\n\t\t}\n\t\tif (kinds.has('select')) selects.add(name);\n\t\tconst typed = [\n\t\t\t...new Set(\n\t\t\t\t[...kinds]\n\t\t\t\t\t.filter((kind) => kind !== 'plain')\n\t\t\t\t\t.map((kind) => (kind === 'select' ? 'string' : kind)),\n\t\t\t),\n\t\t];\n\t\tif (typed.length > 1) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${locale}: ${key} uses {${name}} as ${typed.join(' and as ')}`,\n\t\t\t);\n\t\t}\n\t\targs.set(name, (typed[0] as ArgumentKind | undefined) ?? 'string');\n\t}\n\treturn { text, args, selects };\n}\n\n/**\n * Checks `locale` against the fallback locale: the same keys, and no\n * argument the fallback does not declare, or declares as another kind. A\n * translation may leave an argument out.\n */\nfunction compare(\n\tlocale: string,\n\tmessages: Messages,\n\tfallbackLocale: string,\n\treference: Messages,\n): void {\n\tfor (const key of [...reference.keys()].sort()) {\n\t\tif (!messages.has(key)) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${locale}: ${key} is missing — ${fallbackLocale}, the fallback locale, has it`,\n\t\t\t);\n\t\t}\n\t}\n\tfor (const key of [...messages.keys()].sort()) {\n\t\tconst declared = reference.get(key);\n\t\tif (declared === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`i18n: ${locale}: ${key} is not a key of ${fallbackLocale}, the fallback locale`,\n\t\t\t);\n\t\t}\n\t\tfor (const [name, kind] of (messages.get(key) as Message).args) {\n\t\t\tconst expected = declared.args.get(name);\n\t\t\tif (expected === undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`i18n: ${locale}: ${key} uses {${name}}, which ${fallbackLocale} does not declare`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (expected !== kind) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`i18n: ${locale}: ${key} uses {${name}} as ${kind}, and ${fallbackLocale} declares it as ${expected}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Checks the catalogues of every locale and answers their messages. A\n * catalogue that is not objects of camelCase keys, a message that does not\n * parse, and a locale that differs from the fallback locale in its keys or\n * its arguments **throw**, naming the locale and the key.\n */\nexport function checkCatalogues(\n\tcatalogues: Catalogues,\n\tlocales: readonly string[],\n\tfallbackLocale: string,\n): ReadonlyMap<string, Messages> {\n\tconst out = new Map<string, Messages>();\n\tfor (const locale of locales) {\n\t\tconst flat = new Map<string, string>();\n\t\tflatten(catalogues[locale], locale, '', flat);\n\t\tout.set(\n\t\t\tlocale,\n\t\t\tnew Map(\n\t\t\t\t[...flat].map(([key, text]) => [key, analyse(text, locale, key)]),\n\t\t\t),\n\t\t);\n\t}\n\tconst reference = out.get(fallbackLocale) as Messages;\n\tfor (const locale of locales) {\n\t\tif (locale !== fallbackLocale) {\n\t\t\tcompare(locale, out.get(locale) as Messages, fallbackLocale, reference);\n\t\t}\n\t}\n\treturn out;\n}\n",
10
10
  "import { isAbsolute } from 'node:path';\nimport type { TemplateFolder } from './wrappers';\n\n/** A package's folder of templates, for `i18n({ templates })`. */\nexport interface TemplateSource {\n\t/** The folder, absolute. */\n\treadonly dir: string;\n\t/** The e-mails of the folder to build, as `['verify-email']`. Default every one. */\n\treadonly emails?: readonly [string, ...string[]];\n}\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst isSource = (source: unknown): source is TemplateSource =>\n\tisObject(source) &&\n\ttypeof source.dir === 'string' &&\n\tisAbsolute(source.dir) &&\n\t(source.emails === undefined ||\n\t\t(Array.isArray(source.emails) &&\n\t\t\tsource.emails.length > 0 &&\n\t\t\tsource.emails.every((email) => typeof email === 'string') &&\n\t\t\tnew Set(source.emails).size === source.emails.length));\n\n/** Refuses a `templates` option that is not a list of {@link TemplateSource}. */\nexport function checkTemplates(\n\ttemplates: unknown,\n): asserts templates is readonly TemplateSource[] | undefined {\n\tif (\n\t\ttemplates !== undefined &&\n\t\t(!Array.isArray(templates) || !templates.every(isSource))\n\t) {\n\t\tthrow new TypeError(\n\t\t\t\"i18n: templates must be a list of template folders, as [{ dir: '/abs/path/emails' }] — emails, when given, names at least one, each once\",\n\t\t);\n\t}\n}\n\n/**\n * The folders the wrappers are written from: the project's `emails/` first,\n * so its template replaces a package's of the same name, then each package's.\n */\nexport function templateFolders(\n\temails: { readonly dir: string; readonly name: string },\n\ttemplates: readonly TemplateSource[],\n): TemplateFolder[] {\n\treturn [\n\t\t{ dir: emails.dir, label: emails.name },\n\t\t...templates.map((source, index) => ({\n\t\t\tdir: source.dir,\n\t\t\tlabel: `templates[${index}]`,\n\t\t\tpackaged: true,\n\t\t\t...(source.emails && { only: source.emails }),\n\t\t})),\n\t];\n}\n",
11
11
  "import type { ArgumentKind, Messages } from './catalogues';\nimport { placeholderMark } from './manifest';\nimport type { createFormatter, MessageArgs } from './translator';\n\nconst NAME = /^[a-z][a-zA-Z0-9]*$/;\n\nconst KINDS: Record<ArgumentKind, (value: unknown) => boolean> = {\n\tstring: (value) => typeof value === 'string' || typeof value === 'number',\n\tnumber: (value) => typeof value === 'number',\n\tdate: (value) => value instanceof Date || typeof value === 'number',\n};\n\nconst isPlaceholder = (value: unknown) =>\n\ttypeof value === 'string' && /^\\{\\{ [a-z][a-zA-Z0-9]* \\}\\}$/.test(value);\n\nconst kindOf = (value: unknown) =>\n\tvalue === null ? 'null' : value instanceof Date ? 'date' : typeof value;\n\n/**\n * What one template gets in one locale: `t`, `locale` and `placeholder`.\n *\n * `t` is checked against the fallback locale's message, which declares every\n * argument: an unknown key, an argument left out, one the message does not\n * use, or one of the wrong kind **fails the build**, naming the locale, the\n * template and the key.\n */\nexport function templateProperties(options: {\n\treadonly email: string;\n\treadonly locale: string;\n\treadonly messages: Messages;\n\treadonly reference: Messages;\n\treadonly format: ReturnType<typeof createFormatter>;\n}) {\n\tconst { email, locale, messages, reference, format } = options;\n\tconst where = `i18n: ${locale}: ${email}`;\n\treturn {\n\t\tlocale,\n\t\tt(key: string, args: MessageArgs = {}): string {\n\t\t\tconst message = typeof key === 'string' ? messages.get(key) : undefined;\n\t\t\tconst declared = typeof key === 'string' ? reference.get(key) : undefined;\n\t\t\tif (message === undefined || declared === undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${where} calls t('${String(key)}'), which is not a key of the catalogues`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (typeof args !== 'object' || args === null) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${where} calls t('${key}') with arguments that are not an object, as { name: placeholder('name') }`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tfor (const [name, kind] of declared.args) {\n\t\t\t\tif (!Object.hasOwn(args, name)) {\n\t\t\t\t\tthrow new Error(`${where} calls t('${key}') without {${name}}`);\n\t\t\t\t}\n\t\t\t\tif (declared.selects.has(name) && isPlaceholder(args[name])) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`${where} passes a placeholder to {${name}}, which ${key} chooses on with a select — a placeholder always chooses other`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (!KINDS[kind](args[name])) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`${where} passes {${name}} to ${key} as a ${kindOf(args[name])} — the message uses it as a ${kind}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const name of Object.keys(args)) {\n\t\t\t\tif (!declared.args.has(name)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`${where} passes {${name}} to ${key}, which does not use it`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn format(locale, key, message.text, args);\n\t\t},\n\t\tplaceholder(name: string): string {\n\t\t\tif (typeof name !== 'string' || !NAME.test(name)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${where} calls placeholder() with a name that is not camelCase — as placeholder('firstName')`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn placeholderMark(name);\n\t\t},\n\t};\n}\n",
12
- "import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { ArgumentKind, Messages } from './catalogues';\nimport type { Manifest } from './manifest';\n\n/** Where the template types go, under the project: `.maizzle/*.d.ts` is in the starter's `tsconfig.json`. */\nexport const TYPES_FILE = '.maizzle/nxgt-mail-i18n.d.ts';\n\n/** What `t` accepts for each kind — as the build checks it. */\nconst TYPE_OF: Readonly<Record<ArgumentKind, string>> = {\n\tstring: 'string | number',\n\tnumber: 'number',\n\tdate: 'Date | number',\n};\n\n/**\n * The declaration file that types `t` in the templates: each key of the\n * `reference` catalogue, with its arguments, so an editor completes a key and\n * flags an unknown one or a missing argument. Keys and names are checked\n * before this runs, so they are safe to write quoted.\n */\nexport function templateTypes(\n\treference: Messages,\n\tfallbackLocale: string,\n): string {\n\tconst entries = [...reference.entries()]\n\t\t.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n\t\t.map(([key, message]) => {\n\t\t\tconst args = [...message.args.entries()]\n\t\t\t\t.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n\t\t\t\t.map(([name, kind]) => `${name}: ${TYPE_OF[kind]}`);\n\t\t\treturn `\\t\\t'${key}': { ${args.join('; ')}${args.length > 0 ? ' ' : ''}};`;\n\t\t});\n\treturn [\n\t\t`// Generated by @nxgt/mail-i18n from the ${fallbackLocale} catalogue, each time the config loads.`,\n\t\t'// Never edited, never committed: it types t() in the templates.',\n\t\t\"import type {} from '@nxgt/mail-i18n';\",\n\t\t'',\n\t\t\"declare module '@nxgt/mail-i18n' {\",\n\t\t'\\tinterface TemplateMessages {',\n\t\t...entries,\n\t\t'\\t}',\n\t\t'}',\n\t\t'',\n\t].join('\\n');\n}\n\n/** The first line of the renderer's types: a file without it is not the plugin's to replace. */\nconst RENDERER_TYPES_HEADER = '// Generated by @nxgt/mail-i18n from the build';\n\n/** Where the renderer's types go, under the project, by default. */\nexport const RENDERER_TYPES_FILE = 'generated/mail.ts';\n\n/**\n * The module that types the renderer: `MailEmails`, each e-mail of the build\n * with the variables it takes at send time, for\n * `createMailRenderer<MailEmails>(…)`. A URL variable takes a string; any\n * other a string or a number, as `render` writes it. `@nxgt/mail`'s\n * `RenderArguments` reads `Readonly<Record<string, never>>` as an e-mail\n * without variables, and its type specs copy this output: change them\n * together.\n */\nexport function rendererTypes(manifest: Manifest): string {\n\tconst entries = Object.entries(manifest.emails)\n\t\t.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n\t\t.map(([email, { variables, urlVariables }]) => {\n\t\t\tconst fields = variables.map(\n\t\t\t\t(name) =>\n\t\t\t\t\t`readonly ${name}: ${urlVariables.includes(name) ? 'string' : 'string | number'}`,\n\t\t\t);\n\t\t\tconst type =\n\t\t\t\tfields.length > 0\n\t\t\t\t\t? `{ ${fields.join('; ')} }`\n\t\t\t\t\t: 'Readonly<Record<string, never>>';\n\t\t\t// A name is a file's path, quoted as JSON: valid TypeScript whatever it holds.\n\t\t\treturn `\\t${JSON.stringify(email)}: ${type};`;\n\t\t});\n\treturn [\n\t\t`${RENDERER_TYPES_HEADER}, after each maizzle build.`,\n\t\t'// Never edited; committed, so the code that sends type-checks without a build.',\n\t\t'',\n\t\t'/** The e-mails of the build, each with the variables it takes when it is sent. */',\n\t\t'export interface MailEmails {',\n\t\t...entries,\n\t\t'}',\n\t\t'',\n\t].join('\\n');\n}\n\n/**\n * Writes the renderer's types to `file`, shown as `path` — unless `file` holds\n * something the plugin did not write: that **throws**, and the file is kept.\n */\nexport function writeRendererTypes(\n\tfile: string,\n\tpath: string,\n\tsource: string,\n): void {\n\tif (\n\t\texistsSync(file) &&\n\t\t!readFileSync(file, 'utf8').startsWith(RENDERER_TYPES_HEADER)\n\t) {\n\t\tthrow new Error(\n\t\t\t`i18n: ${path} was not written by i18n() — point rendererTypes at a file of its own`,\n\t\t);\n\t}\n\twriteIfChanged(file, source);\n}\n\n/** Writes `source` to `file` only when it changed, so an editor or a watcher sees a change only where there is one. */\nexport function writeIfChanged(file: string, source: string): void {\n\tif (existsSync(file) && readFileSync(file, 'utf8') === source) return;\n\tmkdirSync(dirname(file), { recursive: true });\n\twriteFileSync(file, source);\n}\n"
12
+ "import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { ArgumentKind, Messages } from './catalogues';\nimport type { Manifest } from './manifest';\n\n/** Where the template types go, under the project: `.maizzle/*.d.ts` is in the starter's `tsconfig.json`. */\nexport const TYPES_FILE = '.maizzle/nxgt-mail-i18n.d.ts';\n\n/** What `t` accepts for each kind — as the build checks it. */\nconst TYPE_OF: Readonly<Record<ArgumentKind, string>> = {\n\tstring: 'string | number',\n\tnumber: 'number',\n\tdate: 'Date | number',\n};\n\n/**\n * The declaration file that types `t` in the templates: each key of the\n * `reference` catalogue, with its arguments, so an editor completes a key and\n * flags an unknown one or a missing argument. Keys and names are checked\n * before this runs, so they are safe to write quoted.\n */\nexport function templateTypes(\n\treference: Messages,\n\tfallbackLocale: string,\n): string {\n\tconst entries = [...reference.entries()]\n\t\t.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n\t\t.map(([key, message]) => {\n\t\t\tconst args = [...message.args.entries()]\n\t\t\t\t.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n\t\t\t\t.map(([name, kind]) => `${name}: ${TYPE_OF[kind]}`);\n\t\t\treturn `\\t\\t'${key}': { ${args.join('; ')}${args.length > 0 ? ' ' : ''}};`;\n\t\t});\n\treturn [\n\t\t`// Generated by @nxgt/mail-i18n from the ${fallbackLocale} catalogue, each time the config loads.`,\n\t\t'// Never edited, never committed: it types t() in the templates.',\n\t\t\"import type {} from '@nxgt/mail-i18n';\",\n\t\t'',\n\t\t\"declare module '@nxgt/mail-i18n' {\",\n\t\t'\\tinterface TemplateMessages {',\n\t\t...entries,\n\t\t'\\t}',\n\t\t'}',\n\t\t'',\n\t].join('\\n');\n}\n\n/** The first line of the renderer's types: a file without it is not the plugin's to replace. */\nconst RENDERER_TYPES_HEADER = '// Generated by @nxgt/mail-i18n from the build';\n\n/** Where the renderer's types go, under the project, by default. */\nexport const RENDERER_TYPES_FILE = 'generated/mail.ts';\n\n/**\n * The module that types the renderer: `MailEmails`, each e-mail of the build\n * with the variables it takes at send time, for\n * `createMailRenderer<MailEmails>(…)`. A URL variable takes a string; any\n * other a string or a number, as `render` writes it. `@nxgt/mail`'s\n * `RenderArguments` reads `Readonly<Record<string, never>>` as an e-mail\n * without variables, and its type specs copy this output: change them\n * together.\n */\nexport function rendererTypes(manifest: Manifest): string {\n\tconst entries = Object.entries(manifest.emails)\n\t\t.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n\t\t.map(([email, { variables, urlVariables }]) => {\n\t\t\tconst fields = variables.map(\n\t\t\t\t(name) =>\n\t\t\t\t\t`readonly ${name}: ${urlVariables.includes(name) ? 'string' : 'string | number'}`,\n\t\t\t);\n\t\t\tconst type =\n\t\t\t\tfields.length > 0\n\t\t\t\t\t? `{ ${fields.join('; ')} }`\n\t\t\t\t\t: 'Readonly<Record<string, never>>';\n\t\t\t// A name is a file's path, quoted as JSON: valid TypeScript whatever it holds.\n\t\t\treturn `\\t${JSON.stringify(email)}: ${type};`;\n\t\t});\n\treturn [\n\t\t`${RENDERER_TYPES_HEADER}, after each maizzle build.`,\n\t\t'// Never edited, never committed: git-ignore it, and build before type-checking.',\n\t\t'',\n\t\t'/** The e-mails of the build, each with the variables it takes when it is sent. */',\n\t\t'export interface MailEmails {',\n\t\t...entries,\n\t\t'}',\n\t\t'',\n\t].join('\\n');\n}\n\n/**\n * Writes the renderer's types to `file`, shown as `path` — unless `file` holds\n * something the plugin did not write: that **throws**, and the file is kept.\n */\nexport function writeRendererTypes(\n\tfile: string,\n\tpath: string,\n\tsource: string,\n): void {\n\tif (\n\t\texistsSync(file) &&\n\t\t!readFileSync(file, 'utf8').startsWith(RENDERER_TYPES_HEADER)\n\t) {\n\t\tthrow new Error(\n\t\t\t`i18n: ${path} was not written by i18n() — point rendererTypes at a file of its own`,\n\t\t);\n\t}\n\twriteIfChanged(file, source);\n}\n\n/** Writes `source` to `file` only when it changed, so an editor or a watcher sees a change only where there is one. */\nexport function writeIfChanged(file: string, source: string): void {\n\tif (existsSync(file) && readFileSync(file, 'utf8') === source) return;\n\tmkdirSync(dirname(file), { recursive: true });\n\twriteFileSync(file, source);\n}\n"
13
13
  ],
14
- "mappings": "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",
15
- "debugId": "874EDA850D792EF364756E2164756E21",
14
+ "mappings": "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",
15
+ "debugId": "3C814EA0EFDDBF5664756E2164756E21",
16
16
  "names": []
17
17
  }
@@ -18,8 +18,21 @@ export interface ManifestEmail {
18
18
  readonly text: string | null;
19
19
  }>>;
20
20
  }
21
+ /**
22
+ * The manifest's format. It changes only with the manifest's shape, and
23
+ * `@nxgt/mail`'s renderer reads every format up to its own within 0.x: a
24
+ * build from an older `@nxgt/mail-i18n` keeps working with a newer renderer.
25
+ * Copied in packages/mail/src/renderer.ts: change both.
26
+ */
27
+ export declare const MANIFEST_FORMAT = 1;
21
28
  /** `dist/mail-manifest.json`: what the build wrote, for the renderer. */
22
29
  export interface Manifest {
30
+ /**
31
+ * {@link MANIFEST_FORMAT} when built, and the first key written. This type
32
+ * is what this version writes: a manifest from `@nxgt/mail-i18n` 0.1 or
33
+ * 0.2 has no such field, and the renderer reads it as format 1.
34
+ */
35
+ readonly formatVersion: number;
23
36
  readonly locales: readonly string[];
24
37
  readonly fallbackLocale: string;
25
38
  readonly emails: Readonly<Record<string, ManifestEmail>>;
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAyB,KAAK,MAAM,EAAc,MAAM,YAAY,CAAC;AAE5E,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC7B,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CACvB,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CACvE,CAAC;CACF;AAED,yEAAyE;AACzE,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;CACzD;AAQD,wDAAwD;AACxD,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,WAAoB,CAAC;AAKjE,6EAA6E;AAC7E,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,WAM1B,CAAC;AA8Cb;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE;IACtC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CACjD,GAAG,QAAQ,CA8EX"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAyB,KAAK,MAAM,EAAc,MAAM,YAAY,CAAC;AAE5E,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC7B,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CACvB,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CACvE,CAAC;CACF;AAED;;;;;GAKG;AACH,eAAO,MAAM,eAAe,IAAI,CAAC;AAEjC,yEAAyE;AACzE,MAAM,WAAW,QAAQ;IACxB;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;CACzD;AAQD,wDAAwD;AACxD,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,WAAoB,CAAC;AAKjE,6EAA6E;AAC7E,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,WAM1B,CAAC;AA8Cb;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE;IACtC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CACjD,GAAG,QAAQ,CA+EX"}
package/dist/plugin.d.ts CHANGED
@@ -35,7 +35,7 @@ export interface I18nOptions {
35
35
  readonly rendererTypes?: string | false;
36
36
  }
37
37
  /** Where the wrappers go, under the project. */
38
- export declare const WRAPPERS_DIR = ".maizzle/i18n";
38
+ export declare const WRAPPERS_DIR = ".maizzle/emails";
39
39
  /** The manifest's name, in the output folder. */
40
40
  export declare const MANIFEST_FILE = "mail-manifest.json";
41
41
  /**
@@ -46,7 +46,7 @@ export declare const MANIFEST_FILE = "mail-manifest.json";
46
46
  * ```
47
47
  *
48
48
  * It checks `locales/<locale>.json`, writes one wrapper per template and
49
- * locale under `.maizzle/i18n/` so one build writes every locale, gives each
49
+ * locale under `.maizzle/emails/` so one build writes every locale, gives each
50
50
  * template `t`, `locale` and `placeholder`, and writes
51
51
  * `dist/mail-manifest.json`. A catalogue or a template that cannot be right
52
52
  * **fails the build**, naming the locale and the key.
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAEN,KAAK,UAAU,EAIf,MAAM,cAAc,CAAC;AAEtB,OAAO,EAEN,KAAK,cAAc,EAEnB,MAAM,WAAW,CAAC;AAWnB,OAAO,EACN,KAAK,MAAM,EAIX,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,WAAW;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,qFAAqF;IACrF,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,mEAAmE;IACnE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,gHAAgH;IAChH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC5C;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CACxC;AAED,gDAAgD;AAChD,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAE5C,iDAAiD;AACjD,eAAO,MAAM,aAAa,uBAAuB,CAAC;AAiGlD;;;;;;;;;;;;GAYG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,CAgGrD"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAEN,KAAK,UAAU,EAIf,MAAM,cAAc,CAAC;AAEtB,OAAO,EAEN,KAAK,cAAc,EAEnB,MAAM,WAAW,CAAC;AAWnB,OAAO,EACN,KAAK,MAAM,EAIX,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,WAAW;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,qFAAqF;IACrF,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,mEAAmE;IACnE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,gHAAgH;IAChH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC5C;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CACxC;AAED,gDAAgD;AAChD,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAE9C,iDAAiD;AACjD,eAAO,MAAM,aAAa,uBAAuB,CAAC;AAiGlD;;;;;;;;;;;;GAYG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,CAgGrD"}
package/docs/README.md CHANGED
@@ -10,7 +10,7 @@ in the
10
10
  | --- | --- |
11
11
  | [Catalogues](guide/catalogues.md) | You are writing `locales/<locale>.json`: nesting and `camelCase`, the kinds of argument, what each locale is checked for against the fallback locale, the subject key of each e-mail, catalogues a package ships (the `catalogues` option), and every build failure a catalogue causes |
12
12
  | [Templates](guide/templates.md) | You are writing `emails/*.vue`: `t`, `locale` and `placeholder`, where a placeholder can go, templates a package ships (the `templates` option), what fails the build, the files the build writes, and `maizzle serve` and its watcher |
13
- | [The manifest](guide/manifest.md) | You are reading `dist/mail-manifest.json`, the file the sending code uses: each field, how it is computed, and the flat layout; and `generated/mail.ts`, the `MailEmails` type that types `createMailRenderer`, with the `rendererTypes` option |
13
+ | [The manifest](guide/manifest.md) | You are reading `dist/mail-manifest.json`, the file the sending code uses: each field, how it is computed, and the flat layout; `formatVersion` and which `@nxgt/mail` reads it; shipping a build in a package; and `generated/mail.ts`, the `MailEmails` type that types `createMailRenderer`, with the `rendererTypes` option |
14
14
  | [Editor and type checking](guide/editor.md) | You want the editor to complete `t('…')` and flag an unknown key or a wrong argument, and `vue-tsc` to check your templates in CI: the tsconfig, `maizzle prepare`, the generated `.maizzle/nxgt-mail-i18n.d.ts`, what each kind of argument accepts, and `TemplateMessages`, `TemplateKey`, `TemplateArgs` |
15
15
  | [Translating outside templates](guide/translator.md) | You need a message in your application's code (a notification, a text message, a test) with `createTranslator`, and want to know how it differs from `@nxgt/i18n` |
16
16
  | [Troubleshooting](troubleshooting.md) | You have an error message and want its cause and its fix |
@@ -39,6 +39,7 @@ against:
39
39
 
40
40
  ```json
41
41
  {
42
+ "formatVersion": 1,
42
43
  "locales": ["en", "fr"],
43
44
  "fallbackLocale": "en",
44
45
  "emails": {
@@ -85,7 +86,10 @@ against:
85
86
  ## The shape
86
87
 
87
88
  ```ts
89
+ const MANIFEST_FORMAT = 1;
90
+
88
91
  interface Manifest {
92
+ readonly formatVersion: number;
89
93
  readonly locales: readonly string[];
90
94
  readonly fallbackLocale: string;
91
95
  readonly emails: Readonly<Record<string, ManifestEmail>>;
@@ -101,6 +105,7 @@ interface ManifestEmail {
101
105
 
102
106
  | Field | Holds |
103
107
  | --- | --- |
108
+ | `formatVersion` | The manifest's format, `MANIFEST_FORMAT` of the `@nxgt/mail-i18n` that built it: `1`. Written first |
104
109
  | `locales` | The plugin's `locales`, in the order given |
105
110
  | `fallbackLocale` | The plugin's `fallbackLocale`, or the first locale |
106
111
  | `emails` | One entry per e-mail, keyed by its template's path under `emails/` without `.vue` (`auth/reset-password`), sorted |
@@ -114,6 +119,30 @@ Each e-mail:
114
119
  | `subject` | The subject per locale, formatted from `<emailKey>.subject`, each argument kept as `{{ name }}` |
115
120
  | `files` | The built files per locale, relative to the output folder: `html`, and `text` or `null` when there is no plain-text part |
116
121
 
122
+ ### `formatVersion`
123
+
124
+ The format of the manifest's shape, so the renderer knows what it reads:
125
+
126
+ ```ts
127
+ import { MANIFEST_FORMAT } from '@nxgt/mail-i18n';
128
+
129
+ MANIFEST_FORMAT; // 1 — what this version writes as formatVersion
130
+ ```
131
+
132
+ - **It changes only when the manifest's shape does.** A new
133
+ `@nxgt/mail-i18n` that writes the same fields writes the same format.
134
+ - **`@nxgt/mail`'s renderer reads every format up to its own**, its
135
+ `MANIFEST_FORMAT` from `@nxgt/mail/renderer`, within 0.x. A build from any
136
+ earlier `@nxgt/mail-i18n` 0.x keeps working with a newer `@nxgt/mail`; a
137
+ newer format fails at start-up with `… is manifest format 2, newer than this
138
+ @nxgt/mail reads (1) — upgrade @nxgt/mail`.
139
+ - **A manifest without it is format 1**, as `@nxgt/mail-i18n` 0.1 and 0.2
140
+ wrote it.
141
+
142
+ See
143
+ [Rendering — which builds it reads](https://github.com/softistx/nxgt-mail/blob/develop/packages/mail/docs/guide/rendering.md#which-builds-it-reads--manifest_format)
144
+ in `@nxgt/mail`.
145
+
117
146
  ### `variables`
118
147
 
119
148
  Collected from the built files, not from the template's source: every
@@ -222,7 +251,7 @@ For the manifest above, the file holds exactly this:
222
251
 
223
252
  ```ts
224
253
  // Generated by @nxgt/mail-i18n from the build, after each maizzle build.
225
- // Never edited; committed, so the code that sends type-checks without a build.
254
+ // Never edited, never committed: git-ignore it, and build before type-checking.
226
255
 
227
256
  /** The e-mails of the build, each with the variables it takes when it is sent. */
228
257
  export interface MailEmails {
@@ -260,13 +289,28 @@ What each refusal looks like, and the untyped default, are in `@nxgt/mail`'s
260
289
  to check.
261
290
  - Its folder is created when missing.
262
291
 
263
- ### Commit it
292
+ ### Git-ignore it, and build before type-checking
264
293
 
265
- The file is the contract between the build and the code that sends, so it is
266
- committed, not ignored: a fresh clone type-checks, and CI checks the sending
267
- code, without running `maizzle build` first. When a template changes, the
268
- next build rewrites it, and the diff shows which e-mail gained or lost a
269
- variable.
294
+ The file is output of the build, as `dist/` is, so it is git-ignored, never
295
+ committed: a copy in git goes stale the moment a template changes, and each
296
+ build rewrites it anyway. Build before type-checking — locally and in CI:
297
+
298
+ ```gitignore
299
+ dist
300
+ generated
301
+ ```
302
+
303
+ ```json
304
+ {
305
+ "scripts": {
306
+ "typecheck": "maizzle build && tsc --noEmit"
307
+ }
308
+ }
309
+ ```
310
+
311
+ A fresh clone that type-checks before its first build reports
312
+ `Cannot find module './generated/mail'` — see
313
+ [troubleshooting](../troubleshooting.md#cannot-find-module-generatedmail-or-its-corresponding-type-declarations).
270
314
 
271
315
  The `generated/` folder holds generated code, never edited by hand: leave it
272
316
  out of your formatter and linter, as Biome's `"includes": ["**",
@@ -336,8 +380,66 @@ describe('the built e-mails', () => {
336
380
  `acme-mails` stands for wherever your built project lives: a package of its
337
381
  own, a folder of the repository, a build artefact.
338
382
 
383
+ ## Shipping a build in a package
384
+
385
+ A package can publish its e-mails already built — `mails/`, with its manifest
386
+ — so the application that installs it only creates a renderer. The build
387
+ decides which `@nxgt/mail` can read it, so the package peers the range whose
388
+ renderers read its format, and checks it when it builds:
389
+
390
+ ```json
391
+ {
392
+ "name": "acme-mails",
393
+ "files": ["mails"],
394
+ "scripts": {
395
+ "build": "maizzle build && bun run scripts/check-manifest-format.ts"
396
+ },
397
+ "peerDependencies": {
398
+ "@nxgt/mail": ">=0.1.0 <1"
399
+ },
400
+ "devDependencies": {
401
+ "@nxgt/mail": "0.5.1",
402
+ "@nxgt/mail-i18n": "^0.3.0"
403
+ }
404
+ }
405
+ ```
406
+
407
+ `maizzle.config.ts` writes the build there, with Maizzle's `output.path`:
408
+ `defineMailConfig({ output: { path: 'mails' }, plugins: [i18n({ locales:
409
+ ['en', 'fr'] })] })`. The check reads the format the build wrote, and compares
410
+ it with what the oldest `@nxgt/mail` you support reads:
411
+
412
+ ```ts
413
+ // scripts/check-manifest-format.ts — after maizzle build, before publishing
414
+ import { readFileSync } from 'node:fs';
415
+ import { MANIFEST_FILE, MANIFEST_FORMAT, type Manifest } from '@nxgt/mail-i18n';
416
+ import { MANIFEST_FORMAT as READABLE } from '@nxgt/mail/renderer'; // the devDependency: the oldest @nxgt/mail supported
417
+
418
+ const manifest: Manifest = JSON.parse(readFileSync(`mails/${MANIFEST_FILE}`, 'utf8'));
419
+
420
+ if (manifest.formatVersion !== MANIFEST_FORMAT) {
421
+ throw new Error(`mails/ is manifest format ${manifest.formatVersion}, not ${MANIFEST_FORMAT} — run maizzle build again`);
422
+ }
423
+ if (manifest.formatVersion > READABLE) {
424
+ throw new Error(
425
+ `mails/ is manifest format ${manifest.formatVersion}; the oldest @nxgt/mail supported reads up to ${READABLE} — raise the @nxgt/mail peer and devDependency`,
426
+ );
427
+ }
428
+ ```
429
+
430
+ - **The devDependency is the peer's lower bound**, so `MANIFEST_FORMAT` from
431
+ `@nxgt/mail/renderer` is what the oldest renderer an application may install
432
+ reads. `@nxgt/mail` 0.5.0 and earlier do not export it; they read format 1,
433
+ as 0.5.1 does, so a format-1 build pins 0.5.1 and still peers
434
+ `>=0.1.0 <1`.
435
+ - **When `@nxgt/mail-i18n` writes a new format**, the second check fails the
436
+ build: raise the peer's lower bound, and the devDependency with it, to the
437
+ first `@nxgt/mail` that reads it.
438
+ - **The first check** catches a `mails/` folder left from another build, made
439
+ before `@nxgt/mail-i18n` was upgraded.
440
+
339
441
  ## See also
340
442
 
341
- - [Rendering](https://github.com/softistx/nxgt-mail/blob/develop/packages/mail/docs/guide/rendering.md) in `@nxgt/mail` — the renderer that reads the manifest at send time.
443
+ - [Rendering](https://github.com/softistx/nxgt-mail/blob/develop/packages/mail/docs/guide/rendering.md) in `@nxgt/mail` — the renderer that reads the manifest at send time, and the formats it reads.
342
444
  - [Templates](templates.md) — where placeholders come from.
343
445
  - [Catalogues](catalogues.md#the-subject) — the subject of each e-mail.
@@ -247,7 +247,7 @@ i18n({
247
247
  The wrapper of a package's template imports it from where it is:
248
248
 
249
249
  ```vue
250
- <!-- .maizzle/i18n/fr/verify-email.vue, generated; the path follows your install -->
250
+ <!-- .maizzle/emails/fr/verify-email.vue, generated; the path follows your install -->
251
251
  <script setup>
252
252
  import Email from '../../../node_modules/@nxgt/mail-presets/emails/verify-email.vue';
253
253
  </script>
@@ -325,13 +325,13 @@ export default defineMailConfig({
325
325
  ## What the build writes
326
326
 
327
327
  For each template and locale, the plugin generates a small file, a
328
- **wrapper**, under `.maizzle/i18n/`. The wrapper imports the template and
328
+ **wrapper**, under `.maizzle/emails/`. The wrapper imports the template and
329
329
  nothing else, and the plugin points Maizzle's `content` at these files. One
330
330
  `maizzle build` then renders every template once per locale, and `t` knows
331
331
  which locale each render is for.
332
332
 
333
333
  ```vue
334
- <!-- .maizzle/i18n/fr/verify-email.vue, generated -->
334
+ <!-- .maizzle/emails/fr/verify-email.vue, generated -->
335
335
  <!-- Generated by @nxgt/mail-i18n: one per template and locale. Never edited, never committed. -->
336
336
  <script setup>
337
337
  import Email from '../../../emails/verify-email.vue';
@@ -351,8 +351,8 @@ default):
351
351
 
352
352
  | `layout` | Wrapper | Built files |
353
353
  | --- | --- | --- |
354
- | `'nested'` (default) | `.maizzle/i18n/fr/auth/reset-password.vue` | `dist/fr/auth/reset-password.html`, `.txt` |
355
- | `'flat'` | `.maizzle/i18n/auth/reset-password.fr.vue` | `dist/auth/reset-password.fr.html`, `.txt` |
354
+ | `'nested'` (default) | `.maizzle/emails/fr/auth/reset-password.vue` | `dist/fr/auth/reset-password.html`, `.txt` |
355
+ | `'flat'` | `.maizzle/emails/auth/reset-password.fr.vue` | `dist/auth/reset-password.fr.html`, `.txt` |
356
356
 
357
357
  ```ts
358
358
  // maizzle.config.ts — the fixture's flat build, in its own folder
@@ -373,10 +373,10 @@ Then the plugin writes `mail-manifest.json` next to them. See
373
373
  The dev UI lists each template once per locale, by its wrapper:
374
374
 
375
375
  ```text
376
- .maizzle/i18n/en/auth/reset-password.vue
377
- .maizzle/i18n/en/verify-email.vue
378
- .maizzle/i18n/fr/auth/reset-password.vue
379
- .maizzle/i18n/fr/verify-email.vue
376
+ .maizzle/emails/en/auth/reset-password.vue
377
+ .maizzle/emails/en/verify-email.vue
378
+ .maizzle/emails/fr/auth/reset-password.vue
379
+ .maizzle/emails/fr/verify-email.vue
380
380
  ```
381
381
 
382
382
  Placeholders show as they are, `Bonjour {{ name }},`: the preview is the file
package/docs/roadmap.md CHANGED
@@ -5,7 +5,10 @@ no dates here, and the version something shipped in is the only number.
5
5
 
6
6
  ## Now
7
7
 
8
- Nothing between releases.
8
+ - **The manifest's format, versioned** — `mail-manifest.json` starts with
9
+ `formatVersion`, `MANIFEST_FORMAT` is exported, and the format changes only
10
+ with the manifest's shape: any later `@nxgt/mail` 0.x reads the build.
11
+ Built, not yet published.
9
12
 
10
13
  ## Next
11
14
 
@@ -38,6 +41,11 @@ Nothing yet. A request is welcome as an
38
41
  The last ten, newest first, each with the version it came in. Everything
39
42
  before is in the [CHANGELOG](../CHANGELOG.md).
40
43
 
44
+ - **The wrappers under `.maizzle/emails/`, v0.2.0** — the files generated per
45
+ template and locale move from `.maizzle/i18n/` to `.maizzle/emails/`, so
46
+ `maizzle serve` lists the e-mails under `.maizzle/emails/en` rather than a
47
+ folder named after the plugin; `WRAPPERS_DIR` follows. The build output
48
+ does not move. Delete the old `.maizzle/i18n/` after upgrading.
41
49
  - **i18n as a plugin, v0.1.0** — `i18n({ locales, fallbackLocale })`, listed in
42
50
  `defineMailConfig`'s `plugins`: one template per e-mail, its text keys into
43
51
  `locales/<locale>.json` ICU catalogues, and one output per locale from a
@@ -79,13 +87,8 @@ before is in the [CHANGELOG](../CHANGELOG.md).
79
87
  CI.
80
88
  - **The renderer typed by the build, v0.1.0** — after each `maizzle build`, the
81
89
  plugin writes `generated/mail.ts`: `MailEmails`, each e-mail with the
82
- variables it takes, a URL variable as a `string`. Committed, it lets
83
- `createMailRenderer<MailEmails>` from `@nxgt/mail/renderer` refuse an
90
+ variables it takes, a URL variable as a `string`. With it,
91
+ `createMailRenderer<MailEmails>` from `@nxgt/mail/renderer` refuses an
84
92
  unknown e-mail, a missing or unknown variable, or a number for a URL at
85
- compile time, without a build in CI. Rewritten only when it changes;
93
+ compile time. Rewritten only when it changes;
86
94
  `rendererTypes` moves it, or `false` turns it off.
87
- - **A starter project, with v0.1.0** — the official Maizzle starter with
88
- `defineMailConfig`, the i18n and the UI plugins wired in as the READMEs
89
- say, built, rendered in `en` and `fr` and served in CI, so the snippets are
90
- known to work: [`examples/starter`](https://github.com/softistx/nxgt-mail/tree/develop/examples/starter).
91
- In the repository; its README says how to start your own from npm.
@@ -32,6 +32,7 @@ template `emails/verify-email.vue`, and keys such as `verifyEmail.title`.
32
32
 
33
33
  **Install and types**
34
34
  - [Which `moduleResolution` is supported](#install-and-types)
35
+ - [`Cannot find module './generated/mail' or its corresponding type declarations`](#cannot-find-module-generatedmail-or-its-corresponding-type-declarations)
35
36
 
36
37
  **Wiring**
37
38
  - [`i18n: options must be an object, as { locales: ['en', 'fr'] }`](#i18n-options-must-be-an-object-as--locales-en-fr-)
@@ -96,6 +97,7 @@ template `emails/verify-email.vue`, and keys such as `verifyEmail.title`.
96
97
  - [`[Vue warn]: Property "name" was accessed during render but is not defined on instance.`](#vue-warn-property-name-was-accessed-during-render-but-is-not-defined-on-instance)
97
98
  - [A link's placeholder is prefixed with a domain](#a-links-placeholder-is-prefixed-with-a-domain)
98
99
  - [`.maizzle/` shows up in `git status`](#maizzle-shows-up-in-git-status)
100
+ - [A `.maizzle/i18n/` folder is left after upgrading](#a-maizzlei18n-folder-is-left-after-upgrading)
99
101
  - [`No templates found`, or old templates, when Maizzle is built from a worker thread](#no-templates-found-or-old-templates-when-maizzle-is-built-from-a-worker-thread)
100
102
  - [The editor says `Property 't' does not exist` in a template, or completes no key](#the-editor-says-property-t-does-not-exist-in-a-template-or-completes-no-key)
101
103
  - [The editor flags a key you just added to a catalogue](#the-editor-flags-a-key-you-just-added-to-a-catalogue)
@@ -110,6 +112,26 @@ Resolve as a bundler does (`"moduleResolution": "bundler"`, as Maizzle's jiti
110
112
  loader does): that is the supported contract. `nodenext` and `node16` are out
111
113
  of contract — they may work today, and are not tested.
112
114
 
115
+ ### `Cannot find module './generated/mail' or its corresponding type declarations`
116
+
117
+ **When:** `tsc` or `vue-tsc` (TS2307), or the editor, on the code that sends
118
+ — `import type { MailEmails } from './generated/mail'` — in a fresh clone,
119
+ or in CI, before any `maizzle build`.
120
+ **Why:** `generated/mail.ts` is written by each build and git-ignored, as
121
+ `dist/` is: until the project has been built once, it does not exist.
122
+ **Fix:** build before type-checking, in the script CI runs too:
123
+
124
+ ```json
125
+ {
126
+ "scripts": {
127
+ "typecheck": "maizzle build && tsc --noEmit"
128
+ }
129
+ }
130
+ ```
131
+
132
+ In an editor, run `maizzle build` once after cloning, and again when an
133
+ e-mail gains or loses a variable.
134
+
113
135
  ---
114
136
 
115
137
  ## Wiring
@@ -614,7 +636,7 @@ emails/auth/reset-password.vue → messages under auth.resetPassword
614
636
  **When:** `maizzle build`, on the first template, when the project sets
615
637
  `content` itself.
616
638
  **Why:** the plugin builds each template through one generated wrapper per
617
- locale, under `.maizzle/i18n/`, and lists those in `content`. A `content`
639
+ locale, under `.maizzle/emails/`, and lists those in `content`. A `content`
618
640
  set in the project **replaces** the plugin's — arrays are not joined — so
619
641
  Maizzle builds the templates directly, with no locale.
620
642
  **Fix:** leave `content` out, and put every template in the `emails` folder
@@ -985,7 +1007,7 @@ export default defineMailConfig({
985
1007
  ### `.maizzle/` shows up in `git status`
986
1008
 
987
1009
  **When:** after the first `maizzle build` or `maizzle serve`, `git status`
988
- lists `.maizzle/i18n/en/verify-email.vue` and one file per template and
1010
+ lists `.maizzle/emails/en/verify-email.vue` and one file per template and
989
1011
  locale.
990
1012
  **Why:** those are the wrappers the plugin generates, one per template and
991
1013
  locale, so that one build writes every locale. They are rewritten on every
@@ -999,13 +1021,28 @@ build, and removed when their template is.
999
1021
 
1000
1022
  Never edit a wrapper: the change is lost on the next build.
1001
1023
 
1024
+ ### A `.maizzle/i18n/` folder is left after upgrading
1025
+
1026
+ **When:** after upgrading `@nxgt/mail-i18n` from 0.1 to 0.2 or later,
1027
+ `.maizzle/` holds both `i18n/` and `emails/`.
1028
+ **Why:** 0.1 wrote the wrappers under `.maizzle/i18n/`; 0.2 writes them under
1029
+ `.maizzle/emails/`, so that `maizzle serve` lists the e-mails under a folder
1030
+ that says what they are. Nothing reads the old folder any more — not the
1031
+ build, not `maizzle serve`, not the type-check — and the build output does
1032
+ not move.
1033
+ **Fix:** delete it, once:
1034
+
1035
+ ```sh
1036
+ rm -rf .maizzle/i18n
1037
+ ```
1038
+
1002
1039
  ### `No templates found`, or old templates, when Maizzle is built from a worker thread
1003
1040
 
1004
1041
  **When:** Maizzle's `build()` is called from code that runs in a worker
1005
1042
  thread, such as a job runner or a Vitest `threads` pool. The build prints
1006
1043
  `No templates found`, or builds templates that were since renamed or
1007
1044
  removed, without the ones added.
1008
- **Why:** the plugin writes the wrappers under `.maizzle/i18n/` only on the
1045
+ **Why:** the plugin writes the wrappers under `.maizzle/emails/` only on the
1009
1046
  main thread, so that the workers of a parallel build never write the same
1010
1047
  file twice. From a worker thread it writes none, and the build finds whatever
1011
1048
  wrappers are already there, or none at all.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxgt/mail-i18n",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "An i18n plugin for a Maizzle project: ICU catalogues checked at build time, t() in templates, one output per locale, and the manifest the renderer reads. createTranslator for use outside templates.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -52,14 +52,14 @@
52
52
  "devDependencies": {
53
53
  "@maizzle/framework": "6.1.7",
54
54
  "@maizzle/tailwindcss": "1.5.6",
55
- "@nxgt/mail-config": "0.1.0",
55
+ "@nxgt/mail-config": "0.2.0",
56
56
  "@types/bun": "^1.4.2",
57
57
  "vue": "3.5.43",
58
58
  "vue-tsc": "^3.3.11"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@maizzle/framework": "^6.1.7",
62
- "@nxgt/mail-config": "^0.1.0",
62
+ "@nxgt/mail-config": "^0.2.0",
63
63
  "typescript": "^6.0.3",
64
64
  "vue": "^3.5.0"
65
65
  },