@nxgt/mail-config 0.1.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/LICENSE +21 -0
- package/README.md +239 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +173 -0
- package/dist/index.js.map +11 -0
- package/dist/layer.d.ts +10 -0
- package/dist/layer.d.ts.map +1 -0
- package/docs/README.md +14 -0
- package/docs/guide/config.md +305 -0
- package/docs/guide/plugins.md +280 -0
- package/docs/guide/production.md +168 -0
- package/docs/roadmap.md +76 -0
- package/docs/troubleshooting.md +497 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Steve Tsala
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# @nxgt/mail-config
|
|
2
|
+
|
|
3
|
+
Less boilerplate in a normal [Maizzle](https://maizzle.com) 6 project of
|
|
4
|
+
transactional e-mails: `defineMailConfig` layers **plugins** — partial Maizzle
|
|
5
|
+
configs shipped by packages — under your own `maizzle.config.ts`, and runs every
|
|
6
|
+
plugin's build events one after the other instead of letting the last one
|
|
7
|
+
silently replace the others.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// maizzle.config.ts
|
|
11
|
+
import { defineMailConfig } from '@nxgt/mail-config';
|
|
12
|
+
import { brand } from './plugins/brand';
|
|
13
|
+
|
|
14
|
+
export default defineMailConfig({
|
|
15
|
+
plugins: [brand],
|
|
16
|
+
// your own Maizzle config, as usual — it wins over every plugin
|
|
17
|
+
afterTransform: ({ html }) => `${html}<!-- built by the project -->`,
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Your project stays a Maizzle project: `emails/`, `components/`, `public/`,
|
|
22
|
+
`maizzle serve`, `maizzle build`. Nothing here replaces a Maizzle command.
|
|
23
|
+
|
|
24
|
+
> **0.x.** A minor version may still change the surface; the changelog says how.
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
bun add @nxgt/mail-config @maizzle/framework @maizzle/tailwindcss
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Peers, all required:
|
|
33
|
+
|
|
34
|
+
- `@maizzle/framework` (`^6.1.7`) — Maizzle itself.
|
|
35
|
+
- `@maizzle/tailwindcss` (`^1.5.6`) — **as a direct dependency of your
|
|
36
|
+
project**, even if another package already brings it: see
|
|
37
|
+
[Setup](#setup).
|
|
38
|
+
- `typescript` (6). Bundler resolution (`"moduleResolution": "bundler"`) is
|
|
39
|
+
what is supported and tested; `nodenext` is out of contract.
|
|
40
|
+
|
|
41
|
+
## Setup
|
|
42
|
+
|
|
43
|
+
```css
|
|
44
|
+
/* in the <style> your layout imports Tailwind from */
|
|
45
|
+
@import "@maizzle/tailwindcss";
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
That import is resolved from your project. Under an isolated install — Bun
|
|
49
|
+
workspaces, pnpm — a copy that is only a dependency of another package is not
|
|
50
|
+
reachable from there, and the import fails **silently**: the build succeeds,
|
|
51
|
+
and no Tailwind utility is generated. Listing `@maizzle/tailwindcss` in
|
|
52
|
+
your own `package.json`, as the `bun add` above does, is what makes it
|
|
53
|
+
resolve.
|
|
54
|
+
|
|
55
|
+
## Exports
|
|
56
|
+
|
|
57
|
+
| Export | What it is |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `defineMailConfig(config?)` | Your `maizzle.config.ts`: base, plugins, then your config |
|
|
60
|
+
| `defineMailPlugin(plugin)` | Checks a plugin and answers it unchanged |
|
|
61
|
+
| `productionConfig(config, overrides?)` | `maizzle.config.production.ts`: minified HTML over your config |
|
|
62
|
+
| `baseConfig` | The lowest layer, `{ plaintext: true }`, frozen |
|
|
63
|
+
| `MailConfig` | The type `defineMailConfig` takes: a `MaizzleConfig` with `plugins` |
|
|
64
|
+
| `MailPlugin` | The type of a plugin: a `MaizzleConfig` with a `name`, and no `plugins` |
|
|
65
|
+
|
|
66
|
+
## Usage
|
|
67
|
+
|
|
68
|
+
### A project config — `defineMailConfig`
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
// maizzle.config.ts
|
|
72
|
+
import { defineMailConfig } from '@nxgt/mail-config';
|
|
73
|
+
import { alpha, beta } from './plugins';
|
|
74
|
+
|
|
75
|
+
export default defineMailConfig({
|
|
76
|
+
plugins: [alpha, beta],
|
|
77
|
+
vue: { globalProperties: { greeting: 'from the project' } },
|
|
78
|
+
afterTransform: ({ html }) => `${html}<!-- project -->`,
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The layers, lowest first:
|
|
83
|
+
|
|
84
|
+
1. **`baseConfig`** — `{ plaintext: true }`: a `.txt` part next to each
|
|
85
|
+
`.html`. Everything else a project needs (`dist/`, `public/` copied, CSS
|
|
86
|
+
inlined and purged) is already Maizzle's default.
|
|
87
|
+
2. **Each plugin, in the order listed** — a later plugin wins over an earlier
|
|
88
|
+
one.
|
|
89
|
+
3. **The rest of your config** — it wins over every plugin.
|
|
90
|
+
|
|
91
|
+
How two layers merge:
|
|
92
|
+
|
|
93
|
+
| What | Rule |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| An object (`output`, `css`, `vue.globalProperties`…) | Merged key by key; the later layer's key wins, a key only an earlier layer sets stays |
|
|
96
|
+
| An array (`content`, `static.source`…) | **Replaced** by the later layer's, as Maizzle's own merge does |
|
|
97
|
+
| `components.source`, `vite.plugins`, `vue.plugins` | **Joined**, in layer order: two plugins that each bring components keep both. A `vue.plugins` factory (`() => Plugin[]`) stays a factory, called once per render |
|
|
98
|
+
| A build event | **Chained** — see below |
|
|
99
|
+
|
|
100
|
+
The result is a plain Maizzle config: `plugins` and each plugin's `name` are
|
|
101
|
+
not passed to Maizzle. See [The project config](docs/guide/config.md).
|
|
102
|
+
|
|
103
|
+
### Build events, chained
|
|
104
|
+
|
|
105
|
+
Every layer's handler for an event runs, in layer order, each awaited before
|
|
106
|
+
the next:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { defineMailConfig, defineMailPlugin } from '@nxgt/mail-config';
|
|
110
|
+
|
|
111
|
+
const alpha = defineMailPlugin({
|
|
112
|
+
name: 'alpha',
|
|
113
|
+
beforeRender: ({ template }) => template.source.replace('[[mark]]', '[[alpha]]'),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const beta = defineMailPlugin({
|
|
117
|
+
name: 'beta', // listed after alpha, so it sees alpha's source
|
|
118
|
+
beforeRender: ({ template }) => template.source.replace('[[alpha]]', 'alpha then beta'),
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
export default defineMailConfig({ plugins: [alpha, beta] }); // [[mark]] → alpha then beta
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
| Event | What a returned string does |
|
|
125
|
+
| --- | --- |
|
|
126
|
+
| `beforeCreate` | Nothing — every handler runs, in order |
|
|
127
|
+
| `beforeRender` | Replaces `template.source`, which the next handler reads |
|
|
128
|
+
| `afterRender`, `afterTransform` | Replaces the `html` the next handler receives; the last string is the output |
|
|
129
|
+
| `afterBuild` | Nothing — every handler runs, in order |
|
|
130
|
+
|
|
131
|
+
A handler that returns nothing leaves the source or the HTML as it was. A
|
|
132
|
+
handler that **throws stops the chain**: the handlers after it do not run, and
|
|
133
|
+
the error reaches Maizzle, which fails the build.
|
|
134
|
+
|
|
135
|
+
### A plugin — `defineMailPlugin`
|
|
136
|
+
|
|
137
|
+
A plugin is a partial Maizzle config with a `name`. A package exports one,
|
|
138
|
+
checked where it is written — a mistake throws `defineMailPlugin: plugin …`
|
|
139
|
+
when the package loads, not in each project that lists it:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
// plugins/brand.ts
|
|
143
|
+
import { fileURLToPath } from 'node:url';
|
|
144
|
+
import { defineMailPlugin } from '@nxgt/mail-config';
|
|
145
|
+
|
|
146
|
+
export const brand = defineMailPlugin({
|
|
147
|
+
name: 'brand',
|
|
148
|
+
components: {
|
|
149
|
+
source: [{ path: fileURLToPath(new URL('./components', import.meta.url)), prefix: 'Brand' }],
|
|
150
|
+
},
|
|
151
|
+
vue: { globalProperties: { company: 'Example Inc.' } },
|
|
152
|
+
afterTransform: ({ html }) => `${html}<!-- brand -->`,
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`components/footer.vue` next to that file is `<BrandFooter>` in every template.
|
|
157
|
+
See [Writing a plugin](docs/guide/plugins.md).
|
|
158
|
+
|
|
159
|
+
### A production build — `productionConfig`
|
|
160
|
+
|
|
161
|
+
Maizzle has no environments: `maizzle build -c <file>` loads that file and no
|
|
162
|
+
other, so the production config imports the project's.
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
// maizzle.config.production.ts
|
|
166
|
+
import { productionConfig } from '@nxgt/mail-config';
|
|
167
|
+
import config from './maizzle.config';
|
|
168
|
+
|
|
169
|
+
export default productionConfig(config, { output: { path: 'dist-production' } });
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
```sh
|
|
173
|
+
maizzle build -c maizzle.config.production.ts
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
It layers your config, then `{ html: { minify: true } }` — unless your config
|
|
177
|
+
already set minify options, which are kept — then the overrides, merged as a
|
|
178
|
+
plugin is: their `components.source`, `vite.plugins` and `vue.plugins` are
|
|
179
|
+
added to yours, their build events run after yours. See
|
|
180
|
+
[Production](docs/guide/production.md).
|
|
181
|
+
|
|
182
|
+
## Traps
|
|
183
|
+
|
|
184
|
+
**A plugin's paths are absolute.** Maizzle resolves a relative
|
|
185
|
+
`components.source` against the directory `maizzle` runs in — your project,
|
|
186
|
+
not the package: write `fileURLToPath(new URL('./components', import.meta.url))`.
|
|
187
|
+
|
|
188
|
+
**A plugin that sets an array replaces the default under it.** `content:
|
|
189
|
+
['src/**/*.vue']` in a plugin drops Maizzle's `emails/**/*.{vue,md}`, as it
|
|
190
|
+
would in your own config.
|
|
191
|
+
|
|
192
|
+
**Do not set a build event by spreading configs yourself.** `{ ...a, ...b }`
|
|
193
|
+
keeps `b`'s `beforeRender` and drops `a`'s without a word; list both in
|
|
194
|
+
`plugins`.
|
|
195
|
+
|
|
196
|
+
**Pass `productionConfig` what `defineMailConfig` answered**, not its argument,
|
|
197
|
+
and list every plugin in the project config: `plugins` in either argument of
|
|
198
|
+
`productionConfig` is a type error, and a `TypeError` at load time.
|
|
199
|
+
|
|
200
|
+
**A wiring mistake is a bare `TypeError`**, thrown when the config file loads:
|
|
201
|
+
a plugin that was not called, a plugin without a `name`, two plugins with the
|
|
202
|
+
same `name`, a build event that is not a function. Each message names the
|
|
203
|
+
plugin or its index — the list is in [The project config](docs/guide/config.md#errors).
|
|
204
|
+
|
|
205
|
+
## Type safety, counted
|
|
206
|
+
|
|
207
|
+
**6 plausible mistakes, 6 refused** at compile time, each measured by a
|
|
208
|
+
`@ts-expect-error` in
|
|
209
|
+
[`test/types/refusals.ts`](https://github.com/softistx/nxgt-mail/blob/develop/packages/mail-config/test/types/refusals.ts)
|
|
210
|
+
that fails the typecheck the moment it stops holding:
|
|
211
|
+
|
|
212
|
+
1. A plugin without a `name`.
|
|
213
|
+
2. `plugins` given one plugin rather than a list.
|
|
214
|
+
3. A build event that is not a function (`beforeRender: 'x'`).
|
|
215
|
+
4. A plugin that brings other plugins.
|
|
216
|
+
5. `productionConfig` given `defineMailConfig`'s argument instead of what it
|
|
217
|
+
answered.
|
|
218
|
+
6. Plugins added in `productionConfig`'s overrides.
|
|
219
|
+
|
|
220
|
+
The same file holds the calls that must keep compiling: a refusal that refuses
|
|
221
|
+
the correct call is a bug.
|
|
222
|
+
|
|
223
|
+
Maizzle's own keys are not refused: its config type takes any key
|
|
224
|
+
(`[key: string]: any`), so a misspelled Maizzle option compiles. What this
|
|
225
|
+
package adds — `name`, `plugins`, the build events' types — is checked.
|
|
226
|
+
|
|
227
|
+
## Documentation
|
|
228
|
+
|
|
229
|
+
- [The guides](docs/README.md) — one page per area, with every option and error.
|
|
230
|
+
- [Troubleshooting](docs/troubleshooting.md) — an error message, its cause and
|
|
231
|
+
its fix.
|
|
232
|
+
- [Roadmap](docs/roadmap.md) — what is next, and what is deliberately not
|
|
233
|
+
planned.
|
|
234
|
+
- [Vocabulary](https://github.com/softistx/nxgt-mail/blob/develop/docs/vocabulary.md)
|
|
235
|
+
— the words these pages use, defined once.
|
|
236
|
+
|
|
237
|
+
## Licence
|
|
238
|
+
|
|
239
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nxgt/mail-config` — a shareable Maizzle config.
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* // maizzle.config.ts
|
|
6
|
+
* import { defineMailConfig } from '@nxgt/mail-config';
|
|
7
|
+
*
|
|
8
|
+
* export default defineMailConfig({
|
|
9
|
+
* plugins: [ui({ brand }), i18n({ locales: ['en', 'fr'] })],
|
|
10
|
+
* // the project's own Maizzle config, which wins over every plugin
|
|
11
|
+
* });
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* A plugin is a partial Maizzle config with a `name`. The layers are the base
|
|
15
|
+
* config, then each plugin in order, then the project; every build event runs
|
|
16
|
+
* each layer's handler in that order instead of the last one replacing the
|
|
17
|
+
* others.
|
|
18
|
+
*/
|
|
19
|
+
import type { MaizzleConfig } from '@maizzle/framework';
|
|
20
|
+
/** A partial Maizzle config a package hands to {@link defineMailConfig}. */
|
|
21
|
+
export interface MailPlugin extends MaizzleConfig {
|
|
22
|
+
/** Names the plugin in an error; two plugins of a project never share one. */
|
|
23
|
+
readonly name: string;
|
|
24
|
+
/** A plugin cannot bring others: the project lists every plugin. */
|
|
25
|
+
readonly plugins?: never;
|
|
26
|
+
}
|
|
27
|
+
/** A project's Maizzle config, with the plugins layered under it. */
|
|
28
|
+
export interface MailConfig extends MaizzleConfig {
|
|
29
|
+
/** Layered in order, each over the one before, all under the project. */
|
|
30
|
+
readonly plugins?: readonly MailPlugin[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* What a project gets without asking: a plain-text part next to each HTML
|
|
34
|
+
* file. Everything else — `dist/`, `public/`, CSS inlined and purged — is
|
|
35
|
+
* already Maizzle's default.
|
|
36
|
+
*/
|
|
37
|
+
export declare const baseConfig: Readonly<MaizzleConfig>;
|
|
38
|
+
/**
|
|
39
|
+
* Checks a plugin and answers it as it is: for a package that exports one, so
|
|
40
|
+
* its mistakes surface where it is written, not in the project that uses it.
|
|
41
|
+
* Typed `MailPlugin`, so a package's declarations can name what it exports.
|
|
42
|
+
*/
|
|
43
|
+
export declare function defineMailPlugin(plugin: MailPlugin): MailPlugin;
|
|
44
|
+
/**
|
|
45
|
+
* The project's Maizzle config: {@link baseConfig}, then each plugin in
|
|
46
|
+
* order, then the rest of `config`. Objects merge and arrays replace, as in
|
|
47
|
+
* Maizzle — except `components.source`, `vite.plugins` and `vue.plugins`,
|
|
48
|
+
* which every layer adds to. Every build event runs each layer's handler, in
|
|
49
|
+
* that order.
|
|
50
|
+
*/
|
|
51
|
+
export declare function defineMailConfig(config?: MailConfig): MaizzleConfig;
|
|
52
|
+
/**
|
|
53
|
+
* The production build's config, for `maizzle.config.production.ts`: the
|
|
54
|
+
* project's `config`, with the HTML minified — with the project's own
|
|
55
|
+
* `html.minify` options when it set some — then `overrides`, merged as a
|
|
56
|
+
* plugin is: its `components.source`, `vite.plugins` and `vue.plugins` are
|
|
57
|
+
* added to the project's, its build events run after the project's.
|
|
58
|
+
*
|
|
59
|
+
* ```ts
|
|
60
|
+
* // maizzle.config.production.ts — `maizzle build -c maizzle.config.production.ts`
|
|
61
|
+
* import config from './maizzle.config';
|
|
62
|
+
* import { productionConfig } from '@nxgt/mail-config';
|
|
63
|
+
*
|
|
64
|
+
* export default productionConfig(config, { output: { path: 'dist-production' } });
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function productionConfig(config: MaizzleConfig & {
|
|
68
|
+
readonly plugins?: never;
|
|
69
|
+
}, overrides?: MaizzleConfig & {
|
|
70
|
+
readonly plugins?: never;
|
|
71
|
+
}): MaizzleConfig;
|
|
72
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,4EAA4E;AAC5E,MAAM,WAAW,UAAW,SAAQ,aAAa;IAChD,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC;CACzB;AAED,qEAAqE;AACrE,MAAM,WAAW,UAAW,SAAQ,aAAa;IAChD,yEAAyE;IACzE,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;CACzC;AAED;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,QAAQ,CAAC,aAAa,CAE7C,CAAC;AA0CH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAG/D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,GAAE,UAAe,GAAG,aAAa,CAwBvE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,aAAa,GAAG;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,CAAA;CAAE,EACpD,SAAS,GAAE,aAAa,GAAG;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,CAAA;CAAO,GAC1D,aAAa,CAyBf"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// src/layer.ts
|
|
2
|
+
import { createDefu } from "defu";
|
|
3
|
+
var EVENTS = [
|
|
4
|
+
"beforeCreate",
|
|
5
|
+
"beforeRender",
|
|
6
|
+
"afterRender",
|
|
7
|
+
"afterTransform",
|
|
8
|
+
"afterBuild"
|
|
9
|
+
];
|
|
10
|
+
var merge = createDefu((target, key, value) => {
|
|
11
|
+
if (Array.isArray(target[key])) {
|
|
12
|
+
target[key] = value;
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
var LISTS = [
|
|
17
|
+
["components", "source"],
|
|
18
|
+
["vite", "plugins"],
|
|
19
|
+
["vue", "plugins"]
|
|
20
|
+
];
|
|
21
|
+
var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22
|
+
function joinVuePlugins(values) {
|
|
23
|
+
if (values.every(Array.isArray))
|
|
24
|
+
return values.flat();
|
|
25
|
+
return () => values.flatMap((value) => typeof value === "function" ? value() : value);
|
|
26
|
+
}
|
|
27
|
+
function takeLists(layers) {
|
|
28
|
+
const joined = [];
|
|
29
|
+
for (const [group, key] of LISTS) {
|
|
30
|
+
const values = [];
|
|
31
|
+
for (const layer of layers) {
|
|
32
|
+
const section = layer[group];
|
|
33
|
+
if (!isObject(section) || section[key] == null)
|
|
34
|
+
continue;
|
|
35
|
+
values.push(section[key]);
|
|
36
|
+
const { [key]: _, ...rest } = section;
|
|
37
|
+
layer[group] = rest;
|
|
38
|
+
}
|
|
39
|
+
if (values.length === 0)
|
|
40
|
+
continue;
|
|
41
|
+
const value = group === "vue" ? joinVuePlugins(values) : values.flatMap((entry) => Array.isArray(entry) ? entry : [entry]);
|
|
42
|
+
joined.push([group, key, value]);
|
|
43
|
+
}
|
|
44
|
+
return joined;
|
|
45
|
+
}
|
|
46
|
+
function chain(event, handlers) {
|
|
47
|
+
if (handlers.length === 1)
|
|
48
|
+
return handlers[0];
|
|
49
|
+
if (event === "beforeRender") {
|
|
50
|
+
return async (params) => {
|
|
51
|
+
for (const handler of handlers) {
|
|
52
|
+
const result = await handler(params);
|
|
53
|
+
if (typeof result === "string")
|
|
54
|
+
params.template.source = result;
|
|
55
|
+
}
|
|
56
|
+
return params.template.source;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (event === "afterRender" || event === "afterTransform") {
|
|
60
|
+
return async ({ config, template, html }) => {
|
|
61
|
+
let current = html;
|
|
62
|
+
for (const handler of handlers) {
|
|
63
|
+
const result = await handler({ config, template, html: current });
|
|
64
|
+
if (typeof result === "string")
|
|
65
|
+
current = result;
|
|
66
|
+
}
|
|
67
|
+
return current;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return async (params) => {
|
|
71
|
+
for (const handler of handlers)
|
|
72
|
+
await handler(params);
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function layer(layers) {
|
|
76
|
+
const copies = layers.map((config) => ({ ...config }));
|
|
77
|
+
const handlers = new Map;
|
|
78
|
+
for (const copy of copies) {
|
|
79
|
+
for (const event of EVENTS) {
|
|
80
|
+
const handler = copy[event];
|
|
81
|
+
if (handler === undefined)
|
|
82
|
+
continue;
|
|
83
|
+
handlers.set(event, [...handlers.get(event) ?? [], handler]);
|
|
84
|
+
delete copy[event];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const lists = takeLists(copies);
|
|
88
|
+
const merged = merge({}, ...copies.reverse());
|
|
89
|
+
for (const [group, key, value] of lists) {
|
|
90
|
+
merged[group] = { ...merged[group], [key]: value };
|
|
91
|
+
}
|
|
92
|
+
for (const [event, list] of handlers)
|
|
93
|
+
merged[event] = chain(event, list);
|
|
94
|
+
return merged;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/index.ts
|
|
98
|
+
var baseConfig = Object.freeze({
|
|
99
|
+
plaintext: true
|
|
100
|
+
});
|
|
101
|
+
var isObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
102
|
+
function checkHandlers(config, where) {
|
|
103
|
+
for (const event of EVENTS) {
|
|
104
|
+
const handler = config[event];
|
|
105
|
+
if (handler !== undefined && typeof handler !== "function") {
|
|
106
|
+
throw new TypeError(`${where}: ${event} must be a function`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function checkPlugin(plugin, call, where) {
|
|
111
|
+
if (!isObject2(plugin)) {
|
|
112
|
+
throw new TypeError(`${call}: ${where} must be a plugin object, as { name, ...config } — was it called?`);
|
|
113
|
+
}
|
|
114
|
+
const { name } = plugin;
|
|
115
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
116
|
+
throw new TypeError(`${call}: ${where} has no name — a plugin is { name, ...config }`);
|
|
117
|
+
}
|
|
118
|
+
if (plugin.plugins !== undefined) {
|
|
119
|
+
throw new TypeError(`${call}: plugin "${name}" lists plugins — a plugin cannot bring others; list them in the project`);
|
|
120
|
+
}
|
|
121
|
+
checkHandlers(plugin, `${call}: plugin "${name}"`);
|
|
122
|
+
}
|
|
123
|
+
function defineMailPlugin(plugin) {
|
|
124
|
+
checkPlugin(plugin, "defineMailPlugin", "plugin");
|
|
125
|
+
return plugin;
|
|
126
|
+
}
|
|
127
|
+
function defineMailConfig(config = {}) {
|
|
128
|
+
if (!isObject2(config)) {
|
|
129
|
+
throw new TypeError("defineMailConfig: config must be an object, as { plugins, ...maizzleConfig }");
|
|
130
|
+
}
|
|
131
|
+
const { plugins = [], ...project } = config;
|
|
132
|
+
if (!Array.isArray(plugins)) {
|
|
133
|
+
throw new TypeError("defineMailConfig: plugins must be an array");
|
|
134
|
+
}
|
|
135
|
+
const names = new Set;
|
|
136
|
+
const layers = plugins.map((plugin, index) => {
|
|
137
|
+
checkPlugin(plugin, "defineMailConfig", `plugins[${index}]`);
|
|
138
|
+
const { name, ...rest } = plugin;
|
|
139
|
+
if (names.has(name)) {
|
|
140
|
+
throw new TypeError(`defineMailConfig: two plugins are named "${name}" — is one listed twice?`);
|
|
141
|
+
}
|
|
142
|
+
names.add(name);
|
|
143
|
+
return rest;
|
|
144
|
+
});
|
|
145
|
+
checkHandlers(project, "defineMailConfig");
|
|
146
|
+
return layer([baseConfig, ...layers, project]);
|
|
147
|
+
}
|
|
148
|
+
function productionConfig(config, overrides = {}) {
|
|
149
|
+
if (!isObject2(config)) {
|
|
150
|
+
throw new TypeError("productionConfig: config must be the project config, as productionConfig(config, overrides)");
|
|
151
|
+
}
|
|
152
|
+
if (config.plugins !== undefined) {
|
|
153
|
+
throw new TypeError("productionConfig: config lists plugins — pass what defineMailConfig answered, not its argument");
|
|
154
|
+
}
|
|
155
|
+
if (!isObject2(overrides)) {
|
|
156
|
+
throw new TypeError("productionConfig: overrides must be an object");
|
|
157
|
+
}
|
|
158
|
+
if (overrides.plugins !== undefined) {
|
|
159
|
+
throw new TypeError("productionConfig: overrides list plugins — list every plugin in the project config");
|
|
160
|
+
}
|
|
161
|
+
checkHandlers(overrides, "productionConfig");
|
|
162
|
+
const minify = isObject2(config.html?.minify) ? {} : { html: { minify: true } };
|
|
163
|
+
return layer([config, minify, overrides]);
|
|
164
|
+
}
|
|
165
|
+
export {
|
|
166
|
+
baseConfig,
|
|
167
|
+
defineMailConfig,
|
|
168
|
+
defineMailPlugin,
|
|
169
|
+
productionConfig
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
//# debugId=48E9630C34283E5C64756E2164756E21
|
|
173
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/layer.ts", "../src/index.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { MaizzleConfig } from '@maizzle/framework';\nimport { createDefu } from 'defu';\n\n/** The build events Maizzle reads from a config, in the order it fires them. */\nexport const EVENTS = [\n\t'beforeCreate',\n\t'beforeRender',\n\t'afterRender',\n\t'afterTransform',\n\t'afterBuild',\n] as const;\n\ntype Event = (typeof EVENTS)[number];\n// biome-ignore lint/suspicious/noExplicitAny: a handler of any of the five events.\ntype Handler = (params: any) => unknown;\n\n/**\n * Maizzle's own merge, copied from `@maizzle/framework`'s config loader:\n * objects merge key by key, an array replaces the array under it.\n */\nconst merge = createDefu((target, key, value) => {\n\tif (Array.isArray(target[key])) {\n\t\ttarget[key] = value;\n\t\treturn true;\n\t}\n});\n\n/**\n * The lists a plugin adds to rather than sets: two plugins that each bring\n * components, or each a Vite or a Vue plugin, keep both. Under Maizzle's rule\n * the last one would silently drop the others.\n */\nconst LISTS = [\n\t['components', 'source'],\n\t['vite', 'plugins'],\n\t['vue', 'plugins'],\n] as const;\n\ntype Layer = Record<string, unknown>;\n\nconst isObject = (value: unknown): value is Layer =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value);\n\n/** A `vue.plugins` may be a list, or a factory that answers one per render. */\nfunction joinVuePlugins(values: unknown[]): unknown {\n\tif (values.every(Array.isArray)) return values.flat();\n\treturn () =>\n\t\tvalues.flatMap((value) =>\n\t\t\ttypeof value === 'function' ? (value as () => unknown[])() : value,\n\t\t);\n}\n\n/** Takes each list out of the layers, and answers them joined, in layer order. */\nfunction takeLists(layers: Layer[]): [string, string, unknown][] {\n\tconst joined: [string, string, unknown][] = [];\n\tfor (const [group, key] of LISTS) {\n\t\tconst values: unknown[] = [];\n\t\tfor (const layer of layers) {\n\t\t\tconst section = layer[group];\n\t\t\t// Skipped as Maizzle's merge skips it: `null` sets nothing.\n\t\t\tif (!isObject(section) || section[key] == null) continue;\n\t\t\tvalues.push(section[key]);\n\t\t\tconst { [key]: _, ...rest } = section;\n\t\t\tlayer[group] = rest;\n\t\t}\n\t\tif (values.length === 0) continue;\n\t\tconst value =\n\t\t\tgroup === 'vue'\n\t\t\t\t? joinVuePlugins(values)\n\t\t\t\t: values.flatMap((entry) => (Array.isArray(entry) ? entry : [entry]));\n\t\tjoined.push([group, key, value]);\n\t}\n\treturn joined;\n}\n\n/**\n * One handler that runs every layer's, in order, the way Maizzle runs the\n * handlers it collects: for `beforeRender` a string replaces\n * `template.source`; for `afterRender` and `afterTransform` it replaces the\n * `html` the next one receives.\n */\nfunction chain(event: Event, handlers: Handler[]): Handler {\n\tif (handlers.length === 1) return handlers[0] as Handler;\n\tif (event === 'beforeRender') {\n\t\treturn async (params) => {\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tconst result = await handler(params);\n\t\t\t\tif (typeof result === 'string') params.template.source = result;\n\t\t\t}\n\t\t\treturn params.template.source;\n\t\t};\n\t}\n\tif (event === 'afterRender' || event === 'afterTransform') {\n\t\treturn async ({ config, template, html }) => {\n\t\t\tlet current: string = html;\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tconst result = await handler({ config, template, html: current });\n\t\t\t\tif (typeof result === 'string') current = result;\n\t\t\t}\n\t\t\treturn current;\n\t\t};\n\t}\n\treturn async (params) => {\n\t\tfor (const handler of handlers) await handler(params);\n\t};\n}\n\n/**\n * Layers configs, the first lowest: each key of a later one wins, objects\n * merge, arrays replace — except the {@link LISTS}, joined — and every build\n * event runs each layer's handler in order.\n */\nexport function layer(layers: readonly MaizzleConfig[]): MaizzleConfig {\n\tconst copies: Layer[] = layers.map((config) => ({ ...config }));\n\tconst handlers = new Map<Event, Handler[]>();\n\tfor (const copy of copies) {\n\t\tfor (const event of EVENTS) {\n\t\t\tconst handler = copy[event];\n\t\t\tif (handler === undefined) continue;\n\t\t\thandlers.set(event, [...(handlers.get(event) ?? []), handler as Handler]);\n\t\t\tdelete copy[event];\n\t\t}\n\t}\n\tconst lists = takeLists(copies);\n\tconst merged: Layer = merge({}, ...copies.reverse());\n\tfor (const [group, key, value] of lists) {\n\t\tmerged[group] = { ...(merged[group] as Layer | undefined), [key]: value };\n\t}\n\tfor (const [event, list] of handlers) merged[event] = chain(event, list);\n\treturn merged as MaizzleConfig;\n}\n",
|
|
6
|
+
"/**\n * `@nxgt/mail-config` — a shareable Maizzle config.\n *\n * ```ts\n * // maizzle.config.ts\n * import { defineMailConfig } from '@nxgt/mail-config';\n *\n * export default defineMailConfig({\n * plugins: [ui({ brand }), i18n({ locales: ['en', 'fr'] })],\n * // the project's own Maizzle config, which wins over every plugin\n * });\n * ```\n *\n * A plugin is a partial Maizzle config with a `name`. The layers are the base\n * config, then each plugin in order, then the project; every build event runs\n * each layer's handler in that order instead of the last one replacing the\n * others.\n */\n\nimport type { MaizzleConfig } from '@maizzle/framework';\nimport { EVENTS, layer } from './layer';\n\n/** A partial Maizzle config a package hands to {@link defineMailConfig}. */\nexport interface MailPlugin extends MaizzleConfig {\n\t/** Names the plugin in an error; two plugins of a project never share one. */\n\treadonly name: string;\n\t/** A plugin cannot bring others: the project lists every plugin. */\n\treadonly plugins?: never;\n}\n\n/** A project's Maizzle config, with the plugins layered under it. */\nexport interface MailConfig extends MaizzleConfig {\n\t/** Layered in order, each over the one before, all under the project. */\n\treadonly plugins?: readonly MailPlugin[];\n}\n\n/**\n * What a project gets without asking: a plain-text part next to each HTML\n * file. Everything else — `dist/`, `public/`, CSS inlined and purged — is\n * already Maizzle's default.\n */\nexport const baseConfig: Readonly<MaizzleConfig> = Object.freeze({\n\tplaintext: true,\n});\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value);\n\nfunction checkHandlers(config: Record<string, unknown>, where: string): void {\n\tfor (const event of EVENTS) {\n\t\tconst handler = config[event];\n\t\tif (handler !== undefined && typeof handler !== 'function') {\n\t\t\tthrow new TypeError(`${where}: ${event} must be a function`);\n\t\t}\n\t}\n}\n\n/**\n * Checks a plugin; `where` names it in an error — `defineMailConfig:\n * plugins[1]`, or `defineMailPlugin: plugin`.\n */\nfunction checkPlugin(\n\tplugin: unknown,\n\tcall: string,\n\twhere: string,\n): asserts plugin is MailPlugin {\n\tif (!isObject(plugin)) {\n\t\tthrow new TypeError(\n\t\t\t`${call}: ${where} must be a plugin object, as { name, ...config } — was it called?`,\n\t\t);\n\t}\n\tconst { name } = plugin;\n\tif (typeof name !== 'string' || name.trim() === '') {\n\t\tthrow new TypeError(\n\t\t\t`${call}: ${where} has no name — a plugin is { name, ...config }`,\n\t\t);\n\t}\n\tif (plugin.plugins !== undefined) {\n\t\tthrow new TypeError(\n\t\t\t`${call}: plugin \"${name}\" lists plugins — a plugin cannot bring others; list them in the project`,\n\t\t);\n\t}\n\tcheckHandlers(plugin, `${call}: plugin \"${name}\"`);\n}\n\n/**\n * Checks a plugin and answers it as it is: for a package that exports one, so\n * its mistakes surface where it is written, not in the project that uses it.\n * Typed `MailPlugin`, so a package's declarations can name what it exports.\n */\nexport function defineMailPlugin(plugin: MailPlugin): MailPlugin {\n\tcheckPlugin(plugin, 'defineMailPlugin', 'plugin');\n\treturn plugin;\n}\n\n/**\n * The project's Maizzle config: {@link baseConfig}, then each plugin in\n * order, then the rest of `config`. Objects merge and arrays replace, as in\n * Maizzle — except `components.source`, `vite.plugins` and `vue.plugins`,\n * which every layer adds to. Every build event runs each layer's handler, in\n * that order.\n */\nexport function defineMailConfig(config: MailConfig = {}): MaizzleConfig {\n\tif (!isObject(config)) {\n\t\tthrow new TypeError(\n\t\t\t'defineMailConfig: config must be an object, as { plugins, ...maizzleConfig }',\n\t\t);\n\t}\n\tconst { plugins = [], ...project } = config;\n\tif (!Array.isArray(plugins)) {\n\t\tthrow new TypeError('defineMailConfig: plugins must be an array');\n\t}\n\tconst names = new Set<string>();\n\tconst layers = plugins.map((plugin: unknown, index) => {\n\t\tcheckPlugin(plugin, 'defineMailConfig', `plugins[${index}]`);\n\t\tconst { name, ...rest } = plugin;\n\t\tif (names.has(name)) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`defineMailConfig: two plugins are named \"${name}\" — is one listed twice?`,\n\t\t\t);\n\t\t}\n\t\tnames.add(name);\n\t\treturn rest;\n\t});\n\tcheckHandlers(project, 'defineMailConfig');\n\treturn layer([baseConfig, ...layers, project]);\n}\n\n/**\n * The production build's config, for `maizzle.config.production.ts`: the\n * project's `config`, with the HTML minified — with the project's own\n * `html.minify` options when it set some — then `overrides`, merged as a\n * plugin is: its `components.source`, `vite.plugins` and `vue.plugins` are\n * added to the project's, its build events run after the project's.\n *\n * ```ts\n * // maizzle.config.production.ts — `maizzle build -c maizzle.config.production.ts`\n * import config from './maizzle.config';\n * import { productionConfig } from '@nxgt/mail-config';\n *\n * export default productionConfig(config, { output: { path: 'dist-production' } });\n * ```\n */\nexport function productionConfig(\n\tconfig: MaizzleConfig & { readonly plugins?: never },\n\toverrides: MaizzleConfig & { readonly plugins?: never } = {},\n): MaizzleConfig {\n\tif (!isObject(config)) {\n\t\tthrow new TypeError(\n\t\t\t'productionConfig: config must be the project config, as productionConfig(config, overrides)',\n\t\t);\n\t}\n\tif (config.plugins !== undefined) {\n\t\tthrow new TypeError(\n\t\t\t'productionConfig: config lists plugins — pass what defineMailConfig answered, not its argument',\n\t\t);\n\t}\n\tif (!isObject(overrides)) {\n\t\tthrow new TypeError('productionConfig: overrides must be an object');\n\t}\n\tif (overrides.plugins !== undefined) {\n\t\tthrow new TypeError(\n\t\t\t'productionConfig: overrides list plugins — list every plugin in the project config',\n\t\t);\n\t}\n\tcheckHandlers(overrides, 'productionConfig');\n\t// Minify options the project already set are kept: `true` would replace them.\n\tconst minify = isObject(config.html?.minify)\n\t\t? {}\n\t\t: { html: { minify: true } };\n\treturn layer([config, minify, overrides]);\n}\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "48E9630C34283E5C64756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|
package/dist/layer.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MaizzleConfig } from '@maizzle/framework';
|
|
2
|
+
/** The build events Maizzle reads from a config, in the order it fires them. */
|
|
3
|
+
export declare const EVENTS: readonly ["beforeCreate", "beforeRender", "afterRender", "afterTransform", "afterBuild"];
|
|
4
|
+
/**
|
|
5
|
+
* Layers configs, the first lowest: each key of a later one wins, objects
|
|
6
|
+
* merge, arrays replace — except the {@link LISTS}, joined — and every build
|
|
7
|
+
* event runs each layer's handler in order.
|
|
8
|
+
*/
|
|
9
|
+
export declare function layer(layers: readonly MaizzleConfig[]): MaizzleConfig;
|
|
10
|
+
//# sourceMappingURL=layer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layer.d.ts","sourceRoot":"","sources":["../src/layer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,gFAAgF;AAChF,eAAO,MAAM,MAAM,0FAMT,CAAC;AAiGX;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,aAAa,CAkBrE"}
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# @nxgt/mail-config — documentation
|
|
2
|
+
|
|
3
|
+
The [README](../README.md) shows that it works; these pages show how, one area
|
|
4
|
+
at a time, with an example for every rule. The words they use — project,
|
|
5
|
+
template, plugin, component — are defined once, in the
|
|
6
|
+
[vocabulary](https://github.com/softistx/nxgt-mail/blob/develop/docs/vocabulary.md).
|
|
7
|
+
|
|
8
|
+
| Page | Read it when |
|
|
9
|
+
| --- | --- |
|
|
10
|
+
| [The project config](guide/config.md) | You are writing `maizzle.config.ts` with `defineMailConfig`: the layers, how objects, arrays and the three joined lists merge, how each build event is chained, and every `TypeError` it throws |
|
|
11
|
+
| [Writing a plugin](guide/plugins.md) | You are shipping a partial Maizzle config in a package with `defineMailPlugin`: components under a prefix, hooks, global properties, options checked at wiring time, and why the order of `plugins` matters |
|
|
12
|
+
| [Production](guide/production.md) | You are adding `maizzle.config.production.ts` with `productionConfig`: minified HTML, its own output folder, a hook that only runs there |
|
|
13
|
+
| [Troubleshooting](troubleshooting.md) | You have an error message and want its cause and its fix |
|
|
14
|
+
| [Roadmap](roadmap.md) | You want to know what is coming, what shipped, and what is deliberately not planned |
|