@taprootio/site-authoring 0.1.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 (57) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +239 -0
  3. package/bin/taproot-site.js +5 -0
  4. package/package.json +40 -0
  5. package/src/api.js +1507 -0
  6. package/src/appearance-contract.js +311 -0
  7. package/src/atomic-file.js +136 -0
  8. package/src/bounded-file.js +59 -0
  9. package/src/capabilities.js +29 -0
  10. package/src/cli.js +872 -0
  11. package/src/config.js +412 -0
  12. package/src/constants.js +173 -0
  13. package/src/content/components.js +870 -0
  14. package/src/content/free-form-section-registry.json +524 -0
  15. package/src/content/free-form-sections.js +582 -0
  16. package/src/content/index.js +29 -0
  17. package/src/content/inline-facts.js +97 -0
  18. package/src/content/markdown.js +1625 -0
  19. package/src/content/tiptap-prosemirror.ts +1266 -0
  20. package/src/content/validate-document.js +1079 -0
  21. package/src/content/vocabulary.js +397 -0
  22. package/src/credentials.js +544 -0
  23. package/src/errors.js +133 -0
  24. package/src/footer-contract.js +687 -0
  25. package/src/footer-draft-hash.js +203 -0
  26. package/src/footer-workspace.js +136 -0
  27. package/src/image-metadata.js +169 -0
  28. package/src/index.js +16 -0
  29. package/src/json-guard.js +111 -0
  30. package/src/output.js +157 -0
  31. package/src/presentation-reference.js +600 -0
  32. package/src/reference-help.js +927 -0
  33. package/src/session.js +316 -0
  34. package/src/settings-catalog.js +187 -0
  35. package/src/settings.js +157 -0
  36. package/src/theme-validation.js +344 -0
  37. package/src/transport.js +777 -0
  38. package/src/verbs/approve.js +178 -0
  39. package/src/verbs/deploy.js +327 -0
  40. package/src/verbs/env.js +89 -0
  41. package/src/verbs/footer-push.js +115 -0
  42. package/src/verbs/index.js +125 -0
  43. package/src/verbs/login.js +529 -0
  44. package/src/verbs/logout.js +39 -0
  45. package/src/verbs/media-upload.js +319 -0
  46. package/src/verbs/nav-push.js +333 -0
  47. package/src/verbs/pages-push.js +990 -0
  48. package/src/verbs/preview-page.js +107 -0
  49. package/src/verbs/preview-revoke.js +56 -0
  50. package/src/verbs/pull.js +727 -0
  51. package/src/verbs/sites.js +57 -0
  52. package/src/verbs/status.js +94 -0
  53. package/src/verbs/theme-push.js +197 -0
  54. package/src/verbs/use.js +129 -0
  55. package/src/verbs/validate.js +477 -0
  56. package/src/verbs/whoami.js +108 -0
  57. package/src/workspace.js +1085 -0
@@ -0,0 +1,97 @@
1
+ import { FREE_FORM_SECTION_REGISTRY } from "./free-form-sections.js";
2
+ import {
3
+ CONTENT_ERROR_CODES as CODES,
4
+ CONTENT_LIMITS,
5
+ contentError,
6
+ identifier,
7
+ isPlainObject,
8
+ isSafeUrl,
9
+ pointerSegment,
10
+ } from "./vocabulary.js";
11
+
12
+ function scalarLength(value, stopAfter = Number.POSITIVE_INFINITY) {
13
+ let length = 0;
14
+ for (const _character of value) {
15
+ length += 1;
16
+ if (length > stopAfter) break;
17
+ }
18
+ return length;
19
+ }
20
+
21
+ function inlineFactUrlIsSafe(value) {
22
+ return typeof value === "string" && value.trim() !== "" && isSafeUrl(value.trim());
23
+ }
24
+
25
+ /** Validate and canonically order the first-class inlineFacts item array. */
26
+ export function normalizeInlineFactsItems(
27
+ value,
28
+ path = "/attrs/items",
29
+ source = FREE_FORM_SECTION_REGISTRY,
30
+ ) {
31
+ const errors = [];
32
+ const report = (errorPath, code, message) => {
33
+ if (errors.length < CONTENT_LIMITS.documentErrors) errors.push(contentError(errorPath, code, message));
34
+ };
35
+ const finish = (items) => Object.freeze({ items, errors: Object.freeze(errors) });
36
+ const definition = source.inlineFacts.attrs.items;
37
+
38
+ if (!Array.isArray(value)) {
39
+ report(path, CODES.attrInvalid, "Inline facts items must be an array.");
40
+ return finish(undefined);
41
+ }
42
+ if (value.length < definition.minItems || value.length > definition.maxItems) {
43
+ report(
44
+ path,
45
+ CODES.attrInvalid,
46
+ `Inline facts must contain ${definition.minItems} through ${definition.maxItems} items.`,
47
+ );
48
+ }
49
+
50
+ const items = [];
51
+ value.forEach((item, index) => {
52
+ const itemPath = `${path}/${index}`;
53
+ if (!isPlainObject(item)) {
54
+ report(itemPath, CODES.attrInvalid, "An inline fact must be an object.");
55
+ return;
56
+ }
57
+ for (const key of Object.keys(item)) {
58
+ if (!Object.hasOwn(definition.fields, key)) {
59
+ report(
60
+ `${itemPath}/${pointerSegment(key)}`,
61
+ CODES.attrUnknown,
62
+ `Inline fact field '${identifier(key)}' is not supported.`,
63
+ );
64
+ }
65
+ }
66
+
67
+ for (const name of ["value", "label"]) {
68
+ const field = definition.fields[name];
69
+ const entry = item[name];
70
+ if (typeof entry !== "string" || (field.nonWhitespace && entry.trim() === "")) {
71
+ report(`${itemPath}/${name}`, CODES.attrInvalid, `Inline fact ${name} must contain non-whitespace text.`);
72
+ } else if (scalarLength(entry, field.maxScalars) > field.maxScalars) {
73
+ report(
74
+ `${itemPath}/${name}`,
75
+ CODES.attrInvalid,
76
+ `Inline fact ${name} must contain at most ${field.maxScalars} Unicode scalar values.`,
77
+ );
78
+ }
79
+ }
80
+
81
+ if (item.url !== undefined && item.url !== null && !inlineFactUrlIsSafe(item.url)) {
82
+ report(
83
+ `${itemPath}/url`,
84
+ CODES.attrInvalid,
85
+ "Inline fact url must be a safe HTTP(S), mailto, tel, non-protocol-relative root, fragment, query, or relative URL without backslashes or ASCII controls.",
86
+ );
87
+ }
88
+
89
+ items.push(Object.freeze({
90
+ value: item.value,
91
+ label: item.label,
92
+ ...(typeof item.url === "string" ? { url: item.url.trim() } : {}),
93
+ }));
94
+ });
95
+
96
+ return errors.length === 0 ? finish(Object.freeze(items)) : finish(undefined);
97
+ }