@unhead/shared 1.7.3 → 1.8.0-beta.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.
Files changed (3) hide show
  1. package/dist/index.cjs +55 -129
  2. package/dist/index.mjs +55 -129
  3. package/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -191,16 +191,10 @@ const MetaPackingSchema = {
191
191
  }
192
192
  }
193
193
  },
194
- articleAuthor: p("article:author"),
195
194
  articleExpirationTime: p("article:expiration_time"),
196
195
  articleModifiedTime: p("article:modified_time"),
197
196
  articlePublishedTime: p("article:published_time"),
198
- articleSection: p("article:section"),
199
- articleTag: p("article:tag"),
200
- bookAuthor: p("book:author"),
201
- bookIsbn: p("book:isbn"),
202
197
  bookReleaseDate: p("book:release_date"),
203
- bookTag: p("book:tag"),
204
198
  charset: {
205
199
  metaKey: "charset"
206
200
  },
@@ -224,32 +218,13 @@ const MetaPackingSchema = {
224
218
  msapplicationTileColor: k("msapplication-TileColor"),
225
219
  msapplicationTileImage: k("msapplication-TileImage"),
226
220
  ogAudioSecureUrl: p("og:audio:secure_url"),
227
- ogAudioType: p("og:audio:type"),
228
221
  ogAudioUrl: p("og:audio"),
229
- ogDescription: p("og:description"),
230
- ogDeterminer: p("og:determiner"),
231
- ogImage: p("og:image"),
232
- ogImageAlt: p("og:image:alt"),
233
- ogImageHeight: p("og:image:height"),
234
222
  ogImageSecureUrl: p("og:image:secure_url"),
235
- ogImageType: p("og:image:type"),
236
223
  ogImageUrl: p("og:image"),
237
- ogImageWidth: p("og:image:width"),
238
- ogLocale: p("og:locale"),
239
- ogLocaleAlternate: p("og:locale:alternate"),
240
224
  ogSiteName: p("og:site_name"),
241
- ogTitle: p("og:title"),
242
- ogType: p("og:type"),
243
- ogUrl: p("og:url"),
244
- ogVideo: p("og:video"),
245
- ogVideoAlt: p("og:video:alt"),
246
- ogVideoHeight: p("og:video:height"),
247
225
  ogVideoSecureUrl: p("og:video:secure_url"),
248
- ogVideoType: p("og:video:type"),
249
226
  ogVideoUrl: p("og:video"),
250
- ogVideoWidth: p("og:video:width"),
251
227
  profileFirstName: p("profile:first_name"),
252
- profileGender: p("profile:gender"),
253
228
  profileLastName: p("profile:last_name"),
254
229
  profileUsername: p("profile:username"),
255
230
  refresh: {
@@ -274,51 +249,31 @@ const MetaPackingSchema = {
274
249
  }
275
250
  }
276
251
  },
