@arkstack/view 0.15.2 → 0.15.4

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/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  /// <reference path="./app.d.ts" />
2
- import { t as clearRouterViewPlugin } from "./plugins-D3vyoc8i.js";
2
+ import { t as clearRouterViewPlugin } from "./plugins-Crhr7ifw.js";
3
3
  import edge, { Edge, Edge as Edge$1 } from "edge.js";
4
+ import { ParserTagDefinitionContract } from "edge.js/types";
4
5
 
5
6
  //#region src/ViewInstance.d.ts
6
7
  declare class ViewInstance implements PromiseLike<string> {
@@ -56,16 +57,109 @@ declare class ViewFactory {
56
57
  private mountedPackages;
57
58
  private packageViewsPath;
58
59
  constructor(options?: ViewFactoryOptions);
60
+ /**
61
+ * Create a new view instance for the given view name and data.
62
+ *
63
+ * @param name
64
+ * @param data
65
+ * @returns
66
+ */
59
67
  make(name: ViewName, data?: ViewData): ViewInstance;
68
+ /**
69
+ * Render the first view that exists from the given list of names.
70
+ *
71
+ * @param names
72
+ * @param data
73
+ * @returns
74
+ */
60
75
  first(names: ViewName[], data?: ViewData): ViewInstance;
76
+ /**
77
+ * Check if a view exists.
78
+ *
79
+ * @param name
80
+ * @returns
81
+ */
61
82
  exists(name: ViewName): boolean;
83
+ /**
84
+ * Share data with all views.
85
+ * This data will be available in every view rendered by the factory.
86
+ *
87
+ * @param key
88
+ * @param value
89
+ */
62
90
  share(key: string, value: any): this;
63
91
  share(data: ViewData): this;
92
+ /**
93
+ * Register a view composer for the given view name(s).
94
+ * A view composer is a function or object that is called when a view is
95
+ * rendered, allowing you to modify the view's data or perform other actions.
96
+ *
97
+ * @param names
98
+ * @param composer
99
+ * @returns
100
+ */
64
101
  composer(names: ViewComposerName, composer: ViewComposer): this;
102
+ /**
103
+ * Mount a directory containing views.
104
+ * If only one argument is provided, it will be treated as the views directory.
105
+ * If two arguments are provided, the first will be treated as the disk name and
106
+ * the second as the views directory.
107
+ *
108
+ * @param viewsDirectory
109
+ */
65
110
  mount(viewsDirectory: string | URL): this;
66
111
  mount(diskName: string, viewsDirectory: string | URL): this;
112
+ /**
113
+ * Register a raw template with the given name and contents.
114
+ *
115
+ * @param name
116
+ * @param contents
117
+ * @returns
118
+ */
67
119
  raw(name: ViewName, contents: string): this;
120
+ /**
121
+ * Register a custom tag with the given name, block type, seekable type,
122
+ * and compiler function.
123
+ *
124
+ * @param tagName
125
+ * @param block
126
+ * @param seekable
127
+ * @param compiler
128
+ */
129
+ tag(
130
+ /**
131
+ * The tag name
132
+ */
133
+
134
+ tagName: string,
135
+ /**
136
+ * Tag accepts content within the opening and
137
+ * closing tags
138
+ */
139
+
140
+ block: boolean,
141
+ /**
142
+ * Tag accepts parameters
143
+ */
144
+
145
+ seekable: boolean,
146
+ /**
147
+ * The parser needs the `compile` method on every tag
148
+ */
149
+
150
+ compiler: ParserTagDefinitionContract['compile']): void;
151
+ /**
152
+ * Flush all shared data. This will remove all data that has been shared with all views.
153
+ *
154
+ * @returns
155
+ */
68
156
  flushShared(): this;
157
+ /**
158
+ * Flush all registered composers. This will remove all composers that have
159
+ * been registered for any view.
160
+ *
161
+ * @returns
162
+ */
69
163
  flushComposers(): this;
70
164
  private getComposers;
71
165
  private runComposers;
@@ -138,6 +232,39 @@ type PackageViewReference = {
138
232
  declare const parsePackageViewName: (name: string) => PackageViewReference | null;
139
233
  declare const resolvePackageViewsPath: (nodePackageName: string, viewPath?: string) => string;
140
234
  //#endregion
235
+ //#region src/vite.d.ts
236
+ interface ViteTagOptions {
237
+ /** Force development (Vite dev server) tags regardless of `NODE_ENV`. */
238
+ hot?: boolean;
239
+ /** Vite dev server URL. Defaults to `VITE_DEV_URL` or `http://localhost:5173`. */
240
+ devUrl?: string;
241
+ /** Path to the Vite build manifest. Defaults to `public/build/.vite/manifest.json`. */
242
+ manifest?: string;
243
+ /** Public URL prefix the built assets are served from. Defaults to `/build/`. */
244
+ buildDir?: string;
245
+ }
246
+ /**
247
+ * Resolve `<script>`/`<link>` tags for one or more Vite entries.
248
+ *
249
+ * In development (when `NODE_ENV` is not `production`, or `hot` is set) it points
250
+ * at the Vite dev server and includes the `@vite/client`. In production it reads
251
+ * the build manifest and emits the hashed asset tags (including any CSS a chunk
252
+ * imports). Backs the `@vite(...)` Edge tag.
253
+ *
254
+ * @param entries
255
+ * @param options
256
+ * @returns
257
+ */
258
+ declare const viteTags: (entries: string | string[], options?: ViteTagOptions) => string;
259
+ /**
260
+ * Register the `@vite(...)` tag (and its backing global) on a view factory so
261
+ * templates can emit Vite asset tags: `@vite('resources/js/app.ts')` or
262
+ * `@vite(['resources/css/app.css', 'resources/js/app.ts'])`.
263
+ *
264
+ * @param factory
265
+ */
266
+ declare const registerViteTag: (factory: ViewFactory) => void;
267
+ //#endregion
141
268
  //#region src/viewContext.d.ts
142
269
  declare const getViewData: () => ViewData;
143
270
  declare const enterViewData: (data?: ViewData) => void;
@@ -145,4 +272,4 @@ declare const runWithViewData: <T>(data: ViewData, callback: () => T | Promise<T
145
272
  declare const clearViewData: () => void;
146
273
  declare const collectViewData: (context: Record<string, any>) => ViewData;
147
274
  //#endregion
148
- export { ComposerRunner, Edge, SyncComposerRunner, View, ViewComposer, ViewComposerClass, ViewComposerHandler, ViewComposerName, ViewComposerObject, ViewData, ViewErrorBag, ViewErrorRecord, ViewErrorValue, ViewFactory, ViewFactoryOptions, ViewInstance, ViewName, clearRouterViewPlugin, clearViewData, collectViewData, edge, enterViewData, getViewData, normalizeViewErrors, parsePackageViewName, resolvePackageViewsPath, runWithViewData, view };
275
+ export { type ComposerRunner, Edge, type SyncComposerRunner, View, type ViewComposer, type ViewComposerClass, type ViewComposerHandler, type ViewComposerName, type ViewComposerObject, type ViewData, ViewErrorBag, type ViewErrorRecord, type ViewErrorValue, ViewFactory, type ViewFactoryOptions, ViewInstance, type ViewName, type ViteTagOptions, clearRouterViewPlugin, clearViewData, collectViewData, edge, enterViewData, getViewData, normalizeViewErrors, parsePackageViewName, registerViteTag, resolvePackageViewsPath, runWithViewData, view, viteTags };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import { a as collectViewData, c as runWithViewData, d as resolvePackageViewsPath, f as view, i as clearViewData, l as ViewInstance, m as normalizeViewErrors, n as View, o as enterViewData, p as ViewErrorBag, r as ViewFactory, s as getViewData, t as clearRouterViewPlugin, u as parsePackageViewName } from "./plugins-BFBs38yL.js";
1
+ import { a as viteTags, c as enterViewData, d as ViewInstance, f as parsePackageViewName, g as normalizeViewErrors, h as ViewErrorBag, i as registerViteTag, l as getViewData, m as view, n as View, o as clearViewData, p as resolvePackageViewsPath, r as ViewFactory, s as collectViewData, t as clearRouterViewPlugin, u as runWithViewData } from "./plugins-DWO_aTcP.js";
2
2
  import edge, { Edge } from "edge.js";
3
- export { Edge, View, ViewErrorBag, ViewFactory, ViewInstance, clearRouterViewPlugin, clearViewData, collectViewData, edge, enterViewData, getViewData, normalizeViewErrors, parsePackageViewName, resolvePackageViewsPath, runWithViewData, view };
3
+ export { Edge, View, ViewErrorBag, ViewFactory, ViewInstance, clearRouterViewPlugin, clearViewData, collectViewData, edge, enterViewData, getViewData, normalizeViewErrors, parsePackageViewName, registerViteTag, resolvePackageViewsPath, runWithViewData, view, viteTags };
@@ -0,0 +1,4 @@
1
+ //#region src/plugins.d.ts
2
+ declare const clearRouterViewPlugin: import("clear-router/core").ClearRouterPlugin<any, any>;
3
+ //#endregion
4
+ export { clearRouterViewPlugin as t };
@@ -1,7 +1,7 @@
1
- import { isClass } from "@arkstack/common";
1
+ import { env, isClass, nodeEnv } from "@arkstack/common";
2
2
  import { Arkstack } from "@arkstack/contract";
3
- import { existsSync } from "node:fs";
4
- import { resolve } from "node:path";
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import { join, resolve } from "node:path";
5
5
  import { Edge } from "edge.js";
6
6
  import { AsyncLocalStorage } from "node:async_hooks";
7
7
  import { Hook } from "@arkstack/foundry";
@@ -306,6 +306,66 @@ const collectViewData = (context) => {
306
306
  });
307
307
  };
308
308
  //#endregion
309
+ //#region src/vite.ts
310
+ const scriptTag = (src) => `<script type="module" src="${src}"><\/script>`;
311
+ const styleTag = (href) => `<link rel="stylesheet" href="${href}">`;
312
+ const isCss = (entry) => /\.(css|scss|sass|less|styl|pcss)$/.test(entry);
313
+ const trimTrailingSlash = (value) => value.replace(/\/+$/, "");
314
+ const withTrailingSlash = (value) => `${trimTrailingSlash(value)}/`;
315
+ const devTags = (entries, devUrl) => {
316
+ const base = trimTrailingSlash(devUrl);
317
+ return [scriptTag(`${base}/@vite/client`), ...entries.map((entry) => scriptTag(`${base}/${entry.replace(/^\/+/, "")}`))].join("\n");
318
+ };
319
+ const productionTags = (entries, manifestPath, buildDir) => {
320
+ let manifest;
321
+ try {
322
+ manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
323
+ } catch {
324
+ throw new Error(`Vite manifest not found at ${manifestPath}. Run \`vite build\` before serving in production.`);
325
+ }
326
+ const base = withTrailingSlash(buildDir);
327
+ const tags = [];
328
+ for (const entry of entries) {
329
+ const chunk = manifest[entry];
330
+ if (!chunk) throw new Error(`Vite manifest (${manifestPath}) has no entry for "${entry}".`);
331
+ for (const css of chunk.css ?? []) tags.push(styleTag(`${base}${css}`));
332
+ tags.push(isCss(entry) ? styleTag(`${base}${chunk.file}`) : scriptTag(`${base}${chunk.file}`));
333
+ }
334
+ return tags.join("\n");
335
+ };
336
+ /**
337
+ * Resolve `<script>`/`<link>` tags for one or more Vite entries.
338
+ *
339
+ * In development (when `NODE_ENV` is not `production`, or `hot` is set) it points
340
+ * at the Vite dev server and includes the `@vite/client`. In production it reads
341
+ * the build manifest and emits the hashed asset tags (including any CSS a chunk
342
+ * imports). Backs the `@vite(...)` Edge tag.
343
+ *
344
+ * @param entries
345
+ * @param options
346
+ * @returns
347
+ */
348
+ const viteTags = (entries, options = {}) => {
349
+ const list = (Array.isArray(entries) ? entries : [entries]).filter(Boolean);
350
+ if (options.hot ?? nodeEnv() !== "prod") return devTags(list, options.devUrl ?? env("VITE_DEV_URL", "http://localhost:5173"));
351
+ return productionTags(list, options.manifest ?? join(Arkstack.rootDir(), "public", "build", ".vite", "manifest.json"), options.buildDir ?? "/build/");
352
+ };
353
+ /**
354
+ * Register the `@vite(...)` tag (and its backing global) on a view factory so
355
+ * templates can emit Vite asset tags: `@vite('resources/js/app.ts')` or
356
+ * `@vite(['resources/css/app.css', 'resources/js/app.ts'])`.
357
+ *
358
+ * @param factory
359
+ */
360
+ const registerViteTag = (factory) => {
361
+ factory.edge.global("__arkViteTags", (entries, options) => viteTags(entries, options));
362
+ factory.tag("vite", false, true, (parser, buffer, token) => {
363
+ const expression = `__arkViteTags(${token.properties.jsArg})`;
364
+ const ast = parser.utils.transformAst(parser.utils.generateAST(expression, token.loc, token.filename), token.filename, parser);
365
+ buffer.outputExpression(parser.utils.stringify(ast), token.filename, token.loc.start.line, false);
366
+ });
367
+ };
368
+ //#endregion
309
369
  //#region src/ViewFactory.ts
310
370
  var ViewFactory = class {
311
371
  edge;
@@ -317,7 +377,15 @@ var ViewFactory = class {
317
377
  this.edge = options.edge ?? Edge.create({ cache: options.cache });
318
378
  this.packageViewsPath = options.packageViewsPath ?? "resources/views";
319
379
  this.mount(options.viewsPath ?? resolve(Arkstack.rootDir(), "src", "resources", "views"));
380
+ registerViteTag(this);
320
381
  }
382
+ /**
383
+ * Create a new view instance for the given view name and data.
384
+ *
385
+ * @param name
386
+ * @param data
387
+ * @returns
388
+ */
321
389
  make(name, data = {}) {
322
390
  const edgeName = this.resolveName(name);
323
391
  return new ViewInstance(name, normalizeViewData({
@@ -326,11 +394,24 @@ var ViewFactory = class {
326
394
  ...data
327
395
  }), this.edge, async (view) => await this.runComposers(name, view), (view) => this.runComposersSync(name, view), edgeName);
328
396
  }
397
+ /**
398
+ * Render the first view that exists from the given list of names.
399
+ *
400
+ * @param names
401
+ * @param data
402
+ * @returns
403
+ */
329
404
  first(names, data = {}) {
330
405
  const name = names.find((candidate) => this.exists(candidate));
331
406
  if (!name) throw new Error(`None of the given views exist: ${names.join(", ")}`);
332
407
  return this.make(name, data);
333
408
  }
409
+ /**
410
+ * Check if a view exists.
411
+ *
412
+ * @param name
413
+ * @returns
414
+ */
334
415
  exists(name) {
335
416
  const edgeName = this.resolveName(name);
336
417
  if (this.edge.loader.templates[edgeName]) return true;
@@ -344,6 +425,15 @@ var ViewFactory = class {
344
425
  mergeData(this.sharedData, data);
345
426
  return this;
346
427
  }
428
+ /**
429
+ * Register a view composer for the given view name(s).
430
+ * A view composer is a function or object that is called when a view is
431
+ * rendered, allowing you to modify the view's data or perform other actions.
432
+ *
433
+ * @param names
434
+ * @param composer
435
+ * @returns
436
+ */
347
437
  composer(names, composer) {
348
438
  for (const name of Array.isArray(names) ? names : [names]) this.composers.set(name, [...this.composers.get(name) ?? [], composer]);
349
439
  return this;
@@ -356,14 +446,50 @@ var ViewFactory = class {
356
446
  this.edge.mount(diskName, viewsDirectory);
357
447
  return this;
358
448
  }
449
+ /**
450
+ * Register a raw template with the given name and contents.
451
+ *
452
+ * @param name
453
+ * @param contents
454
+ * @returns
455
+ */
359
456
  raw(name, contents) {
360
457
  this.edge.registerTemplate(name, { template: contents });
361
458
  return this;
362
459
  }
460
+ /**
461
+ * Register a custom tag with the given name, block type, seekable type,
462
+ * and compiler function.
463
+ *
464
+ * @param tagName
465
+ * @param block
466
+ * @param seekable
467
+ * @param compiler
468
+ */
469
+ tag(tagName, block, seekable, compiler) {
470
+ const tag = {
471
+ block,
472
+ seekable,
473
+ tagName,
474
+ compile: compiler
475
+ };
476
+ this.edge.registerTag(tag);
477
+ }
478
+ /**
479
+ * Flush all shared data. This will remove all data that has been shared with all views.
480
+ *
481
+ * @returns
482
+ */
363
483
  flushShared() {
364
484
  this.sharedData = {};
365
485
  return this;
366
486
  }
487
+ /**
488
+ * Flush all registered composers. This will remove all composers that have
489
+ * been registered for any view.
490
+ *
491
+ * @returns
492
+ */
367
493
  flushComposers() {
368
494
  this.composers.clear();
369
495
  return this;
@@ -462,4 +588,4 @@ const clearRouterViewPlugin = definePlugin({
462
588
  }
463
589
  });
464
590
  //#endregion
465
- export { collectViewData as a, runWithViewData as c, resolvePackageViewsPath as d, view as f, clearViewData as i, ViewInstance as l, normalizeViewErrors as m, View as n, enterViewData as o, ViewErrorBag as p, ViewFactory as r, getViewData as s, clearRouterViewPlugin as t, parsePackageViewName as u };
591
+ export { viteTags as a, enterViewData as c, ViewInstance as d, parsePackageViewName as f, normalizeViewErrors as g, ViewErrorBag as h, registerViteTag as i, getViewData as l, view as m, View as n, clearViewData as o, resolvePackageViewsPath as p, ViewFactory as r, collectViewData as s, clearRouterViewPlugin as t, runWithViewData as u };
package/dist/setup.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { t as clearRouterViewPlugin } from "./plugins-D3vyoc8i.js";
1
+ import { t as clearRouterViewPlugin } from "./plugins-Crhr7ifw.js";
2
2
  export { clearRouterViewPlugin };
package/dist/setup.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as clearRouterViewPlugin } from "./plugins-BFBs38yL.js";
1
+ import { t as clearRouterViewPlugin } from "./plugins-DWO_aTcP.js";
2
2
  import { CoreRouter } from "clear-router/core";
3
3
  //#region src/setup.ts
4
4
  CoreRouter.use(clearRouterViewPlugin);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkstack/view",
3
- "version": "0.15.2",
3
+ "version": "0.15.4",
4
4
  "type": "module",
5
5
  "description": "View module for Arkstack, providing template rendering and view integration utilities.",
6
6
  "homepage": "https://arkstack.toneflix.net/guide/views",
@@ -33,13 +33,13 @@
33
33
  ],
34
34
  "dependencies": {
35
35
  "edge.js": "^6.5.0",
36
- "@arkstack/contract": "^0.15.2"
36
+ "@arkstack/contract": "^0.15.4"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@h3ravel/musket": "^2.2.1",
40
40
  "clear-router": "^2.9.0",
41
- "@arkstack/foundry": "^0.15.2",
42
- "@arkstack/common": "^0.15.2"
41
+ "@arkstack/common": "^0.15.4",
42
+ "@arkstack/foundry": "^0.15.4"
43
43
  },
44
44
  "peerDependenciesMeta": {
45
45
  "@h3ravel/musket": {
@@ -1,6 +0,0 @@
1
- import * as _$clear_router_core0 from "clear-router/core";
2
-
3
- //#region src/plugins.d.ts
4
- declare const clearRouterViewPlugin: _$clear_router_core0.ClearRouterPlugin<any, any>;
5
- //#endregion
6
- export { clearRouterViewPlugin as t };