@stacksjs/stx 0.2.181 → 0.2.182

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/seo.d.ts CHANGED
@@ -77,7 +77,19 @@ export declare function processSeoDirective(template: string, context: Record<st
77
77
  */
78
78
  export declare function injectSeoTags(html: string, context: Record<string, any>, options: StxOptions): string;
79
79
  /**
80
- * SEO meta directive for basic meta tag generation
80
+ * SEO meta directive.
81
+ *
82
+ * Stages the tag on the render's head rather than returning markup. A `<meta>`
83
+ * emitted where the directive happens to sit lands in the `<body>`, where no
84
+ * crawler reads it: the tag is present in the HTML, the page looks correct, and
85
+ * the description silently never applies. Staging it lets the document shell
86
+ * put it in `<head>`, which is the only place it means anything.
87
+ *
88
+ * This directive shadows `processMetaDirective` in head.ts, since custom
89
+ * directives run first. It therefore has to do that function's job, which is
90
+ * why it resolves unquoted arguments from the context and separates `property`
91
+ * from `name` here rather than leaving it to a later pass that will never see
92
+ * the directive.
81
93
  */
82
94
  export declare const metaDirective: CustomDirective;
83
95
  /**
package/dist/seo.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ErrorCodes, inlineError } from "./error-handling.js";
2
+ import { mergeHeadConfigs } from "./head.js";
2
3
  import { safeEvaluateObject } from "./safe-evaluator.js";
3
4
  export function processMetaDirectives(template, context, _filePath, _options) {
4
5
  let output = template;
@@ -309,13 +310,33 @@ ${seoTagsMinimal}
309
310
  function escapeHtml(str) {
310
311
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
311
312
  }
313
+ const PROPERTY_NAMESPACES = ["og:", "article:", "book:", "profile:", "fb:", "music:", "video:"];
314
+ function unquoteParam(raw) {
315
+ const text = raw.trim(), first = text[0];
316
+ if ((first === "'" || first === '"' || first === "`") && text.length > 1 && text.at(-1) === first)
317
+ return { value: text.slice(1, -1), quoted: !0 };
318
+ return { value: text, quoted: !1 };
319
+ }
312
320
  export const metaDirective = {
313
321
  name: "meta",
314
- handler: (_content, params, _context, _filePath) => {
322
+ handler: (_content, params, context, _filePath) => {
315
323
  if (params.length < 1)
316
324
  return inlineError("Meta", "meta directive requires at least the meta name", ErrorCodes.INVALID_DIRECTIVE_SYNTAX);
317
- const name = params[0].replace(/['"]/g, ""), metaContent = params.length > 1 ? params[1].replace(/['"]/g, "") : "";
318
- return `<meta name="${escapeHtml(name)}" content="${escapeHtml(metaContent)}">`;
325
+ const name = unquoteParam(params[0]).value;
326
+ let metaContent;
327
+ if (params.length > 1) {
328
+ const arg = unquoteParam(params[1]);
329
+ metaContent = arg.quoted ? arg.value : String(context?.[arg.value] ?? arg.value);
330
+ } else {
331
+ const segment = name.includes(":") ? name.slice(name.indexOf(":") + 1) : name, openGraph = context?.openGraph;
332
+ metaContent = String(context?.[segment] ?? openGraph?.[segment] ?? "");
333
+ }
334
+ if (!metaContent)
335
+ return "";
336
+ const tag = PROPERTY_NAMESPACES.some((prefix) => name.startsWith(prefix)) ? { property: name, content: metaContent } : { name, content: metaContent };
337
+ if (context)
338
+ context.__stx_runtime_head = mergeHeadConfigs(context.__stx_runtime_head ?? {}, { meta: [tag] });
339
+ return "";
319
340
  },
320
341
  hasEndTag: !1
321
342
  }, structuredDataDirective = {