277
- twitterAppIdGoogleplay: k("twitter:app:id:googleplay"),
278
- twitterAppIdIpad: k("twitter:app:id:ipad"),
279
- twitterAppIdIphone: k("twitter:app:id:iphone"),
280
- twitterAppNameGoogleplay: k("twitter:app:name:googleplay"),
281
- twitterAppNameIpad: k("twitter:app:name:ipad"),
282
- twitterAppNameIphone: k("twitter:app:name:iphone"),
283
- twitterAppUrlGoogleplay: k("twitter:app:url:googleplay"),
284
- twitterAppUrlIpad: k("twitter:app:url:ipad"),
285
- twitterAppUrlIphone: k("twitter:app:url:iphone"),
286
- twitterCard: k("twitter:card"),
287
- twitterCreator: k("twitter:creator"),
288
- twitterCreatorId: k("twitter:creator:id"),
289
- twitterData1: k("twitter:data1"),
290
- twitterData2: k("twitter:data2"),
291
- twitterDescription: k("twitter:description"),
292
- twitterImage: k("twitter:image"),
293
- twitterImageAlt: k("twitter:image:alt"),
294
- /*************************************************/
295
- // not part of Twitter's card specification anymore
296
- twitterImageHeight: k("twitter:image:height"),
297
- twitterImageType: k("twitter:image:type"),
298
- twitterImageUrl: k("twitter:image"),
299
- twitterImageWidth: k("twitter:image:width"),
300
- /**************************************************/
301
- twitterLabel1: k("twitter:label1"),
302
- twitterLabel2: k("twitter:label2"),
303
- twitterPlayer: k("twitter:player"),
304
- twitterPlayerHeight: k("twitter:player:height"),
305
- twitterPlayerStream: k("twitter:player:stream"),
306
- twitterPlayerWidth: k("twitter:player:width"),
307
- twitterSite: k("twitter:site"),
308
- twitterSiteId: k("twitter:site:id"),
309
- twitterTitle: k("twitter:title"),
310
252
  xUaCompatible: {
311
253
  metaKey: "http-equiv"
312
254
  }
313
255
  };
256
+ const openGraphNamespaces = [
257
+ "og",
258
+ "book",
259
+ "article",
260
+ "profile"
261
+ ];
314
262
  function resolveMetaKeyType(key) {
263
+ const fKey = fixKeyCase(key).split(":")[0];
264
+ if (openGraphNamespaces.includes(fKey))
265
+ return "property";
315
266
  return MetaPackingSchema[key]?.metaKey || "name";
316
267
  }
317
268
  function resolveMetaKeyValue(key) {
318
269
  return MetaPackingSchema[key]?.keyValue || fixKeyCase(key);
319
270
  }
320
271
  function fixKeyCase(key) {
321
- return key.replace(/([A-Z])/g, "-$1").toLowerCase();
272
+ const updated = key.replace(/([A-Z])/g, "-$1").toLowerCase();
273
+ const fKey = updated.split("-")[0];
274
+ if (openGraphNamespaces.includes(fKey) || fKey === "twitter")
275
+ return key.replace(/([A-Z])/g, ":$1").toLowerCase();
276
+ return updated;
322
277
  }
323
278
  function changeKeyCasingDeep(input) {
324
279
  if (Array.isArray(input)) {
@@ -349,82 +304,49 @@ function resolvePackedMetaObjectValue(value, key) {
349
304
  }
350
305
  );
351
306
  }
