@arkstack/view 0.4.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Toneflix Technologies Limited
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,31 @@
1
+ # @arkstack/view
2
+
3
+ Views for Arkstack applications.
4
+
5
+ ```ts
6
+ import { View, view } from '@arkstack/view';
7
+
8
+ View.share({ appName: 'Arkstack' });
9
+ View.share('year', new Date().getFullYear());
10
+
11
+ View.composer('welcome', (view) => {
12
+ view.with({ title: 'Welcome' });
13
+ });
14
+
15
+ class WelcomeComposer {
16
+ compose(view) {
17
+ view.with('message', 'Your app is ready.');
18
+ }
19
+ }
20
+
21
+ View.composer('welcome', WelcomeComposer);
22
+
23
+ const html = await view('welcome').with('name', 'Ada');
24
+
25
+ const dashboard = await View.make('dashboard').with({ user }).render();
26
+
27
+ const email = await view('~org/package-name.mail', { user });
28
+ ```
29
+
30
+ Views are resolved from `src/resources/views` by default. Use `View.mount()` to add or replace mounted view directories.
31
+ Package views resolve from `node_modules/<package>/resources/views`.
package/dist/app.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { view as viewHelper } from './helpers'
2
+
3
+ declare global {
4
+ var view: typeof viewHelper
5
+ }
6
+
7
+ export {}
@@ -0,0 +1,41 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_index = require('../index.cjs');
3
+ let node_path = require("node:path");
4
+ let node_fs_promises = require("node:fs/promises");
5
+ let _h3ravel_musket = require("@h3ravel/musket");
6
+
7
+ //#region src/commands/MakeViewCommand.ts
8
+ var MakeViewCommand = class extends _h3ravel_musket.Command {
9
+ signature = `make:view
10
+ {name : name of the view to create}
11
+ {--force : force overwrite if view already exists}
12
+ `;
13
+ description = "Create a new Edge view file";
14
+ async handle() {
15
+ const name = String(this.argument("name") ?? "").trim();
16
+ if (!name) {
17
+ this.error("View name is required");
18
+ return;
19
+ }
20
+ const path = this.path(name);
21
+ await (0, node_fs_promises.mkdir)((0, node_path.dirname)(path), { recursive: true });
22
+ await (0, node_fs_promises.writeFile)(path, this.stub(name), { flag: this.option("force") ? "w" : "wx" });
23
+ this.success(`View ${name} created successfully at ${path}`);
24
+ }
25
+ path(name) {
26
+ const viewPath = name.replace(/\\/g, "/").replace(/\./g, "/").replace(/\.edge$/i, "");
27
+ return (0, node_path.resolve)(process.cwd(), "src", "resources", "views", `${viewPath}.edge`);
28
+ }
29
+ stub(name) {
30
+ const title = name.split(/[./\\]/).filter(Boolean).pop() ?? "view";
31
+ return [
32
+ `{{-- ${title} view --}}`,
33
+ "",
34
+ `<h1>{{ title || '${title}' }}</h1>`,
35
+ ""
36
+ ].join("\n");
37
+ }
38
+ };
39
+
40
+ //#endregion
41
+ exports.MakeViewCommand = MakeViewCommand;
@@ -0,0 +1,13 @@
1
+ import { Command } from "@h3ravel/musket";
2
+
3
+ //#region src/commands/MakeViewCommand.d.ts
4
+ declare class MakeViewCommand extends Command {
5
+ protected signature: string;
6
+ protected description: string;
7
+ handle(): Promise<undefined>;
8
+ path(name: string): string;
9
+ stub(name: string): string;
10
+ }
11
+ //#endregion
12
+ export { MakeViewCommand };
13
+ //# sourceMappingURL=MakeViewCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MakeViewCommand.d.ts","names":[],"sources":["../../src/commands/MakeViewCommand.ts"],"mappings":";;;cAKa,eAAA,SAAwB,OAAA;EAAA,UACvB,SAAA;EAAA,UAKA,WAAA;EAEJ,MAAA,CAAA,GAAM,OAAA;EAeZ,IAAA,CAAM,IAAA;EASN,IAAA,CAAM,IAAA;AAAA"}
@@ -0,0 +1,40 @@
1
+ import { dirname, resolve } from "node:path";
2
+ import { mkdir, writeFile } from "node:fs/promises";
3
+ import { Command } from "@h3ravel/musket";
4
+
5
+ //#region src/commands/MakeViewCommand.ts
6
+ var MakeViewCommand = class extends Command {
7
+ signature = `make:view
8
+ {name : name of the view to create}
9
+ {--force : force overwrite if view already exists}
10
+ `;
11
+ description = "Create a new Edge view file";
12
+ async handle() {
13
+ const name = String(this.argument("name") ?? "").trim();
14
+ if (!name) {
15
+ this.error("View name is required");
16
+ return;
17
+ }
18
+ const path = this.path(name);
19
+ await mkdir(dirname(path), { recursive: true });
20
+ await writeFile(path, this.stub(name), { flag: this.option("force") ? "w" : "wx" });
21
+ this.success(`View ${name} created successfully at ${path}`);
22
+ }
23
+ path(name) {
24
+ const viewPath = name.replace(/\\/g, "/").replace(/\./g, "/").replace(/\.edge$/i, "");
25
+ return resolve(process.cwd(), "src", "resources", "views", `${viewPath}.edge`);
26
+ }
27
+ stub(name) {
28
+ const title = name.split(/[./\\]/).filter(Boolean).pop() ?? "view";
29
+ return [
30
+ `{{-- ${title} view --}}`,
31
+ "",
32
+ `<h1>{{ title || '${title}' }}</h1>`,
33
+ ""
34
+ ].join("\n");
35
+ }
36
+ };
37
+
38
+ //#endregion
39
+ export { MakeViewCommand };
40
+ //# sourceMappingURL=MakeViewCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MakeViewCommand.js","names":[],"sources":["../../src/commands/MakeViewCommand.ts"],"sourcesContent":["import { dirname, resolve } from 'node:path'\nimport { mkdir, writeFile } from 'node:fs/promises'\n\nimport { Command } from '@h3ravel/musket'\n\nexport class MakeViewCommand extends Command {\n protected signature = `make:view\n {name : name of the view to create}\n {--force : force overwrite if view already exists}\n `\n\n protected description = 'Create a new Edge view file'\n\n async handle () {\n const name = String(this.argument('name') ?? '').trim()\n\n if (!name) {\n return void this.error('View name is required')\n }\n\n const path = this.path(name)\n\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, this.stub(name), { flag: this.option('force') ? 'w' : 'wx' })\n\n this.success(`View ${name} created successfully at ${path}`)\n }\n\n path (name: string) {\n const viewPath = name\n .replace(/\\\\/g, '/')\n .replace(/\\./g, '/')\n .replace(/\\.edge$/i, '')\n\n return resolve(process.cwd(), 'src', 'resources', 'views', `${viewPath}.edge`)\n }\n\n stub (name: string) {\n const title = name\n .split(/[./\\\\]/)\n .filter(Boolean)\n .pop() ?? 'view'\n\n return [\n `{{-- ${title} view --}}`,\n '',\n `<h1>{{ title || '${title}' }}</h1>`,\n '',\n ].join('\\n')\n }\n}\n"],"mappings":";;;;;AAKA,IAAa,kBAAb,cAAqC,QAAQ;CACzC,AAAU,YAAY;;;;CAKtB,AAAU,cAAc;CAExB,MAAM,SAAU;EACZ,MAAM,OAAO,OAAO,KAAK,SAAS,OAAO,IAAI,GAAG,CAAC,MAAM;AAEvD,MAAI,CAAC,MAAM;AACA,GAAK,KAAK,MAAM,wBAAwB;AAA/C;;EAGJ,MAAM,OAAO,KAAK,KAAK,KAAK;AAE5B,QAAM,MAAM,QAAQ,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AAC/C,QAAM,UAAU,MAAM,KAAK,KAAK,KAAK,EAAE,EAAE,MAAM,KAAK,OAAO,QAAQ,GAAG,MAAM,MAAM,CAAC;AAEnF,OAAK,QAAQ,QAAQ,KAAK,2BAA2B,OAAO;;CAGhE,KAAM,MAAc;EAChB,MAAM,WAAW,KACZ,QAAQ,OAAO,IAAI,CACnB,QAAQ,OAAO,IAAI,CACnB,QAAQ,YAAY,GAAG;AAE5B,SAAO,QAAQ,QAAQ,KAAK,EAAE,OAAO,aAAa,SAAS,GAAG,SAAS,OAAO;;CAGlF,KAAM,MAAc;EAChB,MAAM,QAAQ,KACT,MAAM,SAAS,CACf,OAAO,QAAQ,CACf,KAAK,IAAI;AAEd,SAAO;GACH,QAAQ,MAAM;GACd;GACA,oBAAoB,MAAM;GAC1B;GACH,CAAC,KAAK,KAAK"}
package/dist/index.cjs ADDED
@@ -0,0 +1,285 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) {
14
+ __defProp(to, key, {
15
+ get: ((k) => from[k]).bind(null, key),
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ }
19
+ }
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
24
+ value: mod,
25
+ enumerable: true
26
+ }) : target, mod));
27
+
28
+ //#endregion
29
+ let node_fs = require("node:fs");
30
+ let node_path = require("node:path");
31
+ let edge_js = require("edge.js");
32
+ edge_js = __toESM(edge_js);
33
+
34
+ //#region src/helpers.ts
35
+ function view(name, data = {}) {
36
+ if (name === void 0) return View.factoryInstance();
37
+ return View.make(name, data);
38
+ }
39
+ Object.defineProperty(globalThis, "view", {
40
+ value: view,
41
+ configurable: true,
42
+ writable: true
43
+ });
44
+ const isClass = (target) => {
45
+ return typeof target === "function" && /^class\s/.test(Function.prototype.toString.call(target));
46
+ };
47
+ const mergeData = (target, data) => {
48
+ if (data.length === 0) return target;
49
+ if (typeof data[0] === "string") {
50
+ target[data[0]] = data[1];
51
+ return target;
52
+ }
53
+ for (const value of data) if (value && typeof value === "object" && !Array.isArray(value)) Object.assign(target, value);
54
+ return target;
55
+ };
56
+ const runComposerSync = (composer, view) => {
57
+ const result = runComposer(composer, view);
58
+ if (result && typeof result.then === "function") throw new Error("Async view composers cannot be used with renderSync.");
59
+ };
60
+ const runComposer = (composer, view) => {
61
+ if (typeof composer === "function") {
62
+ if (isClass(composer)) return new composer().compose(view);
63
+ return composer(view);
64
+ }
65
+ return composer.compose(view);
66
+ };
67
+
68
+ //#endregion
69
+ //#region src/packageViews.ts
70
+ const parsePackageViewName = (name) => {
71
+ if (!name.startsWith("~")) return null;
72
+ const source = name.slice(1);
73
+ const slashIndex = source.indexOf("/");
74
+ const dotIndex = slashIndex === -1 ? source.indexOf(".") : source.indexOf(".", slashIndex);
75
+ if (dotIndex <= 0) throw new Error(`Invalid package view name: ${name}`);
76
+ const packageName = source.slice(0, dotIndex);
77
+ const viewName = source.slice(dotIndex + 1);
78
+ if (!viewName) throw new Error(`Invalid package view name: ${name}`);
79
+ const nodePackageName = slashIndex === -1 ? packageName : `@${packageName}`;
80
+ const diskName = `package_${packageName.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
81
+ return {
82
+ source: name,
83
+ packageName,
84
+ nodePackageName,
85
+ diskName,
86
+ viewName,
87
+ edgeName: `${diskName}::${viewName}`
88
+ };
89
+ };
90
+ const resolvePackageViewsPath = (nodePackageName, viewPath = "resources/views") => {
91
+ const viewsPath = (0, node_path.resolve)((0, node_path.resolve)(process.cwd(), "node_modules", nodePackageName), viewPath);
92
+ if (!(0, node_fs.existsSync)(viewsPath)) throw new Error(`Package views directory not found: ${viewsPath}`);
93
+ return viewsPath;
94
+ };
95
+
96
+ //#endregion
97
+ //#region src/ViewInstance.ts
98
+ var ViewInstance = class {
99
+ payload;
100
+ composersHaveRun = false;
101
+ constructor(name, data = {}, renderer, runComposers, runComposersSync, renderName = name) {
102
+ this.name = name;
103
+ this.renderer = renderer;
104
+ this.runComposers = runComposers;
105
+ this.runComposersSync = runComposersSync;
106
+ this.renderName = renderName;
107
+ this.payload = { ...data };
108
+ }
109
+ get data() {
110
+ return this.payload;
111
+ }
112
+ with(...data) {
113
+ mergeData(this.payload, data);
114
+ return this;
115
+ }
116
+ async render() {
117
+ await this.compose();
118
+ return await this.renderer.render(this.renderName, this.payload);
119
+ }
120
+ renderSync() {
121
+ this.composeSync();
122
+ return this.renderer.renderSync(this.renderName, this.payload);
123
+ }
124
+ then(onfulfilled, onrejected) {
125
+ return this.render().then(onfulfilled, onrejected);
126
+ }
127
+ async compose() {
128
+ if (this.composersHaveRun) return;
129
+ this.composersHaveRun = true;
130
+ await this.runComposers(this);
131
+ }
132
+ composeSync() {
133
+ if (this.composersHaveRun) return;
134
+ this.composersHaveRun = true;
135
+ this.runComposersSync(this);
136
+ }
137
+ };
138
+
139
+ //#endregion
140
+ //#region src/ViewFactory.ts
141
+ var ViewFactory = class {
142
+ edge;
143
+ sharedData = {};
144
+ composers = /* @__PURE__ */ new Map();
145
+ mountedPackages = /* @__PURE__ */ new Set();
146
+ packageViewsPath;
147
+ constructor(options = {}) {
148
+ this.edge = options.edge ?? edge_js.Edge.create({ cache: options.cache });
149
+ this.packageViewsPath = options.packageViewsPath ?? "resources/views";
150
+ this.mount(options.viewsPath ?? (0, node_path.resolve)(process.cwd(), "src", "resources", "views"));
151
+ }
152
+ make(name, data = {}) {
153
+ const edgeName = this.resolveName(name);
154
+ return new ViewInstance(name, {
155
+ ...this.sharedData,
156
+ ...data
157
+ }, this.edge, async (view) => await this.runComposers(name, view), (view) => this.runComposersSync(name, view), edgeName);
158
+ }
159
+ first(names, data = {}) {
160
+ const name = names.find((candidate) => this.exists(candidate));
161
+ if (!name) throw new Error(`None of the given views exist: ${names.join(", ")}`);
162
+ return this.make(name, data);
163
+ }
164
+ exists(name) {
165
+ const edgeName = this.resolveName(name);
166
+ if (this.edge.loader.templates[edgeName]) return true;
167
+ try {
168
+ return (0, node_fs.existsSync)(this.edge.loader.makePath(edgeName));
169
+ } catch {
170
+ return false;
171
+ }
172
+ }
173
+ share(...data) {
174
+ mergeData(this.sharedData, data);
175
+ return this;
176
+ }
177
+ composer(names, composer) {
178
+ for (const name of Array.isArray(names) ? names : [names]) this.composers.set(name, [...this.composers.get(name) ?? [], composer]);
179
+ return this;
180
+ }
181
+ mount(diskName, viewsDirectory) {
182
+ if (viewsDirectory === void 0) {
183
+ this.edge.mount(diskName);
184
+ return this;
185
+ }
186
+ this.edge.mount(diskName, viewsDirectory);
187
+ return this;
188
+ }
189
+ raw(name, contents) {
190
+ this.edge.registerTemplate(name, { template: contents });
191
+ return this;
192
+ }
193
+ flushShared() {
194
+ this.sharedData = {};
195
+ return this;
196
+ }
197
+ flushComposers() {
198
+ this.composers.clear();
199
+ return this;
200
+ }
201
+ getComposers(name) {
202
+ const edgeName = this.resolveName(name);
203
+ return [
204
+ ...this.composers.get("*") ?? [],
205
+ ...this.composers.get(edgeName) ?? [],
206
+ ...this.composers.get(name) ?? []
207
+ ];
208
+ }
209
+ async runComposers(name, view) {
210
+ for (const composer of this.getComposers(name)) await runComposer(composer, view);
211
+ }
212
+ runComposersSync(name, view) {
213
+ for (const composer of this.getComposers(name)) runComposerSync(composer, view);
214
+ }
215
+ resolveName(name) {
216
+ const packageView = parsePackageViewName(name);
217
+ if (!packageView) return name;
218
+ if (!this.mountedPackages.has(packageView.diskName)) {
219
+ this.mount(packageView.diskName, resolvePackageViewsPath(packageView.nodePackageName, this.packageViewsPath));
220
+ this.mountedPackages.add(packageView.diskName);
221
+ }
222
+ return packageView.edgeName;
223
+ }
224
+ };
225
+
226
+ //#endregion
227
+ //#region src/View.ts
228
+ var View = class {
229
+ static factory = new ViewFactory();
230
+ static configure(options = {}) {
231
+ this.factory = new ViewFactory(options);
232
+ return this.factory;
233
+ }
234
+ static factoryInstance() {
235
+ return this.factory;
236
+ }
237
+ static make(name, data = {}) {
238
+ return this.factory.make(name, data);
239
+ }
240
+ static first(names, data = {}) {
241
+ return this.factory.first(names, data);
242
+ }
243
+ static exists(name) {
244
+ return this.factory.exists(name);
245
+ }
246
+ static share(...data) {
247
+ if (typeof data[0] === "string") this.factory.share(data[0], data[1]);
248
+ else this.factory.share(data[0] ?? {});
249
+ return this;
250
+ }
251
+ static composer(names, composer) {
252
+ this.factory.composer(names, composer);
253
+ return this;
254
+ }
255
+ static mount(diskName, viewsDirectory) {
256
+ if (viewsDirectory === void 0) this.factory.mount(diskName);
257
+ else this.factory.mount(diskName, viewsDirectory);
258
+ return this;
259
+ }
260
+ static raw(name, contents) {
261
+ this.factory.raw(name, contents);
262
+ return this;
263
+ }
264
+ };
265
+
266
+ //#endregion
267
+ Object.defineProperty(exports, 'Edge', {
268
+ enumerable: true,
269
+ get: function () {
270
+ return edge_js.Edge;
271
+ }
272
+ });
273
+ exports.View = View;
274
+ exports.ViewFactory = ViewFactory;
275
+ exports.ViewInstance = ViewInstance;
276
+ exports.__toESM = __toESM;
277
+ Object.defineProperty(exports, 'edge', {
278
+ enumerable: true,
279
+ get: function () {
280
+ return edge_js.default;
281
+ }
282
+ });
283
+ exports.parsePackageViewName = parsePackageViewName;
284
+ exports.resolvePackageViewsPath = resolvePackageViewsPath;
285
+ exports.view = view;
@@ -0,0 +1,104 @@
1
+ /// <reference path="./app.d.ts" />
2
+ import edge, { Edge, Edge as Edge$1 } from "edge.js";
3
+
4
+ //#region src/ViewInstance.d.ts
5
+ declare class ViewInstance implements PromiseLike<string> {
6
+ readonly name: string;
7
+ private renderer;
8
+ private runComposers;
9
+ private runComposersSync;
10
+ private renderName;
11
+ private payload;
12
+ private composersHaveRun;
13
+ constructor(name: string, data: ViewData | undefined, renderer: {
14
+ render: (name: string, data?: ViewData) => Promise<string>;
15
+ renderSync: (name: string, data?: ViewData) => string;
16
+ }, runComposers: ComposerRunner, runComposersSync: SyncComposerRunner, renderName?: string);
17
+ get data(): ViewData;
18
+ with(key: string, value: any): this;
19
+ with(data: ViewData): this;
20
+ render(): Promise<string>;
21
+ renderSync(): string;
22
+ then<TResult1 = string, TResult2 = never>(onfulfilled?: ((value: string) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
23
+ private compose;
24
+ private composeSync;
25
+ }
26
+ //#endregion
27
+ //#region src/types.d.ts
28
+ type ComposerRunner = (view: ViewInstance) => Promise<void>;
29
+ type SyncComposerRunner = (view: ViewInstance) => void;
30
+ type ViewData = Record<string, any>;
31
+ type ViewName = string;
32
+ type ViewComposerHandler = (view: ViewInstance) => void | Promise<void>;
33
+ interface ViewComposerObject {
34
+ compose: ViewComposerHandler;
35
+ }
36
+ type ViewComposerClass = new () => ViewComposerObject;
37
+ type ViewComposer = ViewComposerHandler | ViewComposerObject | ViewComposerClass;
38
+ type ViewComposerName = ViewName | ViewName[];
39
+ type ViewFactoryOptions = {
40
+ cache?: boolean;
41
+ viewsPath?: string | URL;
42
+ packageViewsPath?: string;
43
+ edge?: Edge$1;
44
+ };
45
+ //#endregion
46
+ //#region src/ViewFactory.d.ts
47
+ declare class ViewFactory {
48
+ readonly edge: Edge$1;
49
+ private sharedData;
50
+ private composers;
51
+ private mountedPackages;
52
+ private packageViewsPath;
53
+ constructor(options?: ViewFactoryOptions);
54
+ make(name: ViewName, data?: ViewData): ViewInstance;
55
+ first(names: ViewName[], data?: ViewData): ViewInstance;
56
+ exists(name: ViewName): boolean;
57
+ share(key: string, value: any): this;
58
+ share(data: ViewData): this;
59
+ composer(names: ViewComposerName, composer: ViewComposer): this;
60
+ mount(viewsDirectory: string | URL): this;
61
+ mount(diskName: string, viewsDirectory: string | URL): this;
62
+ raw(name: ViewName, contents: string): this;
63
+ flushShared(): this;
64
+ flushComposers(): this;
65
+ private getComposers;
66
+ private runComposers;
67
+ private runComposersSync;
68
+ private resolveName;
69
+ }
70
+ //#endregion
71
+ //#region src/View.d.ts
72
+ declare class View {
73
+ private static factory;
74
+ static configure(options?: ViewFactoryOptions): ViewFactory;
75
+ static factoryInstance(): ViewFactory;
76
+ static make(name: ViewName, data?: ViewData): ViewInstance;
77
+ static first(names: ViewName[], data?: ViewData): ViewInstance;
78
+ static exists(name: ViewName): boolean;
79
+ static share(key: string, value: any): typeof View;
80
+ static share(data: ViewData): typeof View;
81
+ static composer(names: ViewComposerName, composer: ViewComposer): typeof View;
82
+ static mount(viewsDirectory: string | URL): typeof View;
83
+ static mount(diskName: string, viewsDirectory: string | URL): typeof View;
84
+ static raw(name: ViewName, contents: string): typeof View;
85
+ }
86
+ //#endregion
87
+ //#region src/helpers.d.ts
88
+ declare function view(): ViewFactory;
89
+ declare function view(name: ViewName, data?: ViewData): ViewInstance;
90
+ //#endregion
91
+ //#region src/packageViews.d.ts
92
+ type PackageViewReference = {
93
+ source: string;
94
+ packageName: string;
95
+ nodePackageName: string;
96
+ diskName: string;
97
+ viewName: string;
98
+ edgeName: string;
99
+ };
100
+ declare const parsePackageViewName: (name: string) => PackageViewReference | null;
101
+ declare const resolvePackageViewsPath: (nodePackageName: string, viewPath?: string) => string;
102
+ //#endregion
103
+ export { ComposerRunner, Edge, SyncComposerRunner, View, ViewComposer, ViewComposerClass, ViewComposerHandler, ViewComposerName, ViewComposerObject, ViewData, ViewFactory, ViewFactoryOptions, ViewInstance, ViewName, edge, parsePackageViewName, resolvePackageViewsPath, view };
104
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/ViewInstance.ts","../src/types.ts","../src/ViewFactory.ts","../src/View.ts","../src/helpers.ts","../src/packageViews.ts"],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,239 @@
1
+ import { existsSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import edge, { Edge, Edge as Edge$1 } from "edge.js";
4
+
5
+ //#region src/helpers.ts
6
+ function view(name, data = {}) {
7
+ if (name === void 0) return View.factoryInstance();
8
+ return View.make(name, data);
9
+ }
10
+ Object.defineProperty(globalThis, "view", {
11
+ value: view,
12
+ configurable: true,
13
+ writable: true
14
+ });
15
+ const isClass = (target) => {
16
+ return typeof target === "function" && /^class\s/.test(Function.prototype.toString.call(target));
17
+ };
18
+ const mergeData = (target, data) => {
19
+ if (data.length === 0) return target;
20
+ if (typeof data[0] === "string") {
21
+ target[data[0]] = data[1];
22
+ return target;
23
+ }
24
+ for (const value of data) if (value && typeof value === "object" && !Array.isArray(value)) Object.assign(target, value);
25
+ return target;
26
+ };
27
+ const runComposerSync = (composer, view) => {
28
+ const result = runComposer(composer, view);
29
+ if (result && typeof result.then === "function") throw new Error("Async view composers cannot be used with renderSync.");
30
+ };
31
+ const runComposer = (composer, view) => {
32
+ if (typeof composer === "function") {
33
+ if (isClass(composer)) return new composer().compose(view);
34
+ return composer(view);
35
+ }
36
+ return composer.compose(view);
37
+ };
38
+
39
+ //#endregion
40
+ //#region src/packageViews.ts
41
+ const parsePackageViewName = (name) => {
42
+ if (!name.startsWith("~")) return null;
43
+ const source = name.slice(1);
44
+ const slashIndex = source.indexOf("/");
45
+ const dotIndex = slashIndex === -1 ? source.indexOf(".") : source.indexOf(".", slashIndex);
46
+ if (dotIndex <= 0) throw new Error(`Invalid package view name: ${name}`);
47
+ const packageName = source.slice(0, dotIndex);
48
+ const viewName = source.slice(dotIndex + 1);
49
+ if (!viewName) throw new Error(`Invalid package view name: ${name}`);
50
+ const nodePackageName = slashIndex === -1 ? packageName : `@${packageName}`;
51
+ const diskName = `package_${packageName.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
52
+ return {
53
+ source: name,
54
+ packageName,
55
+ nodePackageName,
56
+ diskName,
57
+ viewName,
58
+ edgeName: `${diskName}::${viewName}`
59
+ };
60
+ };
61
+ const resolvePackageViewsPath = (nodePackageName, viewPath = "resources/views") => {
62
+ const viewsPath = resolve(resolve(process.cwd(), "node_modules", nodePackageName), viewPath);
63
+ if (!existsSync(viewsPath)) throw new Error(`Package views directory not found: ${viewsPath}`);
64
+ return viewsPath;
65
+ };
66
+
67
+ //#endregion
68
+ //#region src/ViewInstance.ts
69
+ var ViewInstance = class {
70
+ payload;
71
+ composersHaveRun = false;
72
+ constructor(name, data = {}, renderer, runComposers, runComposersSync, renderName = name) {
73
+ this.name = name;
74
+ this.renderer = renderer;
75
+ this.runComposers = runComposers;
76
+ this.runComposersSync = runComposersSync;
77
+ this.renderName = renderName;
78
+ this.payload = { ...data };
79
+ }
80
+ get data() {
81
+ return this.payload;
82
+ }
83
+ with(...data) {
84
+ mergeData(this.payload, data);
85
+ return this;
86
+ }
87
+ async render() {
88
+ await this.compose();
89
+ return await this.renderer.render(this.renderName, this.payload);
90
+ }
91
+ renderSync() {
92
+ this.composeSync();
93
+ return this.renderer.renderSync(this.renderName, this.payload);
94
+ }
95
+ then(onfulfilled, onrejected) {
96
+ return this.render().then(onfulfilled, onrejected);
97
+ }
98
+ async compose() {
99
+ if (this.composersHaveRun) return;
100
+ this.composersHaveRun = true;
101
+ await this.runComposers(this);
102
+ }
103
+ composeSync() {
104
+ if (this.composersHaveRun) return;
105
+ this.composersHaveRun = true;
106
+ this.runComposersSync(this);
107
+ }
108
+ };
109
+
110
+ //#endregion
111
+ //#region src/ViewFactory.ts
112
+ var ViewFactory = class {
113
+ edge;
114
+ sharedData = {};
115
+ composers = /* @__PURE__ */ new Map();
116
+ mountedPackages = /* @__PURE__ */ new Set();
117
+ packageViewsPath;
118
+ constructor(options = {}) {
119
+ this.edge = options.edge ?? Edge$1.create({ cache: options.cache });
120
+ this.packageViewsPath = options.packageViewsPath ?? "resources/views";
121
+ this.mount(options.viewsPath ?? resolve(process.cwd(), "src", "resources", "views"));
122
+ }
123
+ make(name, data = {}) {
124
+ const edgeName = this.resolveName(name);
125
+ return new ViewInstance(name, {
126
+ ...this.sharedData,
127
+ ...data
128
+ }, this.edge, async (view) => await this.runComposers(name, view), (view) => this.runComposersSync(name, view), edgeName);
129
+ }
130
+ first(names, data = {}) {
131
+ const name = names.find((candidate) => this.exists(candidate));
132
+ if (!name) throw new Error(`None of the given views exist: ${names.join(", ")}`);
133
+ return this.make(name, data);
134
+ }
135
+ exists(name) {
136
+ const edgeName = this.resolveName(name);
137
+ if (this.edge.loader.templates[edgeName]) return true;
138
+ try {
139
+ return existsSync(this.edge.loader.makePath(edgeName));
140
+ } catch {
141
+ return false;
142
+ }
143
+ }
144
+ share(...data) {
145
+ mergeData(this.sharedData, data);
146
+ return this;
147
+ }
148
+ composer(names, composer) {
149
+ for (const name of Array.isArray(names) ? names : [names]) this.composers.set(name, [...this.composers.get(name) ?? [], composer]);
150
+ return this;
151
+ }
152
+ mount(diskName, viewsDirectory) {
153
+ if (viewsDirectory === void 0) {
154
+ this.edge.mount(diskName);
155
+ return this;
156
+ }
157
+ this.edge.mount(diskName, viewsDirectory);
158
+ return this;
159
+ }
160
+ raw(name, contents) {
161
+ this.edge.registerTemplate(name, { template: contents });
162
+ return this;
163
+ }
164
+ flushShared() {
165
+ this.sharedData = {};
166
+ return this;
167
+ }
168
+ flushComposers() {
169
+ this.composers.clear();
170
+ return this;
171
+ }
172
+ getComposers(name) {
173
+ const edgeName = this.resolveName(name);
174
+ return [
175
+ ...this.composers.get("*") ?? [],
176
+ ...this.composers.get(edgeName) ?? [],
177
+ ...this.composers.get(name) ?? []
178
+ ];
179
+ }
180
+ async runComposers(name, view) {
181
+ for (const composer of this.getComposers(name)) await runComposer(composer, view);
182
+ }
183
+ runComposersSync(name, view) {
184
+ for (const composer of this.getComposers(name)) runComposerSync(composer, view);
185
+ }
186
+ resolveName(name) {
187
+ const packageView = parsePackageViewName(name);
188
+ if (!packageView) return name;
189
+ if (!this.mountedPackages.has(packageView.diskName)) {
190
+ this.mount(packageView.diskName, resolvePackageViewsPath(packageView.nodePackageName, this.packageViewsPath));
191
+ this.mountedPackages.add(packageView.diskName);
192
+ }
193
+ return packageView.edgeName;
194
+ }
195
+ };
196
+
197
+ //#endregion
198
+ //#region src/View.ts
199
+ var View = class {
200
+ static factory = new ViewFactory();
201
+ static configure(options = {}) {
202
+ this.factory = new ViewFactory(options);
203
+ return this.factory;
204
+ }
205
+ static factoryInstance() {
206
+ return this.factory;
207
+ }
208
+ static make(name, data = {}) {
209
+ return this.factory.make(name, data);
210
+ }
211
+ static first(names, data = {}) {
212
+ return this.factory.first(names, data);
213
+ }
214
+ static exists(name) {
215
+ return this.factory.exists(name);
216
+ }
217
+ static share(...data) {
218
+ if (typeof data[0] === "string") this.factory.share(data[0], data[1]);
219
+ else this.factory.share(data[0] ?? {});
220
+ return this;
221
+ }
222
+ static composer(names, composer) {
223
+ this.factory.composer(names, composer);
224
+ return this;
225
+ }
226
+ static mount(diskName, viewsDirectory) {
227
+ if (viewsDirectory === void 0) this.factory.mount(diskName);
228
+ else this.factory.mount(diskName, viewsDirectory);
229
+ return this;
230
+ }
231
+ static raw(name, contents) {
232
+ this.factory.raw(name, contents);
233
+ return this;
234
+ }
235
+ };
236
+
237
+ //#endregion
238
+ export { Edge, View, ViewFactory, ViewInstance, edge, parsePackageViewName, resolvePackageViewsPath, view };
239
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["Edge"],"sources":["../src/helpers.ts","../src/packageViews.ts","../src/ViewInstance.ts","../src/ViewFactory.ts","../src/View.ts"],"sourcesContent":["import type { ViewComposer, ViewComposerObject, ViewData, ViewName } from './types'\n\nimport { View } from './View'\nimport { ViewFactory } from './ViewFactory'\nimport { ViewInstance } from './ViewInstance'\n\nexport function view (): ViewFactory\nexport function view (name: ViewName, data?: ViewData): ViewInstance\nexport function view (name?: ViewName, data: ViewData = {}) {\n if (name === undefined) {\n return View.factoryInstance()\n }\n\n return View.make(name, data)\n}\n\nObject.defineProperty(globalThis, 'view', {\n value: view,\n configurable: true,\n writable: true,\n})\n\nexport const isClass = <T = unknown> (\n target: unknown\n): target is new (...args: any[]) => T => {\n return typeof target === 'function'\n && /^class\\s/.test(Function.prototype.toString.call(target))\n}\n\nexport const mergeData = (target: ViewData, data: any[]) => {\n if (data.length === 0) {\n return target\n }\n\n if (typeof data[0] === 'string') {\n target[data[0]] = data[1]\n\n return target\n }\n\n for (const value of data) {\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n Object.assign(target, value)\n }\n }\n\n return target\n}\n\nexport const runComposerSync = (composer: ViewComposer, view: ViewInstance) => {\n const result = runComposer(composer, view)\n\n if (result && typeof result.then === 'function') {\n throw new Error('Async view composers cannot be used with renderSync.')\n }\n}\n\nexport const runComposer = (composer: ViewComposer, view: ViewInstance) => {\n if (typeof composer === 'function') {\n if (isClass<ViewComposerObject>(composer)) {\n return new composer().compose(view)\n }\n\n return composer(view)\n }\n\n return composer.compose(view)\n}\n","import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nexport type PackageViewReference = {\n source: string\n packageName: string\n nodePackageName: string\n diskName: string\n viewName: string\n edgeName: string\n}\n\nexport const parsePackageViewName = (name: string): PackageViewReference | null => {\n if (!name.startsWith('~')) {\n return null\n }\n\n const source = name.slice(1)\n const slashIndex = source.indexOf('/')\n const dotIndex = slashIndex === -1\n ? source.indexOf('.')\n : source.indexOf('.', slashIndex)\n\n if (dotIndex <= 0) {\n throw new Error(`Invalid package view name: ${name}`)\n }\n\n const packageName = source.slice(0, dotIndex)\n const viewName = source.slice(dotIndex + 1)\n\n if (!viewName) {\n throw new Error(`Invalid package view name: ${name}`)\n }\n\n const nodePackageName = slashIndex === -1\n ? packageName\n : `@${packageName}`\n const diskName = `package_${packageName.replace(/[^a-zA-Z0-9_-]/g, '_')}`\n\n return {\n source: name,\n packageName,\n nodePackageName,\n diskName,\n viewName,\n edgeName: `${diskName}::${viewName}`,\n }\n}\n\nexport const resolvePackageViewsPath = (\n nodePackageName: string,\n viewPath = 'resources/views',\n) => {\n const packageRoot = resolve(process.cwd(), 'node_modules', nodePackageName)\n const viewsPath = resolve(packageRoot, viewPath)\n\n if (!existsSync(viewsPath)) {\n throw new Error(`Package views directory not found: ${viewsPath}`)\n }\n\n return viewsPath\n}\n","import type { ComposerRunner, SyncComposerRunner, ViewData } from './types'\n\nimport { mergeData } from './helpers'\n\nexport class ViewInstance implements PromiseLike<string> {\n private payload: ViewData\n private composersHaveRun = false\n\n constructor(\n readonly name: string,\n data: ViewData = {},\n private renderer: {\n render: (name: string, data?: ViewData) => Promise<string>\n renderSync: (name: string, data?: ViewData) => string\n },\n private runComposers: ComposerRunner,\n private runComposersSync: SyncComposerRunner,\n private renderName = name,\n ) {\n this.payload = { ...data }\n }\n\n get data () {\n return this.payload\n }\n\n with (key: string, value: any): this\n with (data: ViewData): this\n with (...data: any[]): this {\n mergeData(this.payload, data)\n\n return this\n }\n\n async render () {\n await this.compose()\n\n return await this.renderer.render(this.renderName, this.payload)\n }\n\n renderSync () {\n this.composeSync()\n\n return this.renderer.renderSync(this.renderName, this.payload)\n }\n\n then<TResult1 = string, TResult2 = never> (\n onfulfilled?: ((value: string) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n return this.render().then(onfulfilled, onrejected)\n }\n\n private async compose () {\n if (this.composersHaveRun) {\n return\n }\n\n this.composersHaveRun = true\n await this.runComposers(this)\n }\n\n private composeSync () {\n if (this.composersHaveRun) {\n return\n }\n\n this.composersHaveRun = true\n this.runComposersSync(this)\n }\n}\n","import type { ViewComposer, ViewComposerName, ViewData, ViewFactoryOptions, ViewName } from './types'\nimport { mergeData, runComposer, runComposerSync } from './helpers'\nimport { parsePackageViewName, resolvePackageViewsPath } from './packageViews'\n\nimport { Edge } from 'edge.js'\nimport { ViewInstance } from './ViewInstance'\nimport { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nexport class ViewFactory {\n readonly edge: Edge\n private sharedData: ViewData = {}\n private composers = new Map<ViewName, ViewComposer[]>()\n private mountedPackages = new Set<string>()\n private packageViewsPath: string\n\n constructor(options: ViewFactoryOptions = {}) {\n this.edge = options.edge ?? Edge.create({ cache: options.cache })\n this.packageViewsPath = options.packageViewsPath ?? 'resources/views'\n this.mount(options.viewsPath ?? resolve(process.cwd(), 'src', 'resources', 'views'))\n }\n\n make (name: ViewName, data: ViewData = {}) {\n const edgeName = this.resolveName(name)\n\n return new ViewInstance(\n name,\n { ...this.sharedData, ...data },\n this.edge,\n async view => await this.runComposers(name, view),\n view => this.runComposersSync(name, view),\n edgeName,\n )\n }\n\n first (names: ViewName[], data: ViewData = {}) {\n const name = names.find(candidate => this.exists(candidate))\n\n if (!name) {\n throw new Error(`None of the given views exist: ${names.join(', ')}`)\n }\n\n return this.make(name, data)\n }\n\n exists (name: ViewName) {\n const edgeName = this.resolveName(name)\n\n if (this.edge.loader.templates[edgeName]) {\n return true\n }\n\n try {\n return existsSync(this.edge.loader.makePath(edgeName))\n } catch {\n return false\n }\n }\n\n share (key: string, value: any): this\n share (data: ViewData): this\n share (...data: any[]): this {\n mergeData(this.sharedData, data)\n\n return this\n }\n\n composer (names: ViewComposerName, composer: ViewComposer): this {\n for (const name of Array.isArray(names) ? names : [names]) {\n this.composers.set(name, [\n ...(this.composers.get(name) ?? []),\n composer,\n ])\n }\n\n return this\n }\n\n mount (viewsDirectory: string | URL): this\n mount (diskName: string, viewsDirectory: string | URL): this\n mount (diskName: string | URL, viewsDirectory?: string | URL): this {\n if (viewsDirectory === undefined) {\n this.edge.mount(diskName)\n\n return this\n }\n\n this.edge.mount(diskName as string, viewsDirectory)\n\n return this\n }\n\n raw (name: ViewName, contents: string): this {\n this.edge.registerTemplate(name, { template: contents })\n\n return this\n }\n\n flushShared () {\n this.sharedData = {}\n\n return this\n }\n\n flushComposers () {\n this.composers.clear()\n\n return this\n }\n\n private getComposers (name: ViewName) {\n const edgeName = this.resolveName(name)\n\n return [\n ...(this.composers.get('*') ?? []),\n ...(this.composers.get(edgeName) ?? []),\n ...(this.composers.get(name) ?? []),\n ]\n }\n\n private async runComposers (name: ViewName, view: ViewInstance) {\n for (const composer of this.getComposers(name)) {\n await runComposer(composer, view)\n }\n }\n\n private runComposersSync (name: ViewName, view: ViewInstance) {\n for (const composer of this.getComposers(name)) {\n runComposerSync(composer, view)\n }\n }\n\n private resolveName (name: ViewName) {\n const packageView = parsePackageViewName(name)\n\n if (!packageView) {\n return name\n }\n\n if (!this.mountedPackages.has(packageView.diskName)) {\n this.mount(\n packageView.diskName,\n resolvePackageViewsPath(packageView.nodePackageName, this.packageViewsPath),\n )\n this.mountedPackages.add(packageView.diskName)\n }\n\n return packageView.edgeName\n }\n}\n","import { ViewFactory } from './ViewFactory'\nimport type { ViewComposer, ViewComposerName, ViewData, ViewFactoryOptions, ViewName } from './types'\nimport type { ViewInstance } from './ViewInstance'\n\nexport class View {\n private static factory = new ViewFactory()\n\n static configure (options: ViewFactoryOptions = {}) {\n this.factory = new ViewFactory(options)\n\n return this.factory\n }\n\n static factoryInstance () {\n return this.factory\n }\n\n static make (name: ViewName, data: ViewData = {}): ViewInstance {\n return this.factory.make(name, data)\n }\n\n static first (names: ViewName[], data: ViewData = {}): ViewInstance {\n return this.factory.first(names, data)\n }\n\n static exists (name: ViewName) {\n return this.factory.exists(name)\n }\n\n static share (key: string, value: any): typeof View\n static share (data: ViewData): typeof View\n static share (...data: any[]) {\n if (typeof data[0] === 'string') {\n this.factory.share(data[0], data[1])\n } else {\n this.factory.share(data[0] ?? {})\n }\n\n return this\n }\n\n static composer (names: ViewComposerName, composer: ViewComposer): typeof View {\n this.factory.composer(names, composer)\n\n return this\n }\n\n static mount (viewsDirectory: string | URL): typeof View\n static mount (diskName: string, viewsDirectory: string | URL): typeof View\n static mount (diskName: string | URL, viewsDirectory?: string | URL) {\n if (viewsDirectory === undefined) {\n this.factory.mount(diskName)\n } else {\n this.factory.mount(diskName as string, viewsDirectory)\n }\n\n return this\n }\n\n static raw (name: ViewName, contents: string) {\n this.factory.raw(name, contents)\n\n return this\n }\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@arkstack/view",
3
+ "version": "0.4.0",
4
+ "type": "module",
5
+ "description": "View rendering package for Arkstack applications.",
6
+ "homepage": "https://arkstack.toneflix.net",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/arkstack-hq/arkstack.git",
10
+ "directory": "packages/view"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "types": "./dist/index.d.ts",
16
+ "main": "./dist/index.cjs",
17
+ "module": "./dist/index.js",
18
+ "exports": {
19
+ ".": {
20
+ "import": "./dist/index.js",
21
+ "require": "./dist/index.cjs"
22
+ },
23
+ "./commands/MakeViewCommand": {
24
+ "import": "./dist/commands/MakeViewCommand.js",
25
+ "require": "./dist/commands/MakeViewCommand.cjs"
26
+ },
27
+ "./package.json": "./package.json"
28
+ },
29
+ "keywords": [
30
+ "view",
31
+ "views",
32
+ "templates",
33
+ "edge",
34
+ "edge.js",
35
+ "arkstack"
36
+ ],
37
+ "files": [
38
+ "dist",
39
+ "resources"
40
+ ],
41
+ "dependencies": {
42
+ "edge.js": "^6.5.0"
43
+ },
44
+ "peerDependencies": {
45
+ "@h3ravel/musket": "^0.10.1",
46
+ "@arkstack/common": "^0.4.0"
47
+ },
48
+ "peerDependenciesMeta": {
49
+ "@h3ravel/musket": {
50
+ "optional": true
51
+ }
52
+ },
53
+ "scripts": {
54
+ "build": "tsdown --config-loader unconfig",
55
+ "test": "vitest",
56
+ "version:patch": "pnpm version patch"
57
+ }
58
+ }