@xylabs/sdk-meta 5.1.1 → 5.1.3

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.
@@ -90,4 +90,4 @@ export {
90
90
  mergeDocumentHead,
91
91
  metaBuilder
92
92
  };
93
- //# sourceMappingURL=index.mjs.map
93
+ //# sourceMappingURL=index.mjs.map
@@ -1 +1,7 @@
1
- {"version":3,"sources":["../../src/html/mergeDocumentHead.ts","../../src/lib/getMetaAsDict.ts","../../src/meta/builder.ts"],"sourcesContent":["import { isString } from '@xylabs/typeof'\nimport { load } from 'cheerio'\n\nconst opts = {}\n// const opts = { decodeEntities: false }\n\n/**\n * Merges meta tags from the source HTML head into the destination HTML head.\n * Existing meta tags with matching property attributes are replaced; others are appended.\n * @param destination - The base HTML string to merge into.\n * @param source - The HTML string whose head meta tags will be merged.\n * @returns The merged HTML string.\n */\nexport const mergeDocumentHead = (destination: string, source: string) => {\n const $destination = load(destination, opts)\n const $source = load(source, opts)\n\n // For each child node of the source head\n $source('head')\n .children()\n .each((_, element) => {\n const el = $destination(element)\n\n // Special case for meta tags: We want to match them by the name attribute\n if (el[0].tagName === 'meta') {\n const property = el.attr('property')\n if (isString(property)) {\n const match = $destination(`head meta[property=\"${property}\"]`)\n\n // If it exists, replace it, otherwise append it\n if (match.length > 0) {\n match.replaceWith(el)\n return\n } else {\n $destination('head').append(el)\n }\n }\n // else {\n // // For all other elements, just check if the same element exists in the first HTML string\n // const match = $destination(el[0].tagName)\n\n // // If it exists, replace it, otherwise append it\n // if (match.length > 0) {\n // match.replaceWith(el)\n // } else {\n // $destination('head').append(el)\n // }\n // }\n }\n })\n\n // Return the merged HTML\n return $destination.html(opts)\n}\n","import { isString } from '@xylabs/typeof'\n\n/** An object with string keys and arbitrary values, used for recursive meta flattening. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type StringIndexable = Record<string, any>\n\nconst propertyDelimiter = ':'\n\n/**\n * Recursively flattens a nested meta object into a flat dictionary with colon-delimited keys.\n * @param obj - The nested object to flatten.\n * @param parentKey - The accumulated key prefix from parent levels.\n * @returns A flat record mapping colon-delimited property names to string values.\n */\nexport const getMetaAsDict = (obj: StringIndexable, parentKey?: string): Record<string, string> => {\n let flatRecord: StringIndexable = {}\n for (const key in obj) {\n if (typeof obj[key] === 'object' && obj[key] !== null) {\n // If the value is another object, we want to iterate through its keys as well.\n const childRecord = getMetaAsDict(obj[key] as StringIndexable, `${isString(parentKey) ? parentKey : ''}${key}${propertyDelimiter}`)\n flatRecord = { ...flatRecord, ...childRecord }\n } else {\n // Concatenate the key with its parent key.\n const newKey = isString(parentKey) ? `${parentKey}${key}` : key\n const trimmed = newKey.endsWith(propertyDelimiter) ? newKey.slice(0, -1) : newKey\n flatRecord[trimmed] = `${obj[key]}`\n }\n }\n return flatRecord\n}\n","import { isString } from '@xylabs/typeof'\nimport type { CheerioAPI } from 'cheerio'\nimport { load } from 'cheerio'\n\nimport { getMetaAsDict } from '../lib/index.ts'\nimport type { Meta } from '../models/index.ts'\n\n/* test change */\n\n/**\n * Adds or replaces a meta tag in the document head.\n * @param $ - The Cheerio API instance for the document.\n * @param name - The meta property name.\n * @param value - The meta content value (string, array, or nested object).\n */\nexport const addMetaToHead = ($: CheerioAPI, name: string, value: string | object) => {\n if (typeof value === 'string') {\n const newMeta = `<meta property=\"${name}\" content=\"${value}\" />`\n const existingMeta = $(`head meta[property=\"${name}\"]`)\n if ((existingMeta?.length ?? 0) > 0) {\n existingMeta.replaceWith(newMeta)\n } else {\n $('head').append(newMeta)\n }\n } else if (Array.isArray(value)) {\n for (const item of value) addMetaToHead($, `${name}`, item)\n } else if (typeof value === 'object') {\n for (const [key, v] of Object.entries(value)) {\n if (key === 'url') {\n addMetaToHead($, name, v)\n } else {\n addMetaToHead($, `${name}:${key}`, v)\n }\n }\n } else {\n throw new TypeError(`Invalid item type [${name}, ${typeof value}]`)\n }\n}\n\n/**\n * Injects meta properties, title, and description into an HTML string.\n * @param html - The base HTML string to modify.\n * @param meta - The metadata to inject.\n * @param handler - Optional meta-handler property value to include.\n * @returns The modified HTML string with injected metadata.\n */\nexport const metaBuilder = (html: string, meta: Meta, handler?: string) => {\n const $ = load(html)\n // NOTE: This assumes unique meta properties (no duplicates)\n // which is generally the case, but not always (you can have\n // multiple og:video:tag tags, for example)\n const metaProperties = getMetaAsDict(meta)\n for (const [key, value] of Object.entries(metaProperties)) {\n addMetaToHead($, key, value)\n }\n if (isString(meta.description)) {\n addMetaToHead($, 'description', meta.description)\n }\n if (isString(meta.title)) {\n $('title').text(meta.title)\n }\n if (isString(handler)) {\n addMetaToHead($, 'meta-handler', handler)\n }\n return $.html()\n}\n"],"mappings":"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","names":["isString","isString","load","load","isString"]}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/html/mergeDocumentHead.ts", "../../src/lib/getMetaAsDict.ts", "../../src/meta/builder.ts"],
4
+ "sourcesContent": ["import { isString } from '@xylabs/typeof'\nimport { load } from 'cheerio'\n\nconst opts = {}\n// const opts = { decodeEntities: false }\n\n/**\n * Merges meta tags from the source HTML head into the destination HTML head.\n * Existing meta tags with matching property attributes are replaced; others are appended.\n * @param destination - The base HTML string to merge into.\n * @param source - The HTML string whose head meta tags will be merged.\n * @returns The merged HTML string.\n */\nexport const mergeDocumentHead = (destination: string, source: string) => {\n const $destination = load(destination, opts)\n const $source = load(source, opts)\n\n // For each child node of the source head\n $source('head')\n .children()\n .each((_, element) => {\n const el = $destination(element)\n\n // Special case for meta tags: We want to match them by the name attribute\n if (el[0].tagName === 'meta') {\n const property = el.attr('property')\n if (isString(property)) {\n const match = $destination(`head meta[property=\"${property}\"]`)\n\n // If it exists, replace it, otherwise append it\n if (match.length > 0) {\n match.replaceWith(el)\n return\n } else {\n $destination('head').append(el)\n }\n }\n // else {\n // // For all other elements, just check if the same element exists in the first HTML string\n // const match = $destination(el[0].tagName)\n\n // // If it exists, replace it, otherwise append it\n // if (match.length > 0) {\n // match.replaceWith(el)\n // } else {\n // $destination('head').append(el)\n // }\n // }\n }\n })\n\n // Return the merged HTML\n return $destination.html(opts)\n}\n", "import { isString } from '@xylabs/typeof'\n\n/** An object with string keys and arbitrary values, used for recursive meta flattening. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type StringIndexable = Record<string, any>\n\nconst propertyDelimiter = ':'\n\n/**\n * Recursively flattens a nested meta object into a flat dictionary with colon-delimited keys.\n * @param obj - The nested object to flatten.\n * @param parentKey - The accumulated key prefix from parent levels.\n * @returns A flat record mapping colon-delimited property names to string values.\n */\nexport const getMetaAsDict = (obj: StringIndexable, parentKey?: string): Record<string, string> => {\n let flatRecord: StringIndexable = {}\n for (const key in obj) {\n if (typeof obj[key] === 'object' && obj[key] !== null) {\n // If the value is another object, we want to iterate through its keys as well.\n const childRecord = getMetaAsDict(obj[key] as StringIndexable, `${isString(parentKey) ? parentKey : ''}${key}${propertyDelimiter}`)\n flatRecord = { ...flatRecord, ...childRecord }\n } else {\n // Concatenate the key with its parent key.\n const newKey = isString(parentKey) ? `${parentKey}${key}` : key\n const trimmed = newKey.endsWith(propertyDelimiter) ? newKey.slice(0, -1) : newKey\n flatRecord[trimmed] = `${obj[key]}`\n }\n }\n return flatRecord\n}\n", "import { isString } from '@xylabs/typeof'\nimport type { CheerioAPI } from 'cheerio'\nimport { load } from 'cheerio'\n\nimport { getMetaAsDict } from '../lib/index.ts'\nimport type { Meta } from '../models/index.ts'\n\n/* test change */\n\n/**\n * Adds or replaces a meta tag in the document head.\n * @param $ - The Cheerio API instance for the document.\n * @param name - The meta property name.\n * @param value - The meta content value (string, array, or nested object).\n */\nexport const addMetaToHead = ($: CheerioAPI, name: string, value: string | object) => {\n if (typeof value === 'string') {\n const newMeta = `<meta property=\"${name}\" content=\"${value}\" />`\n const existingMeta = $(`head meta[property=\"${name}\"]`)\n if ((existingMeta?.length ?? 0) > 0) {\n existingMeta.replaceWith(newMeta)\n } else {\n $('head').append(newMeta)\n }\n } else if (Array.isArray(value)) {\n for (const item of value) addMetaToHead($, `${name}`, item)\n } else if (typeof value === 'object') {\n for (const [key, v] of Object.entries(value)) {\n if (key === 'url') {\n addMetaToHead($, name, v)\n } else {\n addMetaToHead($, `${name}:${key}`, v)\n }\n }\n } else {\n throw new TypeError(`Invalid item type [${name}, ${typeof value}]`)\n }\n}\n\n/**\n * Injects meta properties, title, and description into an HTML string.\n * @param html - The base HTML string to modify.\n * @param meta - The metadata to inject.\n * @param handler - Optional meta-handler property value to include.\n * @returns The modified HTML string with injected metadata.\n */\nexport const metaBuilder = (html: string, meta: Meta, handler?: string) => {\n const $ = load(html)\n // NOTE: This assumes unique meta properties (no duplicates)\n // which is generally the case, but not always (you can have\n // multiple og:video:tag tags, for example)\n const metaProperties = getMetaAsDict(meta)\n for (const [key, value] of Object.entries(metaProperties)) {\n addMetaToHead($, key, value)\n }\n if (isString(meta.description)) {\n addMetaToHead($, 'description', meta.description)\n }\n if (isString(meta.title)) {\n $('title').text(meta.title)\n }\n if (isString(handler)) {\n addMetaToHead($, 'meta-handler', handler)\n }\n return $.html()\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["isString", "isString", "load", "load", "isString"]
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xylabs/sdk-meta",
3
- "version": "5.1.1",
3
+ "version": "5.1.3",
4
4
  "description": "Base functionality used throughout XYO TypeScript/JavaScript libraries",
5
5
  "keywords": [
6
6
  "meta",
@@ -36,19 +36,20 @@
36
36
  "README.md"
37
37
  ],
38
38
  "dependencies": {
39
- "@xylabs/typeof": "~5.1.1"
39
+ "@xylabs/typeof": "~5.1.3"
40
40
  },
41
41
  "devDependencies": {
42
- "@xylabs/toolchain": "~7.13.2",
43
- "@xylabs/tsconfig": "~7.13.2",
42
+ "@types/node": "^25.8.0",
43
+ "@xylabs/toolchain": "~8.0.4",
44
+ "@xylabs/tsconfig": "~8.0.4",
44
45
  "cheerio": "~1.2.0",
45
46
  "eslint": "^10.3.0",
46
- "typescript": "^5.9.3",
47
- "vite": "^8.0.10",
48
- "vitest": "^4.1.5"
47
+ "typescript": "^6.0.3",
48
+ "vite": "^8.0.13",
49
+ "vitest": "^4.1.6"
49
50
  },
50
51
  "peerDependencies": {
51
- "cheerio": ">=1.2.0 <1.3"
52
+ "cheerio": "~1.2"
52
53
  },
53
54
  "engines": {
54
55
  "node": ">=18"