@lupinum/nuxt-email 0.1.1 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/README.md +63 -18
- package/dist/build.d.mts +13 -0
- package/dist/build.mjs +218 -0
- package/dist/module.d.mts +1 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +54 -145
- package/dist/runtime/components/EHtml.d.ts +3 -1
- package/dist/runtime/components/EHtml.js +12 -2
- package/dist/runtime/components/ELink.js +1 -6
- package/dist/runtime/dev-preview/render.get.d.ts +26 -1
- package/dist/runtime/dev-preview/render.get.js +2 -2
- package/dist/runtime/render/define-email.d.ts +19 -10
- package/dist/runtime/render/define-email.js +21 -4
- package/dist/runtime/render/errors.d.ts +2 -2
- package/dist/runtime/render/errors.js +4 -4
- package/dist/runtime/render/index.d.ts +6 -0
- package/dist/runtime/render/index.js +3 -0
- package/dist/runtime/render/render-email-component.d.ts +3 -6
- package/dist/runtime/render/render-email-component.js +16 -16
- package/dist/runtime/render/types.d.ts +7 -0
- package/dist/runtime/tailwind/css-tree.d.ts +10 -0
- package/dist/runtime/tailwind/css-tree.js +11 -0
- package/dist/runtime/tailwind/engine/css/downlevel-for-email-clients.d.ts +8 -38
- package/dist/runtime/tailwind/engine/css/downlevel-for-email-clients.js +186 -72
- package/dist/runtime/tailwind/engine/css/extract-rules-per-class.d.ts +3 -1
- package/dist/runtime/tailwind/engine/css/extract-rules-per-class.js +9 -2
- package/dist/runtime/tailwind/engine/css/get-custom-properties.d.ts +1 -1
- package/dist/runtime/tailwind/engine/css/get-custom-properties.js +1 -1
- package/dist/runtime/tailwind/engine/css/is-part-inlinable.d.ts +1 -1
- package/dist/runtime/tailwind/engine/css/is-part-inlinable.js +1 -1
- package/dist/runtime/tailwind/engine/css/is-rule-inlinable.d.ts +1 -1
- package/dist/runtime/tailwind/engine/css/is-rule-inlinable.js +1 -1
- package/dist/runtime/tailwind/engine/css/make-inline-styles-for.d.ts +1 -1
- package/dist/runtime/tailwind/engine/css/make-inline-styles-for.js +1 -1
- package/dist/runtime/tailwind/engine/css/resolve-all-css-variables.d.ts +1 -1
- package/dist/runtime/tailwind/engine/css/resolve-all-css-variables.js +1 -1
- package/dist/runtime/tailwind/engine/css/resolve-calc-expressions.d.ts +1 -1
- package/dist/runtime/tailwind/engine/css/resolve-calc-expressions.js +1 -1
- package/dist/runtime/tailwind/engine/css/sanitize-declarations.d.ts +1 -1
- package/dist/runtime/tailwind/engine/css/sanitize-declarations.js +1 -1
- package/dist/runtime/tailwind/engine/css/sanitize-non-inlinable-rules.d.ts +1 -1
- package/dist/runtime/tailwind/engine/css/sanitize-non-inlinable-rules.js +1 -1
- package/dist/runtime/tailwind/engine/css/split-mixed-rule.d.ts +1 -1
- package/dist/runtime/tailwind/engine/css/split-mixed-rule.js +1 -1
- package/dist/runtime/tailwind/engine/css/strip-empty-tailwind-vars.d.ts +1 -1
- package/dist/runtime/tailwind/engine/css/strip-empty-tailwind-vars.js +1 -1
- package/dist/runtime/tailwind/engine/index.d.ts +6 -6
- package/dist/runtime/tailwind/engine/index.js +70 -7
- package/dist/runtime/tailwind/engine/setup-tailwind.d.ts +1 -1
- package/dist/runtime/tailwind/engine/setup-tailwind.js +1 -1
- package/dist/runtime/tailwind/post-render.js +7 -8
- package/dist/shared/nuxt-email.B5ux0eBv.mjs +133 -0
- package/dist/types.d.mts +1 -1
- package/package.json +18 -7
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
clone,
|
|
3
|
+
generate,
|
|
4
|
+
List,
|
|
5
|
+
walk
|
|
6
|
+
} from "../css-tree.js";
|
|
2
7
|
import { downlevelForEmailClients } from "./css/downlevel-for-email-clients.js";
|
|
3
8
|
import { extractRulesPerClass } from "./css/extract-rules-per-class.js";
|
|
4
9
|
import { getCustomProperties } from "./css/get-custom-properties.js";
|
|
@@ -7,6 +12,35 @@ import { sanitizeClassName } from "./compatibility/sanitize-class-name.js";
|
|
|
7
12
|
import { sanitizeNonInlinableRules } from "./css/sanitize-non-inlinable-rules.js";
|
|
8
13
|
import { sanitizeStyleSheet } from "./sanitize-stylesheet.js";
|
|
9
14
|
import { setupTailwind } from "./setup-tailwind.js";
|
|
15
|
+
function collectKeyframesDefinitions(styleSheet) {
|
|
16
|
+
const definitions = [];
|
|
17
|
+
styleSheet.children.forEach((node) => {
|
|
18
|
+
if (node.type === "Atrule" && (node.name === "keyframes" || node.name === "-webkit-keyframes") && node.prelude) {
|
|
19
|
+
definitions.push({ name: generate(node.prelude).trim(), node });
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
return definitions;
|
|
23
|
+
}
|
|
24
|
+
function collectReferencedKeyframes(rulesByClass, knownNames) {
|
|
25
|
+
const references = /* @__PURE__ */ new Map();
|
|
26
|
+
for (const [className, rules] of rulesByClass) {
|
|
27
|
+
const classReferences = /* @__PURE__ */ new Set();
|
|
28
|
+
for (const rule of rules) {
|
|
29
|
+
walk(rule, {
|
|
30
|
+
visit: "Declaration",
|
|
31
|
+
enter(declaration) {
|
|
32
|
+
if (declaration.property !== "animation" && declaration.property !== "animation-name") return;
|
|
33
|
+
walk(declaration.value, (node) => {
|
|
34
|
+
const name = node.type === "Identifier" ? node.name : node.type === "String" ? node.value : null;
|
|
35
|
+
if (name && knownNames.has(name)) classReferences.add(name);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (classReferences.size > 0) references.set(className, classReferences);
|
|
41
|
+
}
|
|
42
|
+
return references;
|
|
43
|
+
}
|
|
10
44
|
export async function createTailwindEngine(options = {}) {
|
|
11
45
|
const { config, theme, utility } = options;
|
|
12
46
|
const tailwindSetup = await setupTailwind({
|
|
@@ -17,17 +51,42 @@ export async function createTailwindEngine(options = {}) {
|
|
|
17
51
|
tailwindSetup.addUtilities(classNames);
|
|
18
52
|
const styleSheet = tailwindSetup.getStyleSheet();
|
|
19
53
|
sanitizeStyleSheet(styleSheet);
|
|
20
|
-
const {
|
|
54
|
+
const {
|
|
55
|
+
inlinable: inlinableRules,
|
|
56
|
+
nonInlinable: nonInlinableRules,
|
|
57
|
+
orderedNonInlinable
|
|
58
|
+
} = extractRulesPerClass(styleSheet, classNames);
|
|
21
59
|
const customProperties = getCustomProperties(styleSheet);
|
|
60
|
+
const keyframesDefinitions = collectKeyframesDefinitions(styleSheet);
|
|
61
|
+
const knownKeyframeNames = new Set(
|
|
62
|
+
keyframesDefinitions.map((definition) => definition.name)
|
|
63
|
+
);
|
|
64
|
+
const animationReferences = /* @__PURE__ */ new Map();
|
|
65
|
+
for (const rules of [inlinableRules, nonInlinableRules]) {
|
|
66
|
+
for (const [className, names] of collectReferencedKeyframes(
|
|
67
|
+
rules,
|
|
68
|
+
knownKeyframeNames
|
|
69
|
+
)) {
|
|
70
|
+
const existing = animationReferences.get(className) ?? /* @__PURE__ */ new Set();
|
|
71
|
+
for (const name of names) existing.add(name);
|
|
72
|
+
animationReferences.set(className, existing);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const referencedKeyframeNames = new Set(
|
|
76
|
+
Array.from(animationReferences.values()).flatMap((names) => [...names])
|
|
77
|
+
);
|
|
22
78
|
const nonInlineStyles = {
|
|
23
79
|
type: "StyleSheet",
|
|
24
|
-
children: new List().fromArray(
|
|
25
|
-
Array.from(nonInlinableRules.values()).flat()
|
|
26
|
-
)
|
|
80
|
+
children: new List().fromArray(orderedNonInlinable)
|
|
27
81
|
};
|
|
28
82
|
sanitizeNonInlinableRules(nonInlineStyles);
|
|
83
|
+
for (const definition of keyframesDefinitions) {
|
|
84
|
+
if (referencedKeyframeNames.has(definition.name)) {
|
|
85
|
+
nonInlineStyles.children.appendData(clone(definition.node));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
29
88
|
downlevelForEmailClients(nonInlineStyles);
|
|
30
|
-
const nonInlinableCss =
|
|
89
|
+
const nonInlinableCss = nonInlineStyles.children.isEmpty ? "" : generate(nonInlineStyles);
|
|
31
90
|
const inlinable = /* @__PURE__ */ new Map();
|
|
32
91
|
for (const [className, rules] of inlinableRules) {
|
|
33
92
|
inlinable.set(className, makeInlineStylesFor(rules, customProperties));
|
|
@@ -41,11 +100,15 @@ export async function createTailwindEngine(options = {}) {
|
|
|
41
100
|
residualClassMap.set(className, className);
|
|
42
101
|
}
|
|
43
102
|
}
|
|
103
|
+
const nonInlinableClassNames = new Set(nonInlinableRules.keys());
|
|
104
|
+
for (const className of classNames) {
|
|
105
|
+
if (animationReferences.has(className) && !nonInlinableRules.has(className)) nonInlinableClassNames.add(className);
|
|
106
|
+
}
|
|
44
107
|
return {
|
|
45
108
|
inlinable,
|
|
46
109
|
nonInlinableCss,
|
|
47
110
|
residualClassMap,
|
|
48
|
-
nonInlinableClassNames:
|
|
111
|
+
nonInlinableClassNames: [...nonInlinableClassNames]
|
|
49
112
|
};
|
|
50
113
|
};
|
|
51
114
|
return { computeStyles };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { generate, parse, walk } from "css-tree";
|
|
1
|
+
import { generate, parse, walk } from "./css-tree.js";
|
|
2
2
|
import { Parser } from "htmlparser2";
|
|
3
3
|
import { classTokens, mergeInlinableStyle, residualClasses } from "./inline-utils.js";
|
|
4
4
|
import { TailwindMissingHeadError } from "./errors.js";
|
|
@@ -63,12 +63,7 @@ function rewriteOpenTag(openTag, newClass, newStyle) {
|
|
|
63
63
|
}
|
|
64
64
|
return tag;
|
|
65
65
|
}
|
|
66
|
-
function inlinePlainElements(fragment,
|
|
67
|
-
const hits = collectElements(fragment);
|
|
68
|
-
for (const hit of hits) {
|
|
69
|
-
region.classNames.push(...classTokens(hit.classValue));
|
|
70
|
-
}
|
|
71
|
-
const computed = region.engine.computeStyles(region.classNames);
|
|
66
|
+
function inlinePlainElements(fragment, hits, computed) {
|
|
72
67
|
const edits = [];
|
|
73
68
|
for (const hit of hits) {
|
|
74
69
|
const tokens = classTokens(hit.classValue);
|
|
@@ -131,8 +126,12 @@ function processRegion(html, region) {
|
|
|
131
126
|
if (startIndex === -1 || endIndex === -1) return html;
|
|
132
127
|
const fragmentStart = startIndex + startComment.length;
|
|
133
128
|
const fragment = html.slice(fragmentStart, endIndex);
|
|
134
|
-
const
|
|
129
|
+
const hits = collectElements(fragment);
|
|
130
|
+
for (const hit of hits) {
|
|
131
|
+
region.classNames.push(...classTokens(hit.classValue));
|
|
132
|
+
}
|
|
135
133
|
const computed = region.engine.computeStyles(region.classNames);
|
|
134
|
+
const inlined = inlinePlainElements(fragment, hits, computed);
|
|
136
135
|
if (inlined.includes(region.placeholder)) {
|
|
137
136
|
const completed = inlined.replace(region.placeholder, computed.nonInlinableCss);
|
|
138
137
|
return html.slice(0, startIndex) + completed + html.slice(endIndex + endComment.length);
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { relative, isAbsolute, sep } from 'node:path';
|
|
2
|
+
import { resolveFiles } from '@nuxt/kit';
|
|
3
|
+
|
|
4
|
+
class DuplicateEmailTemplateError extends Error {
|
|
5
|
+
templateName;
|
|
6
|
+
sourcePaths;
|
|
7
|
+
constructor(templateName, sourcePaths) {
|
|
8
|
+
const sortedSourcePaths = [...sourcePaths].sort();
|
|
9
|
+
super(`Duplicate email template name "${templateName}" from: ${sortedSourcePaths.join(", ")}`);
|
|
10
|
+
this.name = "DuplicateEmailTemplateError";
|
|
11
|
+
this.templateName = templateName;
|
|
12
|
+
this.sourcePaths = sortedSourcePaths;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
class EmailTemplateDiscoveryError extends Error {
|
|
16
|
+
sourcePath;
|
|
17
|
+
constructor(sourcePath, cause) {
|
|
18
|
+
super(`Failed to discover email templates under ${sourcePath}`, { cause });
|
|
19
|
+
this.name = "EmailTemplateDiscoveryError";
|
|
20
|
+
this.sourcePath = sourcePath;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function compareCodePoints(left, right) {
|
|
25
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
26
|
+
}
|
|
27
|
+
function normalizeSeparators(value) {
|
|
28
|
+
return value.split(sep).join("/").replaceAll("\\", "/");
|
|
29
|
+
}
|
|
30
|
+
function templatesFromSourcePaths(emailDirectory, sourcePaths) {
|
|
31
|
+
const templates = sourcePaths.map((sourcePath) => {
|
|
32
|
+
const relativePath = normalizeSeparators(relative(emailDirectory, sourcePath));
|
|
33
|
+
if (relativePath.startsWith("../") || relativePath === ".." || isAbsolute(relativePath)) {
|
|
34
|
+
throw new EmailTemplateDiscoveryError(sourcePath, new TypeError("Template path is outside app/emails"));
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
name: relativePath.slice(0, -".vue".length),
|
|
38
|
+
sourcePath: normalizeSeparators(sourcePath)
|
|
39
|
+
};
|
|
40
|
+
}).sort((left, right) => {
|
|
41
|
+
return compareCodePoints(left.name, right.name) || compareCodePoints(left.sourcePath, right.sourcePath);
|
|
42
|
+
});
|
|
43
|
+
const pathsByName = /* @__PURE__ */ new Map();
|
|
44
|
+
for (const template of templates) {
|
|
45
|
+
const paths = pathsByName.get(template.name) ?? [];
|
|
46
|
+
paths.push(template.sourcePath);
|
|
47
|
+
pathsByName.set(template.name, paths);
|
|
48
|
+
}
|
|
49
|
+
const duplicate = [...pathsByName.entries()].filter(([, paths]) => paths.length > 1).sort(([left], [right]) => compareCodePoints(left, right))[0];
|
|
50
|
+
if (duplicate) {
|
|
51
|
+
throw new DuplicateEmailTemplateError(duplicate[0], duplicate[1]);
|
|
52
|
+
}
|
|
53
|
+
return templates;
|
|
54
|
+
}
|
|
55
|
+
async function discoverEmailTemplates(emailDirectory) {
|
|
56
|
+
let sourcePaths;
|
|
57
|
+
try {
|
|
58
|
+
sourcePaths = await resolveFiles(emailDirectory, "**/*.vue", {
|
|
59
|
+
followSymbolicLinks: false,
|
|
60
|
+
ignore: ["components/**"]
|
|
61
|
+
});
|
|
62
|
+
} catch (error) {
|
|
63
|
+
throw new EmailTemplateDiscoveryError(emailDirectory, error);
|
|
64
|
+
}
|
|
65
|
+
return templatesFromSourcePaths(emailDirectory, sourcePaths);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function importPath(path) {
|
|
69
|
+
return JSON.stringify(path.replaceAll("\\", "/"));
|
|
70
|
+
}
|
|
71
|
+
function generateEmailRegistry(templates, runtimePaths) {
|
|
72
|
+
const entries = templates.map((template) => {
|
|
73
|
+
const fixture = template.fixturePath ? `
|
|
74
|
+
fixture: () => import(${importPath(template.fixturePath)}),` : "";
|
|
75
|
+
return ` [${JSON.stringify(template.name)}]: {
|
|
76
|
+
component: () => import(${importPath(template.sourcePath)}),${fixture}
|
|
77
|
+
},`;
|
|
78
|
+
});
|
|
79
|
+
return `import { EmailRenderError } from ${importPath(runtimePaths.emailRenderError)}
|
|
80
|
+
import { renderEmailComponent } from ${importPath(runtimePaths.renderEmailComponent)}
|
|
81
|
+
import { UnknownEmailTemplateError } from ${importPath(runtimePaths.templateRegistryErrors)}
|
|
82
|
+
|
|
83
|
+
export const emailTemplates = Object.freeze({
|
|
84
|
+
${entries.join("\n")}
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
export async function renderEmail(name, props) {
|
|
88
|
+
const loader = typeof name === 'string' && Object.hasOwn(emailTemplates, name)
|
|
89
|
+
? emailTemplates[name]
|
|
90
|
+
: undefined
|
|
91
|
+
if (!loader) {
|
|
92
|
+
throw new UnknownEmailTemplateError(String(name), Object.keys(emailTemplates))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const templateModule = await loader.component()
|
|
97
|
+
return await renderEmailComponent(templateModule.default, props)
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
throw new EmailRenderError(name, error instanceof EmailRenderError ? error.cause : error)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
105
|
+
function generateEmailTypes(templates, typePaths) {
|
|
106
|
+
const entries = templates.map((template) => {
|
|
107
|
+
const fixture = template.fixturePath ? `
|
|
108
|
+
fixture: () => Promise<typeof import(${importPath(template.fixturePath)})>` : "";
|
|
109
|
+
return ` ${JSON.stringify(template.name)}: {
|
|
110
|
+
component: () => Promise<typeof import(${importPath(template.sourcePath)})>${fixture}
|
|
111
|
+
}`;
|
|
112
|
+
});
|
|
113
|
+
return `export const emailTemplates: Readonly<{
|
|
114
|
+
${entries.join("\n")}
|
|
115
|
+
}>
|
|
116
|
+
|
|
117
|
+
export type EmailTemplateName = keyof typeof emailTemplates
|
|
118
|
+
type _EmailProps<Component> = keyof import(${importPath(typePaths.renderedEmail)}).EmailComponentProps<Component> extends never
|
|
119
|
+
? Record<string, never>
|
|
120
|
+
: import(${importPath(typePaths.renderedEmail)}).EmailComponentProps<Component>
|
|
121
|
+
|
|
122
|
+
export type EmailTemplateProps = {
|
|
123
|
+
[Name in EmailTemplateName]: _EmailProps<Awaited<ReturnType<(typeof emailTemplates)[Name]['component']>>['default']>
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function renderEmail<Name extends EmailTemplateName>(
|
|
127
|
+
name: Name,
|
|
128
|
+
props: NoInfer<EmailTemplateProps[Name]>,
|
|
129
|
+
): Promise<import(${importPath(typePaths.renderedEmail)}).RenderedEmail>
|
|
130
|
+
`;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export { generateEmailTypes as a, discoverEmailTemplates as d, generateEmailRegistry as g };
|
package/dist/types.d.mts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lupinum/nuxt-email",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-beta.2",
|
|
4
4
|
"description": "Typed transactional email for Nuxt with email-safe Tailwind v4",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"email",
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"node": "^22.18.0 || ^24.11.0 || ^26.0.0"
|
|
28
28
|
},
|
|
29
29
|
"exports": {
|
|
30
|
+
"./build": {
|
|
31
|
+
"types": "./dist/build.d.mts",
|
|
32
|
+
"import": "./dist/build.mjs"
|
|
33
|
+
},
|
|
34
|
+
"./render": {
|
|
35
|
+
"types": "./dist/runtime/render/index.d.ts",
|
|
36
|
+
"import": "./dist/runtime/render/index.js"
|
|
37
|
+
},
|
|
30
38
|
".": {
|
|
31
39
|
"types": "./dist/module.d.mts",
|
|
32
40
|
"import": "./dist/module.mjs"
|
|
@@ -62,12 +70,15 @@
|
|
|
62
70
|
"@shikijs/langs": "4.3.1",
|
|
63
71
|
"@shikijs/themes": "4.3.1",
|
|
64
72
|
"css-tree": "3.2.1",
|
|
73
|
+
"esbuild": "0.28.1",
|
|
65
74
|
"h3": "1.15.11",
|
|
66
75
|
"html-to-text": "9.0.5",
|
|
67
76
|
"htmlparser2": "^10.1.0",
|
|
68
77
|
"marked": "15.0.12",
|
|
69
78
|
"tailwindcss": "4.1.18",
|
|
70
|
-
"
|
|
79
|
+
"typescript": "~5.9.3",
|
|
80
|
+
"unplugin-vue": "7.2.0",
|
|
81
|
+
"vue-tsc": "^3.3.3"
|
|
71
82
|
},
|
|
72
83
|
"devDependencies": {
|
|
73
84
|
"@nuxt/eslint-config": "^1.15.2",
|
|
@@ -89,10 +100,9 @@
|
|
|
89
100
|
"react-dom": "19.2.7",
|
|
90
101
|
"react-email": "6.9.0",
|
|
91
102
|
"tsx": "4.23.1",
|
|
92
|
-
"typescript": "~5.9.3",
|
|
93
103
|
"vitest": "^4.1.8",
|
|
94
|
-
"vue": "3.5.
|
|
95
|
-
"
|
|
104
|
+
"vue": "3.5.42",
|
|
105
|
+
"yaml": "2.9.0"
|
|
96
106
|
},
|
|
97
107
|
"scripts": {
|
|
98
108
|
"changelog": "changelogen --no-output",
|
|
@@ -105,7 +115,8 @@
|
|
|
105
115
|
"oracle:check": "node --import tsx test/conformance/tooling/generate-react-oracle.ts --check",
|
|
106
116
|
"oracle:write": "node --import tsx test/conformance/tooling/generate-react-oracle.ts --write",
|
|
107
117
|
"performance:measure": "node --expose-gc --import tsx test/performance/measure.ts",
|
|
108
|
-
"docs:build": "nuxt-module-build prepare && pnpm prepack && pnpm --dir docs build",
|
|
118
|
+
"docs:build": "pnpm docs:theme && nuxt-module-build prepare && pnpm prepack && pnpm --dir docs build",
|
|
119
|
+
"docs:theme": "node scripts/check-docs-theme.mjs",
|
|
109
120
|
"proofs:generate": "node --import tsx scripts/proofs/generate.ts",
|
|
110
121
|
"proofs:send": "node --import tsx scripts/proofs/send.ts",
|
|
111
122
|
"repo:check": "node scripts/check-repository-policy.mjs",
|
|
@@ -113,7 +124,7 @@
|
|
|
113
124
|
"release:prepare": "changelogen --bump --clean --hideAuthorEmail",
|
|
114
125
|
"release:artifact": "pnpm release:verify --output .release/lupinum-nuxt-email.tgz && node scripts/write-release-manifest.mjs",
|
|
115
126
|
"lint": "eslint .",
|
|
116
|
-
"test": "vitest run --exclude test/preview.test.ts && pnpm test:preview",
|
|
127
|
+
"test": "pnpm prepack && vitest run --exclude test/preview.test.ts && pnpm test:preview",
|
|
117
128
|
"test:preview": "vitest run test/preview.test.ts",
|
|
118
129
|
"test:conformance": "vitest run test/conformance",
|
|
119
130
|
"test:watch": "vitest watch",
|