@samva/vite 0.1.2 → 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/AGENTS.md +70 -1
- package/README.md +92 -44
- package/dist/build.d.ts +47 -28
- package/dist/build.js +166 -67
- package/dist/editor/assets/index-Cg4x6ewh.css +2 -0
- package/dist/editor/assets/index-Cot9JDdw.js +30 -0
- package/dist/editor/index.html +2 -2
- package/dist/email.d.ts +60 -0
- package/dist/email.js +126 -0
- package/dist/emit.d.ts +13 -30
- package/dist/emit.js +29 -123
- package/dist/index.d.ts +1 -4
- package/dist/index.js +480 -305
- package/dist/project.d.ts +116 -0
- package/dist/project.js +294 -0
- package/dist/theme-CBF6Czjm.js +50 -0
- package/package.json +28 -20
- package/dist/editor/assets/authoring-editor-ClA5aqFP-CO-FhsWG.js +0 -145
- package/dist/editor/assets/index-CI_j2PFe.css +0 -2
- package/dist/editor/assets/index-DbdWiln3.js +0 -84
- package/dist/theme-CfJe8s3k.js +0 -138
package/dist/editor/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
6
|
<title>Samva editor</title>
|
|
7
|
-
<script type="module" crossorigin src="./assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
7
|
+
<script type="module" crossorigin src="./assets/index-Cot9JDdw.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="./assets/index-Cg4x6ewh.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
package/dist/email.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { CompiledEmailProject, TransformOptions, compileEmailProject } from "@samva/markup/compiler";
|
|
2
|
+
import { TemplateDefinition } from "@samva/markup/template";
|
|
3
|
+
import { SerializeEmailOptions } from "@samva/markup/email/html";
|
|
4
|
+
import { renderEmail } from "@samva/markup/email/render";
|
|
5
|
+
//#region src/email.d.ts
|
|
6
|
+
interface EmailProjectSource {
|
|
7
|
+
/** Project-relative path to text content, or to bytes for an imported file. */
|
|
8
|
+
readonly [path: string]: string | Uint8Array;
|
|
9
|
+
}
|
|
10
|
+
interface RenderedEmailProject extends ReturnType<typeof renderEmail> {
|
|
11
|
+
readonly compiled: CompiledEmailProject;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* One compiled entry, evaluated. `template` is `undefined` when the entry has no
|
|
15
|
+
* default export, which is how a helper module is told apart from a template
|
|
16
|
+
* without inspecting authored source.
|
|
17
|
+
*/
|
|
18
|
+
interface LoadedEmailEntry {
|
|
19
|
+
readonly template: TemplateDefinition<unknown> | undefined;
|
|
20
|
+
readonly renderEmail: typeof renderEmail;
|
|
21
|
+
readonly compiled: CompiledEmailProject;
|
|
22
|
+
}
|
|
23
|
+
/** A long-lived evaluator. Every render shares its module graph, as a dev server does. */
|
|
24
|
+
interface EmailRenderer {
|
|
25
|
+
/**
|
|
26
|
+
* Compile one entry and evaluate the compiler's generated wrapper. Callers
|
|
27
|
+
* that render several inputs against one template load once and render many
|
|
28
|
+
* times; nothing here renders on its own.
|
|
29
|
+
*
|
|
30
|
+
* `namespace` names the id space the entry's modules occupy. Reusing one
|
|
31
|
+
* keeps a watch session's ids stable across reloads, while a fresh one
|
|
32
|
+
* isolates an unrelated project. Omitting it takes a new namespace each time.
|
|
33
|
+
* Every load re-evaluates the namespace's own modules, so the wrapper binds
|
|
34
|
+
* the sheets its imports registered; `invalidate` reaches the modules shared
|
|
35
|
+
* between namespaces.
|
|
36
|
+
*/
|
|
37
|
+
readonly load: (source: EmailProjectSource, entryPoint: string, namespace?: string) => Promise<LoadedEmailEntry>;
|
|
38
|
+
/**
|
|
39
|
+
* Compile, evaluate and render one input in a single call. `serialize` reaches
|
|
40
|
+
* the serializer, so a caller that renders for an editor asks for
|
|
41
|
+
* `instancePaths` here; a render that will be delivered passes nothing.
|
|
42
|
+
*/
|
|
43
|
+
readonly render: (source: EmailProjectSource, entryPoint: string, input: unknown, serialize?: SerializeEmailOptions) => Promise<RenderedEmailProject>;
|
|
44
|
+
/** Drop every evaluated module so the next load re-reads changed source. */
|
|
45
|
+
readonly invalidate: () => void;
|
|
46
|
+
readonly close: () => Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* One Vite server, many renders. Each project gets its own id namespace so their
|
|
50
|
+
* modules coexist in one graph — which also means they share one instance of
|
|
51
|
+
* `@samva/markup`, exactly as a published consumer's install does. That shared
|
|
52
|
+
* instance holds the stylesheet registry, which is why the compiler's generated
|
|
53
|
+
* reset module runs first in every project's graph.
|
|
54
|
+
*/
|
|
55
|
+
declare const createEmailRenderer: (options: TransformOptions, ssrExternal?: readonly string[]) => Promise<EmailRenderer>;
|
|
56
|
+
/** Compile and render one project, then release the evaluator. */
|
|
57
|
+
declare const renderEmailProject: (source: EmailProjectSource, entryPoint: string, options: TransformOptions, input: unknown) => Promise<RenderedEmailProject>;
|
|
58
|
+
//#endregion
|
|
59
|
+
export { type CompiledEmailProject, EmailProjectSource, EmailRenderer, LoadedEmailEntry, RenderedEmailProject, compileEmailProject, createEmailRenderer, renderEmailProject };
|
|
60
|
+
//# sourceMappingURL=email.d.ts.map
|
package/dist/email.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { dirname } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { compileEmailProject } from "@samva/markup/compiler";
|
|
4
|
+
//#region src/email.ts
|
|
5
|
+
const VIRTUAL = "/@samva-email/";
|
|
6
|
+
/** This package's own directory: `src` in the repository, `dist` when published. */
|
|
7
|
+
const RESOLUTION_ROOT = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const SCRIPT = /\.[cm]?[jt]sx?$/;
|
|
9
|
+
const qualify = (path) => SCRIPT.test(path) ? path : `${path}.js`;
|
|
10
|
+
const unqualify = (id) => id.endsWith(".js") && !SCRIPT.test(id.slice(0, -3)) ? id.slice(0, -3) : id;
|
|
11
|
+
const resolveWithin = (graph, id, importer) => {
|
|
12
|
+
const own = id.startsWith(graph.prefix) ? unqualify(id.slice(graph.prefix.length)) : id;
|
|
13
|
+
if (graph.files[own] !== void 0) return `${graph.prefix}${qualify(own)}`;
|
|
14
|
+
if (!own.startsWith(".")) return void 0;
|
|
15
|
+
const segments = [...(importer?.startsWith(graph.prefix) === true ? unqualify(importer.slice(graph.prefix.length)) : "").split("/").slice(0, -1), ...own.split("/")];
|
|
16
|
+
const parts = [];
|
|
17
|
+
for (const segment of segments) {
|
|
18
|
+
if (segment === "." || segment === "") continue;
|
|
19
|
+
if (segment === "..") parts.pop();
|
|
20
|
+
else parts.push(segment);
|
|
21
|
+
}
|
|
22
|
+
const path = parts.join("/");
|
|
23
|
+
for (const candidate of [
|
|
24
|
+
path,
|
|
25
|
+
`${path}.ts`,
|
|
26
|
+
`${path}.tsx`,
|
|
27
|
+
`${path}.js`,
|
|
28
|
+
`${path}/index.ts`
|
|
29
|
+
]) if (graph.files[candidate] !== void 0) return `${graph.prefix}${qualify(candidate)}`;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* One Vite server, many renders. Each project gets its own id namespace so their
|
|
33
|
+
* modules coexist in one graph — which also means they share one instance of
|
|
34
|
+
* `@samva/markup`, exactly as a published consumer's install does. That shared
|
|
35
|
+
* instance holds the stylesheet registry, which is why the compiler's generated
|
|
36
|
+
* reset module runs first in every project's graph.
|
|
37
|
+
*/
|
|
38
|
+
const createEmailRenderer = async (options, ssrExternal = []) => {
|
|
39
|
+
const vite = await import("vite").catch(() => void 0);
|
|
40
|
+
if (vite === void 0) throw new Error("`vite` is required to render an email project locally.");
|
|
41
|
+
const graphs = /* @__PURE__ */ new Map();
|
|
42
|
+
let anonymous = 0;
|
|
43
|
+
let evaluating = Promise.resolve();
|
|
44
|
+
const evaluate = (operation) => {
|
|
45
|
+
const running = evaluating.then(operation, operation);
|
|
46
|
+
evaluating = running.catch(() => void 0);
|
|
47
|
+
return running;
|
|
48
|
+
};
|
|
49
|
+
const graphFor = (id) => id === void 0 ? void 0 : [...graphs.values()].find((graph) => id.startsWith(graph.prefix));
|
|
50
|
+
const server = await vite.createServer({
|
|
51
|
+
root: RESOLUTION_ROOT,
|
|
52
|
+
configFile: false,
|
|
53
|
+
logLevel: "silent",
|
|
54
|
+
server: {
|
|
55
|
+
middlewareMode: true,
|
|
56
|
+
hmr: false
|
|
57
|
+
},
|
|
58
|
+
optimizeDeps: {
|
|
59
|
+
noDiscovery: true,
|
|
60
|
+
include: []
|
|
61
|
+
},
|
|
62
|
+
oxc: { jsx: {
|
|
63
|
+
runtime: "automatic",
|
|
64
|
+
importSource: "@samva/markup/email"
|
|
65
|
+
} },
|
|
66
|
+
...ssrExternal.length === 0 ? {} : { ssr: { external: [...ssrExternal] } },
|
|
67
|
+
plugins: [{
|
|
68
|
+
name: "samva:email-project",
|
|
69
|
+
enforce: "pre",
|
|
70
|
+
resolveId: (id, importer) => {
|
|
71
|
+
const graph = graphFor(id) ?? graphFor(importer);
|
|
72
|
+
return graph === void 0 ? void 0 : resolveWithin(graph, id, importer);
|
|
73
|
+
},
|
|
74
|
+
load: (id) => {
|
|
75
|
+
const graph = graphFor(id);
|
|
76
|
+
return graph === void 0 ? void 0 : graph.files[unqualify(id.slice(graph.prefix.length))];
|
|
77
|
+
}
|
|
78
|
+
}]
|
|
79
|
+
});
|
|
80
|
+
const load = async (source, entryPoint, namespace) => {
|
|
81
|
+
const key = namespace ?? `#${anonymous += 1}`;
|
|
82
|
+
const graph = graphs.get(key) ?? {
|
|
83
|
+
files: {},
|
|
84
|
+
prefix: `${VIRTUAL}${graphs.size}/`
|
|
85
|
+
};
|
|
86
|
+
graphs.set(key, graph);
|
|
87
|
+
const compiled = await compileEmailProject(source, entryPoint, options);
|
|
88
|
+
graph.files = compiled.files;
|
|
89
|
+
const module = await evaluate(async () => {
|
|
90
|
+
const ssr = server.environments.ssr;
|
|
91
|
+
for (const node of ssr.moduleGraph.idToModuleMap.values()) if (node.id?.startsWith(graph.prefix) === true) ssr.moduleGraph.invalidateModule(node);
|
|
92
|
+
return await server.ssrLoadModule(`${graph.prefix}${qualify(compiled.entryPoint)}`);
|
|
93
|
+
});
|
|
94
|
+
return {
|
|
95
|
+
template: module.template,
|
|
96
|
+
renderEmail: module.renderEmail,
|
|
97
|
+
compiled
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
load,
|
|
102
|
+
render: async (source, entryPoint, input, serialize) => {
|
|
103
|
+
const entry = await load(source, entryPoint);
|
|
104
|
+
if (entry.template === void 0) throw new TypeError(`${entryPoint} does not default-export a template definition.`);
|
|
105
|
+
return {
|
|
106
|
+
...entry.renderEmail(entry.template, input, serialize),
|
|
107
|
+
compiled: entry.compiled
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
invalidate: () => server.moduleGraph.invalidateAll(),
|
|
111
|
+
close: () => server.close()
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
/** Compile and render one project, then release the evaluator. */
|
|
115
|
+
const renderEmailProject = async (source, entryPoint, options, input) => {
|
|
116
|
+
const renderer = await createEmailRenderer(options);
|
|
117
|
+
try {
|
|
118
|
+
return await renderer.render(source, entryPoint, input);
|
|
119
|
+
} finally {
|
|
120
|
+
await renderer.close();
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
//#endregion
|
|
124
|
+
export { compileEmailProject, createEmailRenderer, renderEmailProject };
|
|
125
|
+
|
|
126
|
+
//# sourceMappingURL=email.js.map
|
package/dist/emit.d.ts
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
import { COMPILER_VERSION
|
|
1
|
+
import { COMPILER_VERSION } from "@samva/markup/compile";
|
|
2
2
|
import { Diagnostic } from "@samva/markup/diagnostics";
|
|
3
3
|
import { TemplateVariable } from "@samva/markup/render-template";
|
|
4
4
|
//#region src/emit.d.ts
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
declare const COMPILE_BASES: readonly ["outlook-safe", "modern"];
|
|
8
|
-
/** One email base's compiled artifact, or its compile diagnostics if it failed. */
|
|
9
|
-
interface EmailBaseArtifact {
|
|
10
|
-
readonly base: CompileBase;
|
|
11
|
-
readonly ok: boolean;
|
|
12
|
-
readonly html?: string | undefined;
|
|
13
|
-
readonly text?: string | undefined;
|
|
14
|
-
readonly warnings?: readonly Diagnostic[] | undefined;
|
|
15
|
-
readonly diagnostics?: readonly Diagnostic[] | undefined;
|
|
16
|
-
}
|
|
5
|
+
/** Structured channel preview emission, independent of the email execution runtime. */
|
|
6
|
+
type PreviewChannel = "unknown" | "sms" | "whatsapp";
|
|
17
7
|
type WhatsAppButtonPreview = {
|
|
18
8
|
readonly type: "QUICK_REPLY";
|
|
19
9
|
readonly text: string;
|
|
@@ -36,19 +26,13 @@ interface AuthoringValidationSummary {
|
|
|
36
26
|
readonly repairableDiagnostics: number;
|
|
37
27
|
readonly placeholders: readonly string[];
|
|
38
28
|
readonly darkClassCount: number;
|
|
39
|
-
readonly emailBases?: readonly {
|
|
40
|
-
readonly base: CompileBase;
|
|
41
|
-
readonly ok: boolean;
|
|
42
|
-
readonly htmlBytes?: number | undefined;
|
|
43
|
-
readonly warnings: number;
|
|
44
|
-
readonly diagnostics: number;
|
|
45
|
-
readonly repairableDiagnostics: number;
|
|
46
|
-
}[] | undefined;
|
|
47
29
|
}
|
|
48
30
|
/** The compiled payload for one template, discriminated by channel. */
|
|
49
31
|
type CompiledPreview = {
|
|
50
|
-
readonly channel: "
|
|
51
|
-
readonly
|
|
32
|
+
readonly channel: "unknown";
|
|
33
|
+
readonly ok: false;
|
|
34
|
+
readonly diagnostics: readonly Diagnostic[];
|
|
35
|
+
readonly warnings?: readonly Diagnostic[];
|
|
52
36
|
} | {
|
|
53
37
|
readonly channel: "sms";
|
|
54
38
|
readonly ok: boolean;
|
|
@@ -103,14 +87,13 @@ interface ModulePreview {
|
|
|
103
87
|
* changes the implementation shape of the default export. Direct callers of
|
|
104
88
|
* `@samva/vite/emit` must pass that file-backed name as the first argument.
|
|
105
89
|
*/
|
|
106
|
-
declare const emitModulePreview: (name: string, moduleExports: Record<string, unknown
|
|
90
|
+
declare const emitModulePreview: (name: string, moduleExports: Record<string, unknown>) => ModulePreview;
|
|
107
91
|
/**
|
|
108
|
-
* Compiles a raw
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* shape so the client renders `.samva` and `.tsx` templates identically.
|
|
92
|
+
* Compiles a raw SML source string directly (no TSX). Used by tests and any
|
|
93
|
+
* caller that already holds emitted SML. Wraps the single source in the same
|
|
94
|
+
* preview shape so the client renders compiled SML identically to TSX emission.
|
|
112
95
|
*/
|
|
113
|
-
declare const compileSourcePreview: (name: string, source: string
|
|
96
|
+
declare const compileSourcePreview: (name: string, source: string) => EmittedTemplatePreview;
|
|
114
97
|
//#endregion
|
|
115
|
-
export { AuthoringValidationSummary, COMPILER_VERSION,
|
|
98
|
+
export { AuthoringValidationSummary, COMPILER_VERSION, CompiledPreview, EmittedTemplatePreview, ModulePreview, PreviewChannel, WhatsAppButtonPreview, compileSourcePreview, emitModulePreview };
|
|
116
99
|
//# sourceMappingURL=emit.d.ts.map
|
package/dist/emit.js
CHANGED
|
@@ -2,37 +2,10 @@ import { Result } from "effect";
|
|
|
2
2
|
import { COMPILER_VERSION, compileSource } from "@samva/markup/compile";
|
|
3
3
|
import { emitModule } from "@samva/markup/emit";
|
|
4
4
|
//#region src/emit.ts
|
|
5
|
-
/** Both email compile bases the preview surfaces and a build materializes. */
|
|
6
|
-
const COMPILE_BASES = ["outlook-safe", "modern"];
|
|
7
5
|
const countRepairable = (diagnostics) => diagnostics.filter((diagnostic) => diagnostic.repair !== void 0).length;
|
|
8
6
|
const uniquePlaceholders = (source) => source === void 0 ? [] : [...new Set([...source.matchAll(/{{\s*([A-Za-z_][\w.-]*)\s*}}/g)].map((match) => match[1] ?? ""))].filter(Boolean).sort();
|
|
9
7
|
const darkClassCount = (source) => source === void 0 ? 0 : (source.match(/\bdark:/g) ?? []).length;
|
|
10
8
|
const validationSummary = (source, emitDiagnostics, compiled) => {
|
|
11
|
-
if (compiled.channel === "email") {
|
|
12
|
-
const baseSummaries = compiled.bases.map((artifact) => {
|
|
13
|
-
const warnings = artifact.warnings ?? [];
|
|
14
|
-
const diagnostics = artifact.diagnostics ?? [];
|
|
15
|
-
return {
|
|
16
|
-
base: artifact.base,
|
|
17
|
-
ok: artifact.ok,
|
|
18
|
-
htmlBytes: artifact.html === void 0 ? void 0 : new TextEncoder().encode(artifact.html).length,
|
|
19
|
-
warnings: warnings.length,
|
|
20
|
-
diagnostics: diagnostics.length,
|
|
21
|
-
repairableDiagnostics: countRepairable(diagnostics)
|
|
22
|
-
};
|
|
23
|
-
});
|
|
24
|
-
const warnings = baseSummaries.reduce((sum, base) => sum + base.warnings, 0);
|
|
25
|
-
const diagnostics = emitDiagnostics.length + baseSummaries.reduce((sum, base) => sum + base.diagnostics, 0);
|
|
26
|
-
return {
|
|
27
|
-
ok: baseSummaries.length > 0 && baseSummaries.every((base) => base.ok) && emitDiagnostics.length === 0,
|
|
28
|
-
diagnostics,
|
|
29
|
-
warnings,
|
|
30
|
-
repairableDiagnostics: countRepairable(emitDiagnostics) + baseSummaries.reduce((sum, base) => sum + base.repairableDiagnostics, 0),
|
|
31
|
-
placeholders: uniquePlaceholders(source),
|
|
32
|
-
darkClassCount: darkClassCount(source),
|
|
33
|
-
emailBases: baseSummaries
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
9
|
const warnings = compiled.warnings ?? [];
|
|
37
10
|
const diagnostics = compiled.diagnostics ?? [];
|
|
38
11
|
return {
|
|
@@ -44,52 +17,16 @@ const validationSummary = (source, emitDiagnostics, compiled) => {
|
|
|
44
17
|
darkClassCount: darkClassCount(source)
|
|
45
18
|
};
|
|
46
19
|
};
|
|
47
|
-
const emailBaseArtifact = (source, base, options) => {
|
|
48
|
-
const result = compileSource(source, {
|
|
49
|
-
...options,
|
|
50
|
-
base
|
|
51
|
-
});
|
|
52
|
-
if (Result.isFailure(result)) return {
|
|
53
|
-
base,
|
|
54
|
-
ok: false,
|
|
55
|
-
diagnostics: result.failure.diagnostics
|
|
56
|
-
};
|
|
57
|
-
if (result.success.channel !== "email") return {
|
|
58
|
-
base,
|
|
59
|
-
ok: false,
|
|
60
|
-
diagnostics: [{
|
|
61
|
-
code: "channel-changed",
|
|
62
|
-
message: "template no longer compiles to email",
|
|
63
|
-
span: {
|
|
64
|
-
start: 0,
|
|
65
|
-
end: 0
|
|
66
|
-
}
|
|
67
|
-
}]
|
|
68
|
-
};
|
|
69
|
-
return {
|
|
70
|
-
base,
|
|
71
|
-
ok: true,
|
|
72
|
-
html: result.success.html,
|
|
73
|
-
text: result.success.text,
|
|
74
|
-
warnings: result.success.warnings
|
|
75
|
-
};
|
|
76
|
-
};
|
|
77
20
|
/** Compile one source into its channel-polymorphic preview. */
|
|
78
|
-
const compiledPreview = (source
|
|
79
|
-
const probe = compileSource(source
|
|
80
|
-
...options,
|
|
81
|
-
base: "outlook-safe"
|
|
82
|
-
});
|
|
21
|
+
const compiledPreview = (source) => {
|
|
22
|
+
const probe = compileSource(source);
|
|
83
23
|
if (Result.isFailure(probe)) return {
|
|
84
|
-
channel: "
|
|
24
|
+
channel: "unknown",
|
|
85
25
|
compileOk: false,
|
|
86
26
|
compiled: {
|
|
87
|
-
channel: "
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
ok: false,
|
|
91
|
-
diagnostics: probe.failure.diagnostics
|
|
92
|
-
}]
|
|
27
|
+
channel: "unknown",
|
|
28
|
+
ok: false,
|
|
29
|
+
diagnostics: probe.failure.diagnostics
|
|
93
30
|
}
|
|
94
31
|
};
|
|
95
32
|
const compiled = probe.success;
|
|
@@ -106,7 +43,7 @@ const compiledPreview = (source, options) => {
|
|
|
106
43
|
warnings: compiled.warnings
|
|
107
44
|
}
|
|
108
45
|
};
|
|
109
|
-
|
|
46
|
+
return {
|
|
110
47
|
channel: "whatsapp",
|
|
111
48
|
compileOk: true,
|
|
112
49
|
compiled: {
|
|
@@ -120,40 +57,27 @@ const compiledPreview = (source, options) => {
|
|
|
120
57
|
warnings: compiled.warnings
|
|
121
58
|
}
|
|
122
59
|
};
|
|
123
|
-
const bases = [{
|
|
124
|
-
base: "outlook-safe",
|
|
125
|
-
ok: true,
|
|
126
|
-
html: compiled.html,
|
|
127
|
-
text: compiled.text,
|
|
128
|
-
warnings: compiled.warnings
|
|
129
|
-
}, emailBaseArtifact(source, "modern", options)];
|
|
130
|
-
return {
|
|
131
|
-
channel: "email",
|
|
132
|
-
compileOk: bases.every((artifact) => artifact.ok),
|
|
133
|
-
compiled: {
|
|
134
|
-
channel: "email",
|
|
135
|
-
bases
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
60
|
};
|
|
139
|
-
const previewTemplate = (emitted
|
|
61
|
+
const previewTemplate = (emitted) => {
|
|
140
62
|
if (emitted.source === void 0) return {
|
|
141
63
|
name: emitted.name,
|
|
142
64
|
ok: false,
|
|
143
|
-
channel: "
|
|
65
|
+
channel: "unknown",
|
|
144
66
|
source: void 0,
|
|
145
67
|
variables: emitted.variables,
|
|
146
68
|
diagnostics: emitted.diagnostics,
|
|
147
69
|
compiled: {
|
|
148
|
-
channel: "
|
|
149
|
-
|
|
70
|
+
channel: "unknown",
|
|
71
|
+
ok: false,
|
|
72
|
+
diagnostics: []
|
|
150
73
|
},
|
|
151
74
|
validation: validationSummary(void 0, emitted.diagnostics, {
|
|
152
|
-
channel: "
|
|
153
|
-
|
|
75
|
+
channel: "unknown",
|
|
76
|
+
ok: false,
|
|
77
|
+
diagnostics: []
|
|
154
78
|
})
|
|
155
79
|
};
|
|
156
|
-
const { channel, compileOk, compiled } = compiledPreview(emitted.source
|
|
80
|
+
const { channel, compileOk, compiled } = compiledPreview(emitted.source);
|
|
157
81
|
return {
|
|
158
82
|
name: emitted.name,
|
|
159
83
|
ok: emitted.ok && compileOk,
|
|
@@ -175,35 +99,18 @@ const previewTemplate = (emitted, options) => {
|
|
|
175
99
|
* changes the implementation shape of the default export. Direct callers of
|
|
176
100
|
* `@samva/vite/emit` must pass that file-backed name as the first argument.
|
|
177
101
|
*/
|
|
178
|
-
const emitModulePreview = (name, moduleExports
|
|
179
|
-
|
|
180
|
-
ok: false,
|
|
181
|
-
compilerVersion: COMPILER_VERSION,
|
|
182
|
-
templates: [],
|
|
183
|
-
diagnostics: [{
|
|
184
|
-
code: "missing-default-export",
|
|
185
|
-
message: "TSX template files must default-export exactly one template; named exports are ignored.",
|
|
186
|
-
span: {
|
|
187
|
-
start: 0,
|
|
188
|
-
end: 0
|
|
189
|
-
}
|
|
190
|
-
}]
|
|
191
|
-
};
|
|
192
|
-
const emitted = emitModule({ [name]: moduleExports.default });
|
|
102
|
+
const emitModulePreview = (name, moduleExports) => {
|
|
103
|
+
const emitted = emitModule(moduleExports);
|
|
193
104
|
if (emitted.templates.length === 0) return {
|
|
194
105
|
ok: false,
|
|
195
106
|
compilerVersion: COMPILER_VERSION,
|
|
196
107
|
templates: [],
|
|
197
|
-
diagnostics:
|
|
198
|
-
code: "invalid-default-export",
|
|
199
|
-
message: "The default export is not a Samva template returning <Email>, <Sms>, or <WhatsApp>.",
|
|
200
|
-
span: {
|
|
201
|
-
start: 0,
|
|
202
|
-
end: 0
|
|
203
|
-
}
|
|
204
|
-
}]
|
|
108
|
+
diagnostics: emitted.diagnostics
|
|
205
109
|
};
|
|
206
|
-
const templates = emitted.templates.map((template) => previewTemplate(
|
|
110
|
+
const templates = emitted.templates.map((template) => previewTemplate({
|
|
111
|
+
...template,
|
|
112
|
+
name
|
|
113
|
+
}));
|
|
207
114
|
return {
|
|
208
115
|
ok: emitted.ok && templates.every((template) => template.ok),
|
|
209
116
|
compilerVersion: COMPILER_VERSION,
|
|
@@ -212,13 +119,12 @@ const emitModulePreview = (name, moduleExports, options) => {
|
|
|
212
119
|
};
|
|
213
120
|
};
|
|
214
121
|
/**
|
|
215
|
-
* Compiles a raw
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
* shape so the client renders `.samva` and `.tsx` templates identically.
|
|
122
|
+
* Compiles a raw SML source string directly (no TSX). Used by tests and any
|
|
123
|
+
* caller that already holds emitted SML. Wraps the single source in the same
|
|
124
|
+
* preview shape so the client renders compiled SML identically to TSX emission.
|
|
219
125
|
*/
|
|
220
|
-
const compileSourcePreview = (name, source
|
|
221
|
-
const { channel, compileOk, compiled } = compiledPreview(source
|
|
126
|
+
const compileSourcePreview = (name, source) => {
|
|
127
|
+
const { channel, compileOk, compiled } = compiledPreview(source);
|
|
222
128
|
return {
|
|
223
129
|
name,
|
|
224
130
|
ok: compileOk,
|
|
@@ -231,6 +137,6 @@ const compileSourcePreview = (name, source, options) => {
|
|
|
231
137
|
};
|
|
232
138
|
};
|
|
233
139
|
//#endregion
|
|
234
|
-
export { COMPILER_VERSION,
|
|
140
|
+
export { COMPILER_VERSION, compileSourcePreview, emitModulePreview };
|
|
235
141
|
|
|
236
142
|
//# sourceMappingURL=emit.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { Plugin } from "vite";
|
|
2
|
-
import { CompileOptions } from "@samva/markup/compile";
|
|
3
2
|
//#region src/editor.d.ts
|
|
4
3
|
interface SamvaEditorPluginOptions {
|
|
5
|
-
/** Directory containing `.
|
|
4
|
+
/** Directory containing `.tsx` templates, relative to project root. Default `emails`. */
|
|
6
5
|
readonly templatesDir?: string | undefined;
|
|
7
6
|
/** Editor UI route. Default `/`; its API and assets are mounted as siblings below it. */
|
|
8
7
|
readonly route?: string | undefined;
|
|
9
|
-
/** Compile options applied to catalog validation and browser previews. */
|
|
10
|
-
readonly compile?: CompileOptions | undefined;
|
|
11
8
|
/** Project theme file relative to root. Default `theme.css`; false disables discovery. */
|
|
12
9
|
readonly theme?: string | false | undefined;
|
|
13
10
|
}
|