@samva/vite 0.8.0 → 0.10.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 +62 -58
- package/CHANGELOG.md +339 -0
- package/README.md +141 -95
- package/dist/build.d.ts +48 -43
- package/dist/build.js +88 -213
- package/dist/dev.d.ts +22 -0
- package/dist/dev.js +43 -0
- package/dist/editor/assets/index-BRnxqVXL.js +34 -0
- package/dist/editor/assets/index-Bv6OXYH5.css +2 -0
- package/dist/editor/index.html +2 -2
- package/dist/editor-B_2rlC_U.js +780 -0
- package/dist/index.d.ts +11 -4
- package/dist/index.js +1 -1054
- package/dist/project-CRqjs-wV.d.ts +270 -0
- package/dist/project-Ut6wra0r.js +772 -0
- package/dist/project.d.ts +2 -175
- package/dist/project.js +2 -2
- package/dist/render.d.ts +54 -0
- package/dist/render.js +98 -0
- package/package.json +12 -16
- package/dist/discovery-D2eR-rzi.js +0 -35
- package/dist/editor/assets/index-6Qlbkdhz.js +0 -36
- package/dist/editor/assets/index-Ed_V5wEW.css +0 -2
- package/dist/email.d.ts +0 -60
- package/dist/email.js +0 -126
- package/dist/emit.d.ts +0 -99
- package/dist/emit.js +0 -142
- package/dist/project-RON2Ei7d.js +0 -603
package/dist/project.d.ts
CHANGED
|
@@ -1,175 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { TemplateDefinition, isTemplateDefinition } from "@samva/markup/template";
|
|
4
|
-
import { EmailDiagnostic } from "@samva/markup/email/diagnostics";
|
|
5
|
-
import { SerializeEmailOptions } from "@samva/markup/email/html";
|
|
6
|
-
//#region src/brand.d.ts
|
|
7
|
-
/** Where `samva brands pull` writes snapshots, relative to the project root. */
|
|
8
|
-
declare const BRAND_SNAPSHOT_DIR = ".samva/brands";
|
|
9
|
-
declare const SNAPSHOT_VERSION = 1;
|
|
10
|
-
/** A brand as a build compiles it, with the digest the API knows its content by. */
|
|
11
|
-
interface ResolvedBrand extends EmailBrand {
|
|
12
|
-
readonly digest: string;
|
|
13
|
-
}
|
|
14
|
-
/** The file `samva brands pull` writes. */
|
|
15
|
-
interface BrandSnapshot extends ResolvedBrand {
|
|
16
|
-
readonly version: typeof SNAPSHOT_VERSION;
|
|
17
|
-
readonly name: string;
|
|
18
|
-
readonly isDefault: boolean;
|
|
19
|
-
/** ISO timestamp of the pull. */
|
|
20
|
-
readonly pulledAt: string;
|
|
21
|
-
}
|
|
22
|
-
type BrandWarningCode = "brand-snapshot-stale" | "brand-offline";
|
|
23
|
-
interface BrandWarning {
|
|
24
|
-
readonly code: BrandWarningCode;
|
|
25
|
-
readonly message: string;
|
|
26
|
-
}
|
|
27
|
-
type BrandResolution = {
|
|
28
|
-
readonly ok: true;
|
|
29
|
-
/** `undefined` when the project imports no brand. */
|
|
30
|
-
readonly brand: ResolvedBrand | undefined;
|
|
31
|
-
readonly source: "live" | "snapshot" | "none";
|
|
32
|
-
readonly warnings: readonly BrandWarning[];
|
|
33
|
-
} | {
|
|
34
|
-
readonly ok: false;
|
|
35
|
-
readonly message: string;
|
|
36
|
-
};
|
|
37
|
-
interface ResolveProjectBrandInput {
|
|
38
|
-
readonly root: string;
|
|
39
|
-
readonly files: EmailProjectSource;
|
|
40
|
-
/** Project-relative theme path; `undefined` when theming is disabled. */
|
|
41
|
-
readonly themePath?: string | undefined;
|
|
42
|
-
/** Environment holding `SAMVA_API_KEY`, `SAMVA_API_URL` and `PATH`; see `loadBrandEnv`. */
|
|
43
|
-
readonly env: Readonly<Record<string, string | undefined>>;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Resolve the brand a project's `samva:brand` import names: live when the
|
|
47
|
-
* environment's credentials reach the API, else the pulled snapshot with a
|
|
48
|
-
* warning, else a failure naming both fixes.
|
|
49
|
-
*/
|
|
50
|
-
declare const resolveProjectBrand: (input: ResolveProjectBrandInput) => Promise<BrandResolution>;
|
|
51
|
-
/**
|
|
52
|
-
* The environment a local build resolves the brand with: the process
|
|
53
|
-
* environment plus the project's `.env` files, as the editor's dev server
|
|
54
|
-
* reads them, so `SAMVA_API_KEY` in `.env` reaches `check` and `export` too.
|
|
55
|
-
*/
|
|
56
|
-
declare const loadBrandEnv: (root: string) => Promise<Readonly<Record<string, string | undefined>>>;
|
|
57
|
-
//#endregion
|
|
58
|
-
//#region src/project.d.ts
|
|
59
|
-
/**
|
|
60
|
-
* Read a project directory into the source map the compiler consumes. Text
|
|
61
|
-
* modules arrive as strings and imported files as bytes, which is the same
|
|
62
|
-
* shape the hosted build hands `compileEmailProject`.
|
|
63
|
-
*/
|
|
64
|
-
declare const readEmailProject: (dir: string) => Promise<EmailProjectSource>;
|
|
65
|
-
/** One discovered template: its declared identity and the entry that declares it. */
|
|
66
|
-
interface EmailCatalogEntry {
|
|
67
|
-
/** The identity the definition declares for itself. */
|
|
68
|
-
readonly id: string;
|
|
69
|
-
/** Project-relative path of the authored entry. */
|
|
70
|
-
readonly entryPath: string;
|
|
71
|
-
readonly definition: TemplateDefinition<unknown>;
|
|
72
|
-
readonly loaded: LoadedEmailEntry;
|
|
73
|
-
}
|
|
74
|
-
interface EmailCatalog {
|
|
75
|
-
readonly templates: readonly EmailCatalogEntry[];
|
|
76
|
-
/** Candidate entries that turned out to be ordinary modules. */
|
|
77
|
-
readonly helpers: readonly string[];
|
|
78
|
-
readonly diagnostics: readonly EmailDiagnostic[];
|
|
79
|
-
/** Every asset the discovered templates import, deduplicated by content. */
|
|
80
|
-
readonly assets: readonly AssetEntry[];
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Compile and evaluate every candidate entry, keeping the ones that declare a
|
|
84
|
-
* template. Compilation is per entry, exactly as a publication is per template,
|
|
85
|
-
* so shared components and CSS reach each template the same way they reach the
|
|
86
|
-
* hosted build.
|
|
87
|
-
*/
|
|
88
|
-
declare const loadEmailCatalog: (input: {
|
|
89
|
-
readonly renderer: EmailRenderer;
|
|
90
|
-
readonly files: EmailProjectSource;
|
|
91
|
-
readonly entryPaths?: readonly string[] | undefined;
|
|
92
|
-
/**
|
|
93
|
-
* Reuse one id namespace per entry so a reload replaces its modules instead
|
|
94
|
-
* of accumulating a new namespace per pass. A watch session sets this; a
|
|
95
|
-
* one-shot load leaves each entry isolated.
|
|
96
|
-
*/
|
|
97
|
-
readonly stableNamespaces?: boolean | undefined;
|
|
98
|
-
}) => Promise<EmailCatalog>;
|
|
99
|
-
/** One fixture rendered through the template it belongs to. */
|
|
100
|
-
interface RenderedFixture {
|
|
101
|
-
readonly templateId: string;
|
|
102
|
-
readonly fixture: string;
|
|
103
|
-
readonly rendered: RenderedEmail | undefined;
|
|
104
|
-
readonly diagnostics: readonly EmailDiagnostic[];
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Validate and render every fixture a template declares. A fixture that its own
|
|
108
|
-
* schema rejects is a source defect the author sees here rather than at publish.
|
|
109
|
-
*/
|
|
110
|
-
declare const renderEmailFixtures: (entry: EmailCatalogEntry, options?: SerializeEmailOptions) => readonly RenderedFixture[];
|
|
111
|
-
/** A live catalog over a project directory, reloaded when its source changes. */
|
|
112
|
-
interface EmailProjectSession {
|
|
113
|
-
readonly reload: () => Promise<EmailCatalog>;
|
|
114
|
-
readonly current: () => EmailCatalog;
|
|
115
|
-
readonly subscribe: (listener: (path: string) => void) => () => void;
|
|
116
|
-
readonly close: () => Promise<void>;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* The authoring loop: one evaluator, one catalog, reloaded on change. Content
|
|
120
|
-
* semantics come from `compileEmailProject` and `renderEmail`, the same two
|
|
121
|
-
* calls the hosted preview makes, so what an author iterates on locally is what
|
|
122
|
-
* a publication renders.
|
|
123
|
-
*/
|
|
124
|
-
declare const createEmailProjectSession: (dir: string, options: TransformOptions) => Promise<EmailProjectSession>;
|
|
125
|
-
interface EmailExportReceipt {
|
|
126
|
-
readonly templates: readonly {
|
|
127
|
-
readonly id: string;
|
|
128
|
-
readonly entryPath: string;
|
|
129
|
-
readonly fixtures: readonly {
|
|
130
|
-
readonly fixture: string;
|
|
131
|
-
readonly html: string;
|
|
132
|
-
readonly text: string;
|
|
133
|
-
}[];
|
|
134
|
-
}[];
|
|
135
|
-
readonly assets: {
|
|
136
|
-
readonly base: string;
|
|
137
|
-
readonly assets: readonly AssetEntry[];
|
|
138
|
-
};
|
|
139
|
-
readonly diagnostics: readonly EmailDiagnostic[];
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Where an export serves its assets from when the caller names no origin.
|
|
143
|
-
*
|
|
144
|
-
* An export writes one page at `templates/<id>/<fixture>.html` and every asset
|
|
145
|
-
* once at `assets/<content address>`, so the base a page resolves against is
|
|
146
|
-
* the path from its own directory back to that one. A template id is one path
|
|
147
|
-
* segment, so every page sits at the same depth and one base serves them all.
|
|
148
|
-
*/
|
|
149
|
-
declare const DEFAULT_EXPORT_ASSET_BASE = "../../assets";
|
|
150
|
-
/**
|
|
151
|
-
* Render every template's fixtures to HTML and text beside the bytes of every
|
|
152
|
-
* asset they reference, with the manifest that maps each address to its file.
|
|
153
|
-
*
|
|
154
|
-
* The export renders in the compiler's export mode, so a relative `assetBase`
|
|
155
|
-
* is accepted and the written page resolves its images from the directory it
|
|
156
|
-
* sits in. Delivery keeps refusing relative references — an inbox has no
|
|
157
|
-
* directory to resolve one against — so an export destined for sending names
|
|
158
|
-
* the https origin it will be served from instead.
|
|
159
|
-
*/
|
|
160
|
-
declare const exportEmailProject: (input: {
|
|
161
|
-
/** Directory holding the templates; every `.tsx` under it is a candidate entry. */
|
|
162
|
-
readonly dir: string;
|
|
163
|
-
/**
|
|
164
|
-
* Project root holding shared imports, `theme.css` and `.samva/brands`; defaults to `dir`.
|
|
165
|
-
* `samva templates export` passes the working directory, as `check` and `build` do.
|
|
166
|
-
*/
|
|
167
|
-
readonly root?: string | undefined;
|
|
168
|
-
readonly out: string;
|
|
169
|
-
readonly assetBase?: string | undefined;
|
|
170
|
-
/** Project theme file relative to `root`, as in `buildTemplates()`; `false` disables it. */
|
|
171
|
-
readonly theme?: string | false | undefined;
|
|
172
|
-
}) => Promise<EmailExportReceipt>;
|
|
173
|
-
//#endregion
|
|
174
|
-
export { BRAND_SNAPSHOT_DIR, type BrandResolution, type BrandSnapshot, type BrandWarning, DEFAULT_EXPORT_ASSET_BASE, EmailCatalog, EmailCatalogEntry, EmailExportReceipt, EmailProjectSession, RenderedFixture, type ResolvedBrand, createEmailProjectSession, exportEmailProject, isTemplateDefinition, loadBrandEnv, loadEmailCatalog, readEmailProject, renderEmailFixtures, resolveProjectBrand };
|
|
175
|
-
//# sourceMappingURL=project.d.ts.map
|
|
1
|
+
import { A as loadBrandEnv, C as renderChannelFixture, D as BrandSnapshot, E as BrandResolution, F as discoverEntries, I as readProjectFiles, L as templateDirectories, M as DEFAULT_TEMPLATE_DIRS, N as ProjectFiles, O as BrandWarning, P as SAMVA_DIR, S as hasErrors, T as BRAND_SNAPSHOT_DIR, _ as TemplateChannel, a as ProjectOptions, b as emailCompatibility, c as exportProject, d as CompileProjectInput, f as CompiledEntry, g as RenderedFixture, h as RenderedChannel, i as ProjectExportReceipt, j as resolveProjectBrand, k as ResolvedBrand, l as loadProject, m as FailedEntry, n as ExportedFixture, o as ProjectSession, p as CompiledProject, r as LoadedProject, s as createProjectSession, t as DEFAULT_EXPORT_ASSET_BASE, u as projectRoot, v as channelsOf, w as renderEmailFixtures, x as finding, y as compileProject } from "./project-CRqjs-wV.js";
|
|
2
|
+
export { BRAND_SNAPSHOT_DIR, type BrandResolution, type BrandSnapshot, type BrandWarning, CompileProjectInput, CompiledEntry, CompiledProject, DEFAULT_EXPORT_ASSET_BASE, DEFAULT_TEMPLATE_DIRS, ExportedFixture, FailedEntry, LoadedProject, ProjectExportReceipt, type ProjectFiles, ProjectOptions, ProjectSession, RenderedChannel, RenderedFixture, type ResolvedBrand, SAMVA_DIR, TemplateChannel, channelsOf, compileProject, createProjectSession, discoverEntries, emailCompatibility, exportProject, finding, hasErrors, loadBrandEnv, loadProject, projectRoot, readProjectFiles, renderChannelFixture, renderEmailFixtures, resolveProjectBrand, templateDirectories };
|
package/dist/project.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { BRAND_SNAPSHOT_DIR, DEFAULT_EXPORT_ASSET_BASE,
|
|
1
|
+
import { C as discoverEntries, D as readProjectFiles, O as templateDirectories, S as SAMVA_DIR, a as projectRoot, b as resolveProjectBrand, d as emailCompatibility, f as finding, g as BRAND_SNAPSHOT_DIR, h as renderEmailFixtures, i as loadProject, l as channelsOf, m as renderChannelFixture, n as createProjectSession, p as hasErrors, r as exportProject, t as DEFAULT_EXPORT_ASSET_BASE, u as compileProject, x as DEFAULT_TEMPLATE_DIRS, y as loadBrandEnv } from "./project-Ut6wra0r.js";
|
|
2
|
+
export { BRAND_SNAPSHOT_DIR, DEFAULT_EXPORT_ASSET_BASE, DEFAULT_TEMPLATE_DIRS, SAMVA_DIR, channelsOf, compileProject, createProjectSession, discoverEntries, emailCompatibility, exportProject, finding, hasErrors, loadBrandEnv, loadProject, projectRoot, readProjectFiles, renderChannelFixture, renderEmailFixtures, resolveProjectBrand, templateDirectories };
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { a as ProjectOptions } from "./project-CRqjs-wV.js";
|
|
2
|
+
import { RenderedIrWhatsApp } from "@samva/markup/render";
|
|
3
|
+
import { EmailDiagnostic } from "@samva/markup/diagnostics";
|
|
4
|
+
//#region src/render.d.ts
|
|
5
|
+
interface RenderTemplateInput extends ProjectOptions {
|
|
6
|
+
/** A template id, or the project-relative path of its entry. */
|
|
7
|
+
readonly template: string;
|
|
8
|
+
readonly fixture: string;
|
|
9
|
+
/** Overrides the template's locale for formatters. */
|
|
10
|
+
readonly locale?: string | undefined;
|
|
11
|
+
/** IANA time zone for date and time formatters; defaults to UTC. */
|
|
12
|
+
readonly timeZone?: string | undefined;
|
|
13
|
+
}
|
|
14
|
+
type RenderTemplateResult = {
|
|
15
|
+
readonly ok: true;
|
|
16
|
+
readonly template: string;
|
|
17
|
+
readonly fixture: string;
|
|
18
|
+
readonly subject: string;
|
|
19
|
+
readonly preheader?: string | undefined;
|
|
20
|
+
readonly html: string;
|
|
21
|
+
readonly text: string;
|
|
22
|
+
readonly diagnostics: readonly EmailDiagnostic[];
|
|
23
|
+
} | {
|
|
24
|
+
readonly ok: false;
|
|
25
|
+
readonly diagnostics: readonly EmailDiagnostic[];
|
|
26
|
+
};
|
|
27
|
+
type RenderChannelInput = RenderTemplateInput & {
|
|
28
|
+
readonly channel: "sms" | "whatsapp";
|
|
29
|
+
};
|
|
30
|
+
type RenderChannelResult = {
|
|
31
|
+
readonly ok: true;
|
|
32
|
+
readonly channel: "sms";
|
|
33
|
+
readonly template: string;
|
|
34
|
+
readonly fixture: string;
|
|
35
|
+
readonly text: string;
|
|
36
|
+
readonly diagnostics: readonly EmailDiagnostic[];
|
|
37
|
+
} | {
|
|
38
|
+
readonly ok: true;
|
|
39
|
+
readonly channel: "whatsapp";
|
|
40
|
+
readonly template: string;
|
|
41
|
+
readonly fixture: string;
|
|
42
|
+
readonly message: RenderedIrWhatsApp;
|
|
43
|
+
readonly diagnostics: readonly EmailDiagnostic[];
|
|
44
|
+
} | {
|
|
45
|
+
readonly ok: false;
|
|
46
|
+
readonly diagnostics: readonly EmailDiagnostic[];
|
|
47
|
+
};
|
|
48
|
+
/** Compile the project and render one fixture of one template through its email channel. */
|
|
49
|
+
declare const renderTemplate: (input: RenderTemplateInput) => Promise<RenderTemplateResult>;
|
|
50
|
+
/** Compile the project and render one fixture of one template through its SMS or WhatsApp channel. */
|
|
51
|
+
declare const renderChannel: (input: RenderChannelInput) => Promise<RenderChannelResult>;
|
|
52
|
+
//#endregion
|
|
53
|
+
export { RenderChannelInput, RenderChannelResult, RenderTemplateInput, RenderTemplateResult, renderChannel, renderTemplate };
|
|
54
|
+
//# sourceMappingURL=render.d.ts.map
|
package/dist/render.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { _ as brandDiagnostics, f as finding, h as renderEmailFixtures, i as loadProject, m as renderChannelFixture, p as hasErrors } from "./project-Ut6wra0r.js";
|
|
2
|
+
//#region src/render.ts
|
|
3
|
+
/** Compile just enough of the project to find and build the named template. */
|
|
4
|
+
const locate = async (input) => {
|
|
5
|
+
const byPath = input.template.endsWith(".tsx");
|
|
6
|
+
const project = await loadProject(input, void 0, byPath ? [input.template.replace(/^\.\//, "")] : void 0);
|
|
7
|
+
const { catalog } = project;
|
|
8
|
+
const entry = catalog.templates.find((candidate) => byPath ? candidate.entryPath === input.template.replace(/^\.\//, "") : candidate.id === input.template);
|
|
9
|
+
const brand = brandDiagnostics(project.brand);
|
|
10
|
+
const ambiguous = entry === void 0 ? [] : catalog.diagnostics.filter((item) => item.code === "duplicate-template-id" && item.message.startsWith(`Template id ${JSON.stringify(entry.id)} `));
|
|
11
|
+
if (entry !== void 0 && ambiguous.length === 0) return {
|
|
12
|
+
ok: true,
|
|
13
|
+
entry,
|
|
14
|
+
diagnostics: [...brand, ...entry.diagnostics]
|
|
15
|
+
};
|
|
16
|
+
const failed = byPath ? catalog.failures.filter((candidate) => candidate.entryPath === input.template.replace(/^\.\//, "")) : catalog.failures;
|
|
17
|
+
return {
|
|
18
|
+
ok: false,
|
|
19
|
+
diagnostics: [
|
|
20
|
+
...brand,
|
|
21
|
+
...catalog.diagnostics,
|
|
22
|
+
...failed.flatMap((candidate) => candidate.diagnostics),
|
|
23
|
+
...entry !== void 0 || byPath && failed.length > 0 ? [] : [finding("template-not-found", "error", `No template ${JSON.stringify(input.template)} in the project${failed.length > 0 ? ", and some entries did not compile (their findings are listed)" : ""}. Known templates: ${catalog.templates.map((candidate) => candidate.id).join(", ") || "none"}.`)]
|
|
24
|
+
]
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
/** Compile the project and render one fixture of one template through its email channel. */
|
|
28
|
+
const renderTemplate = async (input) => {
|
|
29
|
+
const located = await locate(input);
|
|
30
|
+
if (!located.ok) return located;
|
|
31
|
+
const { entry } = located;
|
|
32
|
+
if (!entry.channels.includes("email")) return {
|
|
33
|
+
ok: false,
|
|
34
|
+
diagnostics: [finding("missing-channel", "error", `Template ${entry.id} declares no email channel.`)]
|
|
35
|
+
};
|
|
36
|
+
const [rendered] = renderEmailFixtures({
|
|
37
|
+
...entry,
|
|
38
|
+
fixtures: pick(entry.fixtures, input.fixture)
|
|
39
|
+
}, renderOptions(input));
|
|
40
|
+
if (rendered === void 0) return {
|
|
41
|
+
ok: false,
|
|
42
|
+
diagnostics: [...located.diagnostics, unknownFixture(entry, input.fixture)]
|
|
43
|
+
};
|
|
44
|
+
if (rendered.rendered === void 0 || hasErrors(located.diagnostics)) return {
|
|
45
|
+
ok: false,
|
|
46
|
+
diagnostics: [...located.diagnostics, ...rendered.diagnostics]
|
|
47
|
+
};
|
|
48
|
+
return {
|
|
49
|
+
ok: true,
|
|
50
|
+
template: entry.id,
|
|
51
|
+
fixture: input.fixture,
|
|
52
|
+
subject: rendered.rendered.subject,
|
|
53
|
+
...rendered.rendered.preheader === void 0 ? {} : { preheader: rendered.rendered.preheader },
|
|
54
|
+
html: rendered.rendered.html,
|
|
55
|
+
text: rendered.rendered.text,
|
|
56
|
+
diagnostics: located.diagnostics
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
/** Compile the project and render one fixture of one template through its SMS or WhatsApp channel. */
|
|
60
|
+
const renderChannel = async (input) => {
|
|
61
|
+
const located = await locate(input);
|
|
62
|
+
if (!located.ok) return located;
|
|
63
|
+
const { entry } = located;
|
|
64
|
+
if (!entry.channels.includes(input.channel)) return {
|
|
65
|
+
ok: false,
|
|
66
|
+
diagnostics: [finding("missing-channel", "error", `Template ${entry.id} declares no ${input.channel} channel.`)]
|
|
67
|
+
};
|
|
68
|
+
const rendered = renderChannelFixture(entry, input.channel, input.fixture, renderOptions(input));
|
|
69
|
+
if (!rendered.ok || hasErrors(located.diagnostics)) return {
|
|
70
|
+
ok: false,
|
|
71
|
+
diagnostics: [...located.diagnostics, ...rendered.ok ? [] : rendered.diagnostics]
|
|
72
|
+
};
|
|
73
|
+
return rendered.channel === "sms" ? {
|
|
74
|
+
ok: true,
|
|
75
|
+
channel: "sms",
|
|
76
|
+
template: entry.id,
|
|
77
|
+
fixture: input.fixture,
|
|
78
|
+
text: rendered.text,
|
|
79
|
+
diagnostics: located.diagnostics
|
|
80
|
+
} : {
|
|
81
|
+
ok: true,
|
|
82
|
+
channel: "whatsapp",
|
|
83
|
+
template: entry.id,
|
|
84
|
+
fixture: input.fixture,
|
|
85
|
+
message: rendered.message,
|
|
86
|
+
diagnostics: located.diagnostics
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
const renderOptions = (input) => ({
|
|
90
|
+
...input.locale === void 0 ? {} : { locale: input.locale },
|
|
91
|
+
...input.timeZone === void 0 ? {} : { timeZone: input.timeZone }
|
|
92
|
+
});
|
|
93
|
+
const pick = (fixtures, name) => Object.hasOwn(fixtures, name) ? { [name]: fixtures[name] } : {};
|
|
94
|
+
const unknownFixture = (entry, fixture) => finding("unknown-fixture", "error", `Template ${entry.id} declares no fixture named ${JSON.stringify(fixture)}. Declared: ${Object.keys(entry.fixtures).join(", ")}.`);
|
|
95
|
+
//#endregion
|
|
96
|
+
export { renderChannel, renderTemplate };
|
|
97
|
+
|
|
98
|
+
//# sourceMappingURL=render.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@samva/vite",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"description": "Local editor, dev server and build for Samva email, SMS and WhatsApp templates",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"email",
|
|
7
7
|
"samva",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"!dist/**/*.map",
|
|
29
29
|
"package.json",
|
|
30
30
|
"README.md",
|
|
31
|
+
"CHANGELOG.md",
|
|
31
32
|
"AGENTS.md",
|
|
32
33
|
"LICENSE"
|
|
33
34
|
],
|
|
@@ -38,10 +39,6 @@
|
|
|
38
39
|
"types": "./dist/index.d.ts",
|
|
39
40
|
"import": "./dist/index.js"
|
|
40
41
|
},
|
|
41
|
-
"./emit": {
|
|
42
|
-
"types": "./dist/emit.d.ts",
|
|
43
|
-
"import": "./dist/emit.js"
|
|
44
|
-
},
|
|
45
42
|
"./build": {
|
|
46
43
|
"types": "./dist/build.d.ts",
|
|
47
44
|
"import": "./dist/build.js"
|
|
@@ -50,9 +47,13 @@
|
|
|
50
47
|
"types": "./dist/project.d.ts",
|
|
51
48
|
"import": "./dist/project.js"
|
|
52
49
|
},
|
|
53
|
-
"./
|
|
54
|
-
"types": "./dist/
|
|
55
|
-
"import": "./dist/
|
|
50
|
+
"./dev": {
|
|
51
|
+
"types": "./dist/dev.d.ts",
|
|
52
|
+
"import": "./dist/dev.js"
|
|
53
|
+
},
|
|
54
|
+
"./render": {
|
|
55
|
+
"types": "./dist/render.d.ts",
|
|
56
|
+
"import": "./dist/render.js"
|
|
56
57
|
}
|
|
57
58
|
},
|
|
58
59
|
"publishConfig": {
|
|
@@ -64,17 +65,12 @@
|
|
|
64
65
|
"dev:editor": "bun run --filter @samva/vite-editor-app dev",
|
|
65
66
|
"prepack": "bun run build",
|
|
66
67
|
"typecheck": "tsc --noEmit",
|
|
67
|
-
"test": "vitest run
|
|
68
|
+
"test": "vitest run",
|
|
68
69
|
"test:browser": "turbo run build --filter=@samva/vite && playwright test --config playwright.config.ts --project chromium",
|
|
69
70
|
"test:browser:cross": "turbo run build --filter=@samva/vite && playwright test --config playwright.config.ts"
|
|
70
71
|
},
|
|
71
72
|
"dependencies": {
|
|
72
|
-
"@
|
|
73
|
-
"@samva/markup": "^0.8.0",
|
|
74
|
-
"better-result": "3.0.1",
|
|
75
|
-
"caniemail": "2.0.2",
|
|
76
|
-
"css-tree": "3.2.1",
|
|
77
|
-
"tailwindcss": "^4.3.3"
|
|
73
|
+
"@samva/markup": "^0.10.0"
|
|
78
74
|
},
|
|
79
75
|
"devDependencies": {
|
|
80
76
|
"@effect/vitest": "4.0.0-rc.117",
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { readdir } from "node:fs/promises";
|
|
2
|
-
import { join, relative, sep } from "node:path";
|
|
3
|
-
//#region src/discovery.ts
|
|
4
|
-
const isTemplateFile = (name) => name.endsWith(".tsx");
|
|
5
|
-
const toPosix = (value) => sep === "/" ? value : value.split(sep).join("/");
|
|
6
|
-
/**
|
|
7
|
-
* Recursively lists template files under `dir`. Hidden entries and
|
|
8
|
-
* `node_modules` are skipped. Results are sorted by id for deterministic
|
|
9
|
-
* ordering (the preview list and build output must be stable).
|
|
10
|
-
*/
|
|
11
|
-
const discoverTemplateFiles = async (dir) => {
|
|
12
|
-
const found = [];
|
|
13
|
-
const walk = async (current) => {
|
|
14
|
-
const visible = (await readdir(current, { withFileTypes: true })).filter((entry) => !entry.name.startsWith(".") && entry.name !== "node_modules");
|
|
15
|
-
await Promise.all(visible.map(async (entry) => {
|
|
16
|
-
const full = join(current, entry.name);
|
|
17
|
-
if (entry.isDirectory()) {
|
|
18
|
-
await walk(full);
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
if (!isTemplateFile(entry.name)) return;
|
|
22
|
-
found.push({
|
|
23
|
-
path: full,
|
|
24
|
-
id: toPosix(relative(dir, full)),
|
|
25
|
-
kind: "tsx"
|
|
26
|
-
});
|
|
27
|
-
}));
|
|
28
|
-
};
|
|
29
|
-
await walk(dir);
|
|
30
|
-
return found.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
31
|
-
};
|
|
32
|
-
//#endregion
|
|
33
|
-
export { discoverTemplateFiles as t };
|
|
34
|
-
|
|
35
|
-
//# sourceMappingURL=discovery-D2eR-rzi.js.map
|