@gunkin/uiify 0.0.26-alpha → 0.0.27-alpha

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 (62) hide show
  1. package/README.md +59 -0
  2. package/agents/components.md +2 -0
  3. package/agents/index.md +1 -0
  4. package/dist/ai/UiDocument.d.ts +16 -0
  5. package/dist/ai/UiDocument.d.ts.map +1 -0
  6. package/dist/ai/UiDocument.js +33 -0
  7. package/dist/ai/UiDocument.js.map +1 -0
  8. package/dist/ai/catalog.generated.d.ts +2766 -0
  9. package/dist/ai/catalog.generated.d.ts.map +1 -0
  10. package/dist/ai/catalog.generated.js +214 -0
  11. package/dist/ai/catalog.generated.js.map +1 -0
  12. package/dist/ai/index.d.ts +9 -0
  13. package/dist/ai/index.d.ts.map +1 -0
  14. package/dist/ai/index.js +13 -0
  15. package/dist/ai/index.js.map +1 -0
  16. package/dist/ai/issues.d.ts +10 -0
  17. package/dist/ai/issues.d.ts.map +1 -0
  18. package/dist/ai/issues.js +178 -0
  19. package/dist/ai/issues.js.map +1 -0
  20. package/dist/ai/layout.d.ts +26 -0
  21. package/dist/ai/layout.d.ts.map +1 -0
  22. package/dist/ai/layout.js +46 -0
  23. package/dist/ai/layout.js.map +1 -0
  24. package/dist/ai/limits.d.ts +16 -0
  25. package/dist/ai/limits.d.ts.map +1 -0
  26. package/dist/ai/limits.js +99 -0
  27. package/dist/ai/limits.js.map +1 -0
  28. package/dist/ai/load.d.ts +16 -0
  29. package/dist/ai/load.d.ts.map +1 -0
  30. package/dist/ai/load.js +69 -0
  31. package/dist/ai/load.js.map +1 -0
  32. package/dist/ai/loaders.generated.d.ts +5 -0
  33. package/dist/ai/loaders.generated.d.ts.map +1 -0
  34. package/dist/ai/loaders.generated.js +122 -0
  35. package/dist/ai/loaders.generated.js.map +1 -0
  36. package/dist/ai/rules.d.ts +11 -0
  37. package/dist/ai/rules.d.ts.map +1 -0
  38. package/dist/ai/rules.js +126 -0
  39. package/dist/ai/rules.js.map +1 -0
  40. package/dist/ai/schema.generated.d.ts +8 -0
  41. package/dist/ai/schema.generated.d.ts.map +1 -0
  42. package/dist/ai/schema.generated.js +3316 -0
  43. package/dist/ai/schema.generated.js.map +1 -0
  44. package/dist/ai/types.d.ts +33 -0
  45. package/dist/ai/types.d.ts.map +1 -0
  46. package/dist/ai/types.js +14 -0
  47. package/dist/ai/types.js.map +1 -0
  48. package/dist/ai/validate.d.ts +15 -0
  49. package/dist/ai/validate.d.ts.map +1 -0
  50. package/dist/ai/validate.js +32 -0
  51. package/dist/ai/validate.js.map +1 -0
  52. package/dist/ai/validator.generated.d.ts +13 -0
  53. package/dist/ai/validator.generated.d.ts.map +1 -0
  54. package/dist/ai/validator.generated.js +49133 -0
  55. package/dist/ai/validator.generated.js.map +1 -0
  56. package/dist/components/virtual-scroll/VirtualScroll.d.ts.map +1 -1
  57. package/dist/components/virtual-scroll/VirtualScroll.js +1 -1
  58. package/dist/components/virtual-scroll/VirtualScroll.js.map +1 -1
  59. package/dist/styles/index.css +1 -1
  60. package/package.json +10 -1
  61. package/skills/uiify/SKILL.md +14 -10
  62. package/skills/uiify/references/guides/verification.md +13 -2
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ai/rules.ts"],"sourcesContent":["import { uiParts, type UiChild, type UiNode, type UiType } from \"./catalog.generated.js\";\nimport type { UiValidationIssue } from \"./types.js\";\n\ninterface Ancestry {\n readonly node: UiNode;\n readonly parent: Ancestry | undefined;\n}\n\ninterface Visit {\n readonly node: UiNode;\n readonly path: string;\n readonly parent: Ancestry | undefined;\n}\n\n/** Natives that may hold only text and phrasing natives: the HTML parser closes or moves out\n * anything else, so server HTML would not hydrate. */\nconst PHRASING_PARENTS: ReadonlySet<string> = new Set([\n \"p\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"a\",\n \"strong\",\n \"em\",\n \"label\",\n \"legend\",\n \"dt\",\n]);\n\n/** The phrasing natives a phrasing parent may hold. */\nconst PHRASING: ReadonlySet<string> = new Set([\"a\", \"strong\", \"em\", \"label\"]);\n\n/** Types that render a `<form>`. */\nconst FORMS: readonly UiType[] = [\"form\", \"Form\"];\n\n/** Native interactive content a link may not hold; components are caught as non-phrasing. */\nconst LINK_INTERACTIVE: ReadonlySet<string> = new Set([\"a\", \"label\"]);\n\n/** List natives and the only children they take. */\nconst LIST_ITEMS: Readonly<Record<string, readonly string[]>> = {\n ul: [\"li\"],\n ol: [\"li\"],\n dl: [\"dt\", \"dd\"],\n};\n\nfunction nestingProblem(node: UiNode, parent: Ancestry | undefined): string | undefined {\n if (parent === undefined) return undefined;\n const parentType = parent.node.type;\n const items = LIST_ITEMS[parentType];\n if (items !== undefined && !items.includes(node.type)) {\n return `${node.type} cannot be directly inside ${parentType}; ${parentType} takes only ${items.join(\" and \")} children`;\n }\n if (PHRASING_PARENTS.has(parentType) && !PHRASING.has(node.type)) {\n return `${node.type} cannot be inside ${parentType}; ${parentType} holds only text and ${[...PHRASING].join(\", \")}`;\n }\n if (FORMS.includes(node.type) && FORMS.some((type) => nearest(parent, type) !== undefined)) {\n return `${node.type} cannot be inside another form`;\n }\n if (LINK_INTERACTIVE.has(node.type) && nearest(parent, \"a\") !== undefined) {\n return `${node.type} cannot be inside a link (a)`;\n }\n return undefined;\n}\n\nfunction propsOf(node: UiNode): Readonly<Record<string, unknown>> {\n return node.props as Readonly<Record<string, unknown>>;\n}\n\nfunction nearest(from: Ancestry | undefined, type: UiType): UiNode | undefined {\n for (let link = from; link !== undefined; link = link.parent) {\n if (link.node.type === type) return link.node;\n }\n return undefined;\n}\n\nfunction crumbsOf(parent: Ancestry | undefined, node: UiNode, suffix = \"\"): string {\n const types: string[] = [];\n for (let link = parent; link !== undefined; link = link.parent) types.push(link.node.type);\n types.reverse();\n types.push(`${node.type}${suffix}`);\n return types.join(\" › \");\n}\n\n/**\n * Rules JSON Schema cannot express, over a document that already passed the schema:\n * a part sits inside its root, a `fieldId` names the enclosing root, ids are unique, and\n * nesting the HTML parser would rewrite (block content in phrasing elements, a form in a form,\n * a link or label in a link, anything but items in a list) is rejected.\n * `basePath` is the pointer of `root` inside the value the caller validated.\n */\nexport function checkRules(root: UiNode, basePath = \"\"): UiValidationIssue[] {\n const issues: UiValidationIssue[] = [];\n const firstPathOfId = new Map<string, string>();\n const stack: Visit[] = [{ node: root, path: basePath, parent: undefined }];\n\n while (stack.length > 0) {\n const { node, path, parent } = stack.pop() as Visit;\n const props = propsOf(node);\n const rootType = uiParts[node.type].rootType;\n\n const nesting = nestingProblem(node, parent);\n if (nesting !== undefined) {\n issues.push({ path, breadcrumb: crumbsOf(parent, node), message: nesting });\n }\n\n if (rootType !== undefined) {\n const enclosing = nearest(parent, rootType);\n if (enclosing === undefined) {\n issues.push({\n path,\n breadcrumb: crumbsOf(parent, node),\n message: `${node.type} must be inside a ${rootType}`,\n allowed: [rootType],\n });\n } else if (typeof props.fieldId === \"string\") {\n const id = propsOf(enclosing).id;\n if (props.fieldId !== id) {\n issues.push({\n path: `${path}/props/fieldId`,\n breadcrumb: crumbsOf(parent, node, \".props.fieldId\"),\n message: `fieldId ${JSON.stringify(props.fieldId)} does not match the id ${JSON.stringify(id)} of the enclosing ${rootType}`,\n allowed: [id],\n });\n }\n }\n }\n\n if (typeof props.id === \"string\") {\n const first = firstPathOfId.get(props.id);\n if (first === undefined) {\n firstPathOfId.set(props.id, path);\n } else {\n issues.push({\n path: `${path}/props/id`,\n breadcrumb: crumbsOf(parent, node, \".props.id\"),\n message: `duplicate id ${JSON.stringify(props.id)}; first used at ${first}`,\n });\n }\n }\n\n const children = (node as { readonly children?: readonly UiChild[] }).children;\n if (children !== undefined) {\n const link: Ancestry = { node, parent };\n for (let index = children.length - 1; index >= 0; index -= 1) {\n const child = children[index];\n if (typeof child === \"object\" && child !== null) {\n stack.push({ node: child, path: `${path}/children/${index}`, parent: link });\n } else if (LIST_ITEMS[node.type] !== undefined) {\n issues.push({\n path: `${path}/children/${index}`,\n breadcrumb: `${crumbsOf(parent, node)} › children[${index}]`,\n message: `text cannot be directly inside ${node.type}; wrap it in ${LIST_ITEMS[node.type]?.[0] ?? \"an item\"}`,\n });\n }\n }\n }\n }\n return issues;\n}\n"],"mappings":"AAAA,SAAS,eAAuD;AAgBhE,MAAM,mBAAwC,oBAAI,IAAI;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGD,MAAM,WAAgC,oBAAI,IAAI,CAAC,KAAK,UAAU,MAAM,OAAO,CAAC;AAG5E,MAAM,QAA2B,CAAC,QAAQ,MAAM;AAGhD,MAAM,mBAAwC,oBAAI,IAAI,CAAC,KAAK,OAAO,CAAC;AAGpE,MAAM,aAA0D;AAAA,EAC9D,IAAI,CAAC,IAAI;AAAA,EACT,IAAI,CAAC,IAAI;AAAA,EACT,IAAI,CAAC,MAAM,IAAI;AACjB;AAEA,SAAS,eAAe,MAAc,QAAkD;AACtF,MAAI,WAAW,OAAW,QAAO;AACjC,QAAM,aAAa,OAAO,KAAK;AAC/B,QAAM,QAAQ,WAAW,UAAU;AACnC,MAAI,UAAU,UAAa,CAAC,MAAM,SAAS,KAAK,IAAI,GAAG;AACrD,WAAO,GAAG,KAAK,IAAI,8BAA8B,UAAU,KAAK,UAAU,eAAe,MAAM,KAAK,OAAO,CAAC;AAAA,EAC9G;AACA,MAAI,iBAAiB,IAAI,UAAU,KAAK,CAAC,SAAS,IAAI,KAAK,IAAI,GAAG;AAChE,WAAO,GAAG,KAAK,IAAI,qBAAqB,UAAU,KAAK,UAAU,wBAAwB,CAAC,GAAG,QAAQ,EAAE,KAAK,IAAI,CAAC;AAAA,EACnH;AACA,MAAI,MAAM,SAAS,KAAK,IAAI,KAAK,MAAM,KAAK,CAAC,SAAS,QAAQ,QAAQ,IAAI,MAAM,MAAS,GAAG;AAC1F,WAAO,GAAG,KAAK,IAAI;AAAA,EACrB;AACA,MAAI,iBAAiB,IAAI,KAAK,IAAI,KAAK,QAAQ,QAAQ,GAAG,MAAM,QAAW;AACzE,WAAO,GAAG,KAAK,IAAI;AAAA,EACrB;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,MAAiD;AAChE,SAAO,KAAK;AACd;AAEA,SAAS,QAAQ,MAA4B,MAAkC;AAC7E,WAAS,OAAO,MAAM,SAAS,QAAW,OAAO,KAAK,QAAQ;AAC5D,QAAI,KAAK,KAAK,SAAS,KAAM,QAAO,KAAK;AAAA,EAC3C;AACA,SAAO;AACT;AAEA,SAAS,SAAS,QAA8B,MAAc,SAAS,IAAY;AACjF,QAAM,QAAkB,CAAC;AACzB,WAAS,OAAO,QAAQ,SAAS,QAAW,OAAO,KAAK,OAAQ,OAAM,KAAK,KAAK,KAAK,IAAI;AACzF,QAAM,QAAQ;AACd,QAAM,KAAK,GAAG,KAAK,IAAI,GAAG,MAAM,EAAE;AAClC,SAAO,MAAM,KAAK,UAAK;AACzB;AASO,SAAS,WAAW,MAAc,WAAW,IAAyB;AAC3E,QAAM,SAA8B,CAAC;AACrC,QAAM,gBAAgB,oBAAI,IAAoB;AAC9C,QAAM,QAAiB,CAAC,EAAE,MAAM,MAAM,MAAM,UAAU,QAAQ,OAAU,CAAC;AAEzE,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,EAAE,MAAM,MAAM,OAAO,IAAI,MAAM,IAAI;AACzC,UAAM,QAAQ,QAAQ,IAAI;AAC1B,UAAM,WAAW,QAAQ,KAAK,IAAI,EAAE;AAEpC,UAAM,UAAU,eAAe,MAAM,MAAM;AAC3C,QAAI,YAAY,QAAW;AACzB,aAAO,KAAK,EAAE,MAAM,YAAY,SAAS,QAAQ,IAAI,GAAG,SAAS,QAAQ,CAAC;AAAA,IAC5E;AAEA,QAAI,aAAa,QAAW;AAC1B,YAAM,YAAY,QAAQ,QAAQ,QAAQ;AAC1C,UAAI,cAAc,QAAW;AAC3B,eAAO,KAAK;AAAA,UACV;AAAA,UACA,YAAY,SAAS,QAAQ,IAAI;AAAA,UACjC,SAAS,GAAG,KAAK,IAAI,qBAAqB,QAAQ;AAAA,UAClD,SAAS,CAAC,QAAQ;AAAA,QACpB,CAAC;AAAA,MACH,WAAW,OAAO,MAAM,YAAY,UAAU;AAC5C,cAAM,KAAK,QAAQ,SAAS,EAAE;AAC9B,YAAI,MAAM,YAAY,IAAI;AACxB,iBAAO,KAAK;AAAA,YACV,MAAM,GAAG,IAAI;AAAA,YACb,YAAY,SAAS,QAAQ,MAAM,gBAAgB;AAAA,YACnD,SAAS,WAAW,KAAK,UAAU,MAAM,OAAO,CAAC,0BAA0B,KAAK,UAAU,EAAE,CAAC,qBAAqB,QAAQ;AAAA,YAC1H,SAAS,CAAC,EAAE;AAAA,UACd,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,QAAI,OAAO,MAAM,OAAO,UAAU;AAChC,YAAM,QAAQ,cAAc,IAAI,MAAM,EAAE;AACxC,UAAI,UAAU,QAAW;AACvB,sBAAc,IAAI,MAAM,IAAI,IAAI;AAAA,MAClC,OAAO;AACL,eAAO,KAAK;AAAA,UACV,MAAM,GAAG,IAAI;AAAA,UACb,YAAY,SAAS,QAAQ,MAAM,WAAW;AAAA,UAC9C,SAAS,gBAAgB,KAAK,UAAU,MAAM,EAAE,CAAC,mBAAmB,KAAK;AAAA,QAC3E,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,WAAY,KAAoD;AACtE,QAAI,aAAa,QAAW;AAC1B,YAAM,OAAiB,EAAE,MAAM,OAAO;AACtC,eAAS,QAAQ,SAAS,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AAC5D,cAAM,QAAQ,SAAS,KAAK;AAC5B,YAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,gBAAM,KAAK,EAAE,MAAM,OAAO,MAAM,GAAG,IAAI,aAAa,KAAK,IAAI,QAAQ,KAAK,CAAC;AAAA,QAC7E,WAAW,WAAW,KAAK,IAAI,MAAM,QAAW;AAC9C,iBAAO,KAAK;AAAA,YACV,MAAM,GAAG,IAAI,aAAa,KAAK;AAAA,YAC/B,YAAY,GAAG,SAAS,QAAQ,IAAI,CAAC,oBAAe,KAAK;AAAA,YACzD,SAAS,kCAAkC,KAAK,IAAI,gBAAgB,WAAW,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS;AAAA,UAC7G,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * JSON Schema (draft 2020-12) of a UI document; compile with Ajv's `discriminator` option.
3
+ * It checks parts, props and values only: the size limits (depth, node count, string length)
4
+ * and the rules (parts inside their root, `fieldId` wiring, unique ids, nesting) are not in it.
5
+ * To check a document, use `validateDocument`.
6
+ */
7
+ export declare const uiDocumentSchema: Readonly<Record<string, unknown>>;
8
+ //# sourceMappingURL=schema.generated.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.generated.d.ts","sourceRoot":"","sources":["../../src/ai/schema.generated.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA0xG9D,CAAC"}