352
- const SimpleArrayUnpackMetas = ["themeColor"];
353
- function getMeta(key, value) {
354
- const meta = {};
355
- const metaKeyType = resolveMetaKeyType(key);
356
- if (metaKeyType === "charset") {
357
- meta[metaKeyType] = value;
358
- } else {
359
- meta[metaKeyType] = resolveMetaKeyValue(key);
360
- meta.content = value;
361
- }
362
- return meta;
307
+ const ObjectArrayEntries = ["og:image", "og:video", "og:audio", "twitter:image"];
308
+ function sanitize(input) {
309
+ const out = {};
310
+ Object.entries(input).forEach(([k2, v]) => {
311
+ if (String(v) !== "false" && k2)
312
+ out[k2] = v;
313
+ });
314
+ return out;
363
315
  }
364
- function flattenMetaObjects(input, prefix = "") {
365
- const extras = [];
366
- for (const [k2, v] of Object.entries(input)) {
367
- const key = k2;
368
- const value = v;
369
- const fullkey = `${prefix}${prefix === "" ? key : key.charAt(0).toUpperCase() + key.slice(1)}`;
370
- const unpacker = MetaPackingSchema[key]?.unpack;
371
- if (unpacker) {
372
- extras.push(getMeta(fullkey, unpackToString(value, unpacker)));
373
- delete input[key];
374
- continue;
375
- }
376
- if (!value) {
377
- extras.push(getMeta(fullkey, value));
378
- delete input[key];
379
- continue;
380
- }
381
- if (typeof value === "object") {
382
- const children = Array.isArray(value) ? value : [value];
383
- for (const child of children) {
384
- if (!child)
385
- extras.push(getMeta(fullkey, child));
386
- else if (typeof child === "object")
387
- extras.push(...flattenMetaObjects(child, fullkey));
388
- else
389
- extras.push(getMeta(fullkey, child));
390
- }
391
- delete input[key];
392
- } else {
393
- extras.push(getMeta(fullkey, value));
394
- if (typeof input === "object")
395
- delete input[key];
396
- }
316
+ function handleObjectEntry(key, v) {
317
+ const value = sanitize(v);
318
+ const fKey = fixKeyCase(key);
319
+ const attr = resolveMetaKeyType(fKey);
320
+ if (ObjectArrayEntries.includes(fKey)) {
321
+ const input = {};
322
+ Object.entries(value).forEach(([k2, v2]) => {
323
+ input[`${key}${k2 === "url" ? "" : `${k2.charAt(0).toUpperCase()}${k2.slice(1)}`}`] = v2;
324
+ });
325
+ return unpackMeta(input).sort((a, b) => (a[attr]?.length || 0) - (b[attr]?.length || 0));
397
326
  }
398
- return extras;
327
+ return [{ [attr]: fKey, ...value }];
399
328
  }
400
329
  function unpackMeta(input) {
401
330
  const extras = [];
402
- SimpleArrayUnpackMetas.forEach((meta2) => {
403
- if (input[meta2] && typeof input[meta2] !== "string") {
404
- const val = Array.isArray(input[meta2]) ? input[meta2] : [input[meta2]];
405
- delete input[meta2];
406
- val.forEach((entry) => {
407
- extras.push({
408
- name: fixKeyCase(meta2),
409
- ...entry
410
- });
411
- });
331
+ const primitives = {};
332
+ Object.entries(input).forEach(([key, value]) => {
333
+ if (!Array.isArray(value)) {
334
+ if (typeof value === "object" && value) {
335
+ if (ObjectArrayEntries.includes(fixKeyCase(key))) {
336
+ extras.push(...handleObjectEntry(key, value));
337
+ return;
338
+ }
339
+ primitives[key] = sanitize(value);
340
+ } else {
341
+ primitives[key] = value;
342
+ }
343
+ return;
412
344
  }
345
+ value.forEach((v) => {
346
+ extras.push(...typeof v === "string" ? unpackMeta({ [key]: v }) : handleObjectEntry(key, v));
347
+ });
413
348
  });
414
- extras.push(
415
- ...flattenMetaObjects(input).sort((a, b) => {
416
- if (a.property?.startsWith("og:image")) {
417
- if (b.property?.startsWith("og:image"))
418
- return 0;
419
- else
420
- return -1;
421
- }
422
- if (b.property?.startsWith("og:image"))
423
- return 1;
424
- return 0;
425
- })
426
- );
427
- const meta = unpackToArray(input, {
349
+ const meta = unpackToArray(primitives, {
428
350
  key({ key }) {
429
351
  return resolveMetaKeyType(key);
430
352
  },
@@ -442,7 +364,11 @@ function unpackMeta(input) {
442
364
  return typeof value === "number" ? value.toString() : value;
443
365
  }
444
366
  });
445
- return [...extras, ...meta];
367
+ return [...extras, ...meta].map((m) => {
368
+ if (m.content === "_null")
369
+ m.content = null;
370
+ return m;
371
+ });
446
372
  }
447
373
  function packMeta(inputs) {
448
374
  const mappedPackingSchema = Object.entries(MetaPackingSchema).map(([key, value]) => [key, value.keyValue]);
package/dist/index.mjs CHANGED
@@ -189,16 +189,10 @@ const MetaPackingSchema = {
189
189
  }
190
190
  }
191
191
  },
192
- articleAuthor: p("article:author"),
193
192
  articleExpirationTime: p("article:expiration_time"),
194
193
  articleModifiedTime: p("article:modified_time"),
195
194
  articlePublishedTime: p("article:published_time"),
196
- articleSection: p("article:section"),
197
- articleTag: p("article:tag"),
198
- bookAuthor: p("book:author"),
199
- bookIsbn: p("book:isbn"),
200
195
  bookReleaseDate: p("book:release_date"),
201
- bookTag: p("book:tag"),
202
196
  charset: {
203
197
  metaKey: "charset"
204
198
  },
@@ -222,32 +216,13 @@ const MetaPackingSchema = {
222
216
  msapplicationTileColor: k("msapplication-TileColor"),
223
217
  msapplicationTileImage: k("msapplication-TileImage"),
224
218
  ogAudioSecureUrl: p("og:audio:secure_url"),
225
- ogAudioType: p("og:audio:type"),
226
219
  ogAudioUrl: p("og:audio"),
227
- ogDescription: p("og:description"),
228
- ogDeterminer: p("og:determiner"),
229
- ogImage: p("og:image"),
230
- ogImageAlt: p("og:image:alt"),
231
- ogImageHeight: p("og:image:height"),
232
220
  ogImageSecureUrl: p("og:image:secure_url"),
233
- ogImageType: p("og:image:type"),
234
221
  ogImageUrl: p("og:image"),
235
- ogImageWidth: p("og:image:width"),
236
- ogLocale: p("og:locale"),
237
- ogLocaleAlternate: p("og:locale:alternate"),
238
222
  ogSiteName: p("og:site_name"),
239
- ogTitle: p("og:title"),
240
- ogType: p("og:type"),
241
- ogUrl: p("og:url"),
242
- ogVideo: p("og:video"),
243
- ogVideoAlt: p("og:video:alt"),
244
- ogVideoHeight: p("og:video:height"),
245
223
  ogVideoSecureUrl: p("og:video:secure_url"),
246
- ogVideoType: p("og:video:type"),
247
224
  ogVideoUrl: p("og:video"),
248
- ogVideoWidth: p("og:video:width"),
249
225
  profileFirstName: p("profile:first_name"),
250
- profileGender: p("profile:gender"),
251
226
  profileLastName: p("profile:last_name"),
252
227
  profileUsername: p("profile:username"),
253
228
  refresh: {
@@ -272,51 +247,31 @@ const MetaPackingSchema = {
272
247
  }
273
248
  }
274
249
  },
275
- twitterAppIdGoogleplay: k("twitter:app:id:googleplay"),
276
- twitterAppIdIpad: k("twitter:app:id:ipad"),
277
- twitterAppIdIphone: k("twitter:app:id:iphone"),
278
- twitterAppNameGoogleplay: k("twitter:app:name:googleplay"),
279
- twitterAppNameIpad: k("twitter:app:name:ipad"),
280
- twitterAppNameIphone: k("twitter:app:name:iphone"),
281
- twitterAppUrlGoogleplay: k("twitter:app:url:googleplay"),
282
- twitterAppUrlIpad: k("twitter:app:url:ipad"),
283
- twitterAppUrlIphone: k("twitter:app:url:iphone"),
284
- twitterCard: k("twitter:card"),
285
- twitterCreator: k("twitter:creator"),
286
- twitterCreatorId: k("twitter:creator:id"),
287
- twitterData1: k("twitter:data1"),
288
- twitterData2: k("twitter:data2"),
289
- twitterDescription: k("twitter:description"),
290
- twitterImage: k("twitter:image"),
291
- twitterImageAlt: k("twitter:image:alt"),
292
- /*************************************************/
293
- // not part of Twitter's card specification anymore
294
- twitterImageHeight: k("twitter:image:height"),
295
- twitterImageType: k("twitter:image:type"),
296
- twitterImageUrl: k("twitter:image"),
297
- twitterImageWidth: k("twitter:image:width"),
298
- /**************************************************/
299
- twitterLabel1: k("twitter:label1"),
300
- twitterLabel2: k("twitter:label2"),
301
- twitterPlayer: k("twitter:player"),
302
- twitterPlayerHeight: k("twitter:player:height"),
303
- twitterPlayerStream: k("twitter:player:stream"),
304
- twitterPlayerWidth: k("twitter:player:width"),
305
- twitterSite: k("twitter:site"),
306
- twitterSiteId: k("twitter:site:id"),
307
- twitterTitle: k("twitter:title"),
308
250
  xUaCompatible: {
309
251
  metaKey: "http-equiv"
310
252
  }
311
253
  };
254
+ const openGraphNamespaces = [
255
+ "og",
256
+ "book",
257
+ "article",
258
+ "profile"
259
+ ];
312
260
  function resolveMetaKeyType(key) {
261
+ const fKey = fixKeyCase(key).split(":")[0];
262
+ if (openGraphNamespaces.includes(fKey))
263
+ return "property";
313
264
  return MetaPackingSchema[key]?.metaKey || "name";
314
265
  }
315
266
  function resolveMetaKeyValue(key) {
316
267
  return MetaPackingSchema[key]?.keyValue || fixKeyCase(key);
317
268
  }
318
269
  function fixKeyCase(key) {
319
- return key.replace(/([A-Z])/g, "-$1").toLowerCase();
270
+ const updated = key.replace(/([A-Z])/g, "-$1").toLowerCase();
271
+ const fKey = updated.split("-")[0];
272
+ if (openGraphNamespaces.includes(fKey) || fKey === "twitter")
273
+ return key.replace(/([A-Z])/g, ":$1").toLowerCase();
274
+ return updated;
320
275
  }
321
276
  function changeKeyCasingDeep(input) {
322
277
  if (Array.isArray(input)) {
@@ -347,82 +302,49 @@ function resolvePackedMetaObjectValue(value, key) {
347
302
  }
348
303
  );
349
304
  }
350
- const SimpleArrayUnpackMetas = ["themeColor"];
351
- function getMeta(key, value) {
352
- const meta = {};
353
- const metaKeyType = resolveMetaKeyType(key);
354
- if (metaKeyType === "charset") {
355
- meta[metaKeyType] = value;
356
- } else {
357
- meta[metaKeyType] = resolveMetaKeyValue(key);
358
- meta.content = value;
359
- }
360
- return meta;
305
+ const ObjectArrayEntries = ["og:image", "og:video", "og:audio", "twitter:image"];
306
+ function sanitize(input) {
307
+ const out = {};
308
+ Object.entries(input).forEach(([k2, v]) => {
309
+ if (String(v) !== "false" && k2)
310
+ out[k2] = v;
311
+ });
312
+ return out;
361
313
  }
362
- function flattenMetaObjects(input, prefix = "") {
363
- const extras = [];
364
- for (const [k2, v] of Object.entries(input)) {
365
- const key = k2;
366
- const value = v;
367
- const fullkey = `${prefix}${prefix === "" ? key : key.charAt(0).toUpperCase() + key.slice(1)}`;
368
- const unpacker = MetaPackingSchema[key]?.unpack;
369
- if (unpacker) {
370
- extras.push(getMeta(fullkey, unpackToString(value, unpacker)));
371
- delete input[key];
372
- continue;
373
- }
374
- if (!value) {
375
- extras.push(getMeta(fullkey, value));
376
- delete input[key];
377
- continue;
378
- }
379
- if (typeof value === "object") {
380
- const children = Array.isArray(value) ? value : [value];
381
- for (const child of children) {
382
- if (!child)
383
- extras.push(getMeta(fullkey, child));
384
- else if (typeof child === "object")
385
- extras.push(...flattenMetaObjects(child, fullkey));
386
- else
387
- extras.push(getMeta(fullkey, child));
388
- }
389
- delete input[key];
390
- } else {
391
- extras.push(getMeta(fullkey, value));
392
- if (typeof input === "object")
393
- delete input[key];
394
- }
314
+ function handleObjectEntry(key, v) {
315
+ const value = sanitize(v);
316
+ const fKey = fixKeyCase(key);
317
+ const attr = resolveMetaKeyType(fKey);
318
+ if (ObjectArrayEntries.includes(fKey)) {
319
+ const input = {};
320
+ Object.entries(value).forEach(([k2, v2]) => {
321
+ input[`${key}${k2 === "url" ? "" : `${k2.charAt(0).toUpperCase()}${k2.slice(1)}`}`] = v2;
322
+ });
323
+ return unpackMeta(input).sort((a, b) => (a[attr]?.length || 0) - (b[attr]?.length || 0));
395
324
  }
396
- return extras;
325
+ return [{ [attr]: fKey, ...value }];
397
326
  }
398
327
  function unpackMeta(input) {
399
328
  const extras = [];
400
- SimpleArrayUnpackMetas.forEach((meta2) => {
401
- if (input[meta2] && typeof input[meta2] !== "string") {
402
- const val = Array.isArray(input[meta2]) ? input[meta2] : [input[meta2]];
403
- delete input[meta2];
404
- val.forEach((entry) => {
405
- extras.push({
406
- name: fixKeyCase(meta2),
407
- ...entry
408
- });
409
- });
329
+ const primitives = {};
330
+ Object.entries(input).forEach(([key, value]) => {
331
+ if (!Array.isArray(value)) {
332
+ if (typeof value === "object" && value) {
333
+ if (ObjectArrayEntries.includes(fixKeyCase(key))) {
334
+ extras.push(...handleObjectEntry(key, value));
335
+ return;
336
+ }
337
+ primitives[key] = sanitize(value);
338
+ } else {
339
+ primitives[key] = value;
340
+ }
341
+ return;
410
342
  }
343
+ value.forEach((v) => {
344
+ extras.push(...typeof v === "string" ? unpackMeta({ [key]: v }) : handleObjectEntry(key, v));
345
+ });
411
346
  });
412
- extras.push(
413
- ...flattenMetaObjects(input).sort((a, b) => {
414
- if (a.property?.startsWith("og:image")) {
415
- if (b.property?.startsWith("og:image"))
416
- return 0;
417
- else
418
- return -1;
419
- }
420
- if (b.property?.startsWith("og:image"))
421
- return 1;
422
- return 0;
423
- })
424
- );
425
- const meta = unpackToArray(input, {
347
+ const meta = unpackToArray(primitives, {
426
348
  key({ key }) {
427
349
  return resolveMetaKeyType(key);
428
350
  },
@@ -440,7 +362,11 @@ function unpackMeta(input) {
440
362
  return typeof value === "number" ? value.toString() : value;
441
363
  }
442
364
  });
443
- return [...extras, ...meta];
365
+ return [...extras, ...meta].map((m) => {
366
+ if (m.content === "_null")
367
+ m.content = null;
368
+ return m;
369
+ });
444
370
  }
445
371
  function packMeta(inputs) {
446
372
  const mappedPackingSchema = Object.entries(MetaPackingSchema).map(([key, value]) => [key, value.keyValue]);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unhead/shared",
3
3
  "type": "module",
4
- "version": "1.7.3",
4
+ "version": "1.8.0-beta.0",
5
5
  "author": "Harlan Wilton <harlan@harlanzw.com>",
6
6
  "license": "MIT",
7
7
  "funding": "https://github.com/sponsors/harlan-zw",
@@ -34,7 +34,7 @@
34
34
  "dist"
35
35
  ],
36
36
  "dependencies": {
37
- "@unhead/schema": "1.7.3"
37
+ "@unhead/schema": "1.8.0-beta.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "packrup": "^0.1.0"