@estiva-app/ui 0.35.2 → 0.36.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.
- package/dist/eslint/escape.d.ts +23 -6
- package/dist/eslint/escape.d.ts.map +1 -1
- package/dist/eslint/index.js +70 -9
- package/dist/eslint/index.js.map +2 -2
- package/dist/eslint/no-raw-element.d.ts +7 -0
- package/dist/eslint/no-raw-element.d.ts.map +1 -1
- package/dist/eslint/no-restyled-part.d.ts +8 -0
- package/dist/eslint/no-restyled-part.d.ts.map +1 -1
- package/dist/gates/app-checks.d.ts.map +1 -1
- package/dist/gates/{chunk-DRIHHXQK.js → chunk-CC6L4B5U.js} +23 -17
- package/dist/gates/chunk-CC6L4B5U.js.map +7 -0
- package/dist/gates/chunk-SYVKGOWM.js +1131 -0
- package/dist/gates/chunk-SYVKGOWM.js.map +7 -0
- package/dist/gates/ci.d.ts +18 -0
- package/dist/gates/ci.d.ts.map +1 -0
- package/dist/gates/cli.js +20 -3
- package/dist/gates/cli.js.map +2 -2
- package/dist/gates/create-app.d.ts.map +1 -1
- package/dist/gates/create-app.js +1 -1
- package/dist/gates/escapes.d.ts +23 -0
- package/dist/gates/escapes.d.ts.map +1 -0
- package/dist/gates/gate-config.d.ts.map +1 -1
- package/dist/gates/hook.d.ts +2 -0
- package/dist/gates/hook.d.ts.map +1 -1
- package/dist/gates/index.d.ts +5 -1
- package/dist/gates/index.d.ts.map +1 -1
- package/dist/gates/index.js +37 -183
- package/dist/gates/index.js.map +4 -4
- package/dist/gates/name-escapes.d.ts +14 -0
- package/dist/gates/name-escapes.d.ts.map +1 -0
- package/dist/gates/status.d.ts +3 -1
- package/dist/gates/status.d.ts.map +1 -1
- package/dist/gates/token-lint.d.ts.map +1 -1
- package/dist/gates/token-style.d.ts +21 -0
- package/dist/gates/token-style.d.ts.map +1 -0
- package/dist/index.js +13 -13
- package/dist/index.js.map +1 -1
- package/dist/registry/{app-3ALZE6XO.js → app-YMABQII6.js} +3 -3
- package/dist/registry/app.d.ts.map +1 -1
- package/dist/registry/behaviours.d.ts +71 -0
- package/dist/registry/behaviours.d.ts.map +1 -0
- package/dist/registry/{build-NDXMVFQ5.js → build-3EANARLQ.js} +2 -2
- package/dist/registry/build.d.ts.map +1 -1
- package/dist/registry/{chunk-3WJ7ZZ7Z.js → chunk-EVJW26UR.js} +51 -4
- package/dist/registry/chunk-EVJW26UR.js.map +7 -0
- package/dist/registry/{chunk-XVII7P6G.js → chunk-SIB44CES.js} +276 -90
- package/dist/registry/chunk-SIB44CES.js.map +7 -0
- package/dist/registry/{chunk-5K2TRR4X.js → chunk-XK747STJ.js} +18 -3
- package/dist/registry/chunk-XK747STJ.js.map +7 -0
- package/dist/registry/cli.js +7 -6
- package/dist/registry/cli.js.map +2 -2
- package/dist/registry/contract.d.ts +13 -1
- package/dist/registry/contract.d.ts.map +1 -1
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +11 -5
- package/package.json +4 -1
- package/registry.json +293 -17
- package/skill/estiva-ui.md +2 -1
- package/src/AppShell.mdx +2 -1
- package/src/AttachmentCard.tsx +7 -7
- package/src/Button.tsx +1 -1
- package/src/Card.tsx +2 -2
- package/src/ChipInput.mdx +2 -0
- package/src/ChipInput.tsx +1 -1
- package/src/CommandPalette.tsx +3 -3
- package/src/DialogShell.tsx +1 -1
- package/src/EmptyState.mdx +4 -3
- package/src/Lightbox.tsx +1 -1
- package/src/NavItem.tsx +1 -1
- package/src/PersonTrigger.tsx +1 -1
- package/src/Reaction.tsx +1 -1
- package/src/ScrollArea.mdx +4 -0
- package/src/Select.tsx +1 -1
- package/src/TopBar.mdx +1 -1
- package/src/eslint/escape.ts +43 -14
- package/src/eslint/has-a-page-and-a-story.test.ts +1 -1
- package/src/eslint/index.test.ts +2 -2
- package/src/eslint/no-copied-look.test.ts +1 -1
- package/src/eslint/no-hand-rolled-behaviour.test.ts +3 -3
- package/src/eslint/no-handmade-empty-state.test.ts +2 -2
- package/src/eslint/no-handmade-header.test.ts +2 -2
- package/src/eslint/no-native-title.test.ts +2 -2
- package/src/eslint/no-raw-element.test.ts +47 -15
- package/src/eslint/no-raw-element.ts +53 -3
- package/src/eslint/no-rebuilt-behaviour.test.ts +9 -9
- package/src/eslint/no-restyled-part.test.ts +21 -2
- package/src/eslint/no-restyled-part.ts +30 -0
- package/src/eslint/raw-element-outside-a-wrapper.test.ts +3 -3
- package/src/gates/app-checks.ts +4 -3
- package/src/gates/ci.ts +152 -0
- package/src/gates/cli.ts +19 -3
- package/src/gates/count.ts +1 -1
- package/src/gates/create-app.test.ts +2 -2
- package/src/gates/create-app.ts +22 -16
- package/src/gates/escapes.ts +111 -0
- package/src/gates/gate-config.ts +2 -0
- package/src/gates/gates.test.ts +86 -1
- package/src/gates/hook.ts +38 -4
- package/src/gates/index.ts +5 -1
- package/src/gates/name-escapes.ts +77 -0
- package/src/gates/status.ts +45 -2
- package/src/gates/token-lint.ts +11 -4
- package/src/gates/token-style.ts +79 -0
- package/src/how.test.ts +282 -0
- package/src/pages.test.ts +6 -0
- package/src/registry/app.test.ts +34 -0
- package/src/registry/app.ts +52 -2
- package/src/registry/behaviours.ts +223 -0
- package/src/registry/build.ts +36 -0
- package/src/registry/cli.ts +5 -3
- package/src/registry/contract.test.ts +27 -2
- package/src/registry/contract.ts +28 -3
- package/src/registry/index.ts +1 -1
- package/src/registry/registry.test.ts +14 -0
- package/dist/gates/chunk-DBMUQAR6.js +0 -607
- package/dist/gates/chunk-DBMUQAR6.js.map +0 -7
- package/dist/gates/chunk-DRIHHXQK.js.map +0 -7
- package/dist/registry/chunk-3WJ7ZZ7Z.js.map +0 -7
- package/dist/registry/chunk-5K2TRR4X.js.map +0 -7
- package/dist/registry/chunk-XVII7P6G.js.map +0 -7
- /package/dist/registry/{app-3ALZE6XO.js.map → app-YMABQII6.js.map} +0 -0
- /package/dist/registry/{build-NDXMVFQ5.js.map → build-3EANARLQ.js.map} +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/registry/build.ts", "../../src/registry/behaviours.ts", "../../src/eslint/looks-of.ts"],
|
|
4
|
+
"sourcesContent": ["/// <reference types=\"node\" />\n/**\n * The catalogue's builder (UIG-12): it reads the code and writes\n * `registry.json`. Nothing here is kept by hand, and CI rebuilds it and fails\n * on a difference, so the file cannot drift from what it describes.\n *\n * **Why a parser and not a regex.** This package's components are flat in\n * `src/`, with `.tsx`, `.mdx`, `.stories.tsx` and sometimes `.test.tsx` side by\n * side, and **a file is not a component**: eleven files export more than one\n * name \u2014 `Menu.tsx` alone exports seven \u2014 and `Skeleton.tsx` exports no\n * `Skeleton` at all. Pairing by filename gets `FieldLine`, `MenuItem` and every\n * one of those wrong. The target set is what `src/index.ts` exports, read with\n * TypeScript's own parser, and everything else is looked up from there.\n *\n * TypeScript is the app's own install, as it is for the gate pieces\n * (`build.mjs`): every package this names stays external.\n */\nimport { existsSync, readFileSync, readdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport ts from 'typescript'\nimport { OWNED_BEHAVIOURS } from '../eslint/index'\nimport { asBehaviours, baseUiBehaviours, drawnIn, handedOn, importsOf, isBaseUi, rootsIn, splitTag } from './behaviours'\nimport { looksOf, parseForLooks } from '../eslint/looks-of'\nimport { SCHEMA_VERSION, type EntryBehaviour, type EntryKind, type EntryProp, type EntryVariant, type Registry, type RegistryEntry } from './schema'\n\nexport interface BuildOptions {\n /** The repository's top folder. */\n root?: string\n /** The name this registry's entries are recorded under. */\n repo?: string\n}\n\n/** One name as `index.ts` exports it. */\ninterface RawExport {\n name: string\n /** The sibling it comes from, without `./`. */\n module: string\n isType: boolean\n}\n\n/** What the parser found above and about one top-level declaration. */\ninterface Declared {\n /** The doc comment, cleaned, or `''`. */\n doc: string\n deprecated: boolean\n /**\n * Its first parameter's type, as written. Kept as the node and resolved after\n * the whole file is walked: a props interface is often declared *below* the\n * component that takes it.\n */\n propsType?: ts.TypeNode\n}\n\nexport const PACKAGE_IMPORT = '@estiva-app/ui'\n\n/**\n * Storybook's own `sanitize`, which is what turns a title and a story's export\n * name into the id in the URL. Copied rather than imported: `storybook` is a\n * dev dependency of this repo and must not become a runtime dependency of the\n * builder, which apps run. A test holds this to the ids a real Storybook build\n * produces.\n */\nexport function sanitize(name: string): string {\n return name\n .toLowerCase()\n .replace(/[ \u2019\u2013\u2014\u2015\u2032\u00BF'`~!@#$%^&*()_|+\\-=?;:'\",.<>{}[\\]\\\\/]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-+/, '')\n .replace(/-+$/, '')\n}\n\n/**\n * Storybook's `storyNameFromExport`, which is lodash's `startCase`: an export\n * called `WithCounts` is the story \"With Counts\", and its id is\n * `navigation-tabs--with-counts`, not `--withcounts`.\n *\n * Measured against a real `storybook build` (2026-09-18): without this, 11 of\n * the 81 ids resolved nowhere \u2014 every export whose name is more than one word.\n * Written out rather than pulled from lodash or `@storybook/csf`, neither of\n * which may become a runtime dependency of a builder that apps run.\n */\nfunction storyNameFromExport(key: string): string {\n return key\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/([a-zA-Z])([0-9])/g, '$1 $2')\n .replace(/([0-9])([a-zA-Z])/g, '$1 $2')\n .replace(/[_-]+/g, ' ')\n .trim()\n}\n\nexport const toId = (title: string, name: string) => `${sanitize(title)}--${sanitize(storyNameFromExport(name))}`\n\n/** Read `src/index.ts`. Its `export { \u2026 } from './Sibling'` statements are the target set. */\nexport function readIndexExports(source: string): RawExport[] {\n const file = ts.createSourceFile('index.ts', source, ts.ScriptTarget.Latest, true)\n const found: RawExport[] = []\n for (const statement of file.statements) {\n if (!ts.isExportDeclaration(statement)) continue\n const from = statement.moduleSpecifier\n const clause = statement.exportClause\n if (!from || !ts.isStringLiteral(from) || !clause || !ts.isNamedExports(clause)) continue\n for (const element of clause.elements) {\n found.push({ name: element.name.text, module: from.text.replace(/^\\.\\//, ''), isType: statement.isTypeOnly || element.isTypeOnly })\n }\n }\n return found\n}\n\n/**\n * The doc comment immediately above a declaration, cleaned of its markers.\n * `''` when there is none.\n *\n * `headerPos` is where the **file's** own header comment starts, and a\n * declaration never gets to claim it. Measured: `Skeleton.tsx` opens with a\n * paragraph about the whole family and `export function SkeletonBar` follows it\n * directly, so the bar was given the family's description \u2014 right-looking, and\n * wrong. Refusing it turns that into a build failure with the export's name in\n * it, which is a line somebody then writes.\n */\nfunction docAbove(source: string, node: ts.Node, headerPos: number | null = null): string {\n const ranges = ts.getLeadingCommentRanges(source, node.getFullStart()) ?? []\n const jsdoc = ranges.filter((range) => source.slice(range.pos, range.pos + 3) === '/**').pop()\n if (!jsdoc) return ''\n if (headerPos !== null && jsdoc.pos === headerPos) return ''\n // Only a comment that sits against the declaration describes it: anything\n // with another statement between them is about something else. A `//` line\n // between is still its own \u2014 the written note an escape needs sits there, and\n // TypeScript attaches the doc comment through it too.\n const between = source.slice(jsdoc.end, node.getStart())\n if (between.replace(/\\/\\/[^\\n]*/g, '').trim() !== '') return ''\n return source\n .slice(jsdoc.pos, jsdoc.end)\n .split(/\\r?\\n/)\n .map((line) => line.trim().replace(/^\\/\\*\\*/, '').replace(/\\*\\/$/, '').replace(/^\\*/, '').trim())\n .join('\\n')\n .trim()\n}\n\n/**\n * The first sentence of a block of prose, which is the purpose.\n *\n * A sentence ends at `.`, `!` or `?` followed by a space and something that\n * starts a new one. A very short first sentence takes the next as well \u2014\n * \"A list of actions from a trigger.\" is a purpose; \"One row, two parts.\" is\n * not, on its own.\n */\nexport function firstSentence(prose: string): string {\n const flat = prose\n .split(/\\n\\s*\\n/)[0]\n .split('\\n')\n .filter((line) => !line.trim().startsWith('@'))\n .join(' ')\n .replace(/\\*\\*/g, '')\n .replace(/\\s+/g, ' ')\n .trim()\n const parts = flat.split(/(?<=[.!?])\\s+(?=[A-Z`'\"\u2018\u201C])/)\n let line = parts[0] ?? ''\n if (line.length < 40 && parts[1]) line = `${line} ${parts[1]}`\n return line.trim()\n}\n\n/** A page's opening paragraph: everything between its `# Heading` and the first blank line. */\nexport function pageOpening(mdx: string): string {\n const lines = mdx.split(/\\r?\\n/)\n const heading = lines.findIndex((line) => /^#\\s+\\S/.test(line))\n if (heading < 0) return ''\n const paragraph: string[] = []\n for (const line of lines.slice(heading + 1)) {\n const text = line.trim()\n if (text === '') {\n if (paragraph.length) break\n continue\n }\n // A canvas, an import or the next heading: the opening paragraph is over,\n // or there never was one.\n if (text.startsWith('<') || text.startsWith('#')) break\n paragraph.push(text)\n }\n return paragraph.join(' ')\n}\n\n/**\n * A property's name, however it is written.\n *\n * **A quoted name is a name.** `'aria-label'?: string` cannot be written as an\n * identifier, so a reader that takes identifiers only drops it \u2014 and with it\n * every accessible name this package declares. Found by comparing against\n * `react-docgen`, a parser with none of this one's assumptions: 13 props over\n * 10 files, two of them required (`Reaction`, `Toolbar`).\n */\nfunction propName(member: ts.TypeElement): string | null {\n if (!member.name) return null\n if (ts.isIdentifier(member.name) || ts.isStringLiteral(member.name)) return member.name.text\n return null\n}\n\n/** A union of string literals, following one local type alias if the property points at one. */\nfunction literalUnion(type: ts.TypeNode | undefined, aliases: Map<string, ts.TypeNode>, seen = new Set<string>()): string[] | null {\n if (!type) return null\n if (ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName)) {\n const name = type.typeName.text\n if (seen.has(name)) return null\n seen.add(name)\n const alias = aliases.get(name)\n return alias ? literalUnion(alias, aliases, seen) : null\n }\n if (ts.isLiteralTypeNode(type) && ts.isStringLiteral(type.literal)) return [type.literal.text]\n if (!ts.isUnionTypeNode(type)) return null\n const values: string[] = []\n for (const member of type.types) {\n // `'small' | 'default' | undefined` is still a set of two words.\n if (member.kind === ts.SyntaxKind.UndefinedKeyword || member.kind === ts.SyntaxKind.NullKeyword) continue\n const inner = literalUnion(member, aliases, seen)\n if (!inner) return null\n values.push(...inner)\n }\n return values.length > 1 ? values : null\n}\n\n/** A type\u2019s finished props and word-choices, read by the module that declares them. */\nexport interface Resolved {\n props: EntryProp[]\n variants: EntryVariant[]\n}\n\n/**\n * Ask another file for a type it declares, already resolved. `specifier` is the\n * import as written (`./IconButton`, `@/lib/types`); the caller decides what it\n * points at, and answers `undefined` for anything outside the library it reads.\n */\nexport type Sibling = (specifier: string, typeName: string) => Resolved | undefined\n\nexport interface ReadOptions {\n /**\n * Whether a file with no comment of its own at the top lends the comment on\n * its first declaration to the file. The package: yes \u2014 `Skeleton.tsx`'s\n * family paragraph sits there, and taking it as `SkeletonBar`'s was wrong. An\n * app: no \u2014 a comment directly above a part is that part's, which is what a\n * person writing one expects; a file's own goes at the very top.\n */\n lendFirstComment?: boolean\n}\n\nexport function readModule(source: string, sibling: Sibling = () => undefined, { lendFirstComment = true }: ReadOptions = {}) {\n const file = ts.createSourceFile('module.tsx', source, ts.ScriptTarget.Latest, true)\n const declarations = new Map<string, Declared>()\n const aliases = new Map<string, ts.TypeNode>()\n const shapes = new Map<string, ts.TypeElement[]>()\n /** What each interface extends, as written \u2014 `Omit<IdentityMenuProps, 'compact'>` and all. */\n const bases = new Map<string, ts.ExpressionWithTypeArguments[]>()\n /** Which module each imported name came from. */\n const importedFrom = new Map<string, { specifier: string; imported: string }>()\n\n const propsTypeOf = (parameters: readonly ts.ParameterDeclaration[]): ts.TypeNode | undefined => parameters[0]?.type\n\n /**\n * The props type of `const X = \u2026`.\n *\n * A plain function expression carries it on its first parameter. `forwardRef`\n * carries it as its **second type argument** and leaves the inner function's\n * parameter bare \u2014 `TextInput`, whose `size` was missed until this read it.\n */\n const propsOfInitializer = (initializer: ts.Expression | undefined): ts.TypeNode | undefined => {\n if (!initializer) return undefined\n if (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer)) return propsTypeOf(initializer.parameters)\n if (ts.isCallExpression(initializer)) {\n const callee = ts.isPropertyAccessExpression(initializer.expression) ? initializer.expression.name.text : ts.isIdentifier(initializer.expression) ? initializer.expression.text : ''\n if (callee === 'forwardRef' && initializer.typeArguments?.[1]) return initializer.typeArguments[1]\n // `memo(function X({ \u2026 }: Props) { \u2026 })` and anything else that wraps a\n // function written out at the call.\n const wrapped = initializer.arguments.find((argument) => ts.isArrowFunction(argument) || ts.isFunctionExpression(argument))\n if (wrapped) return propsTypeOf((wrapped as ts.ArrowFunction | ts.FunctionExpression).parameters)\n }\n return undefined\n }\n\n /**\n * `const Row: FC<RowProps> = ({ \u2026 }) => \u2026` leaves the parameter bare: the\n * props are the annotation's type argument \u2014 `FC`, `FunctionComponent`,\n * `React.FC`, `React.FunctionComponent`.\n */\n const propsOfAnnotation = (type: ts.TypeNode | undefined): ts.TypeNode | undefined => {\n if (!type || !ts.isTypeReferenceNode(type)) return undefined\n const named = ts.isIdentifier(type.typeName) ? type.typeName.text : type.typeName.right.text\n return named === 'FC' || named === 'FunctionComponent' ? type.typeArguments?.[0] : undefined\n }\n\n // The file's header comment: the first `/**` above the first thing that is\n // not an import. It belongs to the file, whatever export happens to follow it.\n const opening = file.statements.find((statement) => !ts.isImportDeclaration(statement))\n const headerPos = opening ? ((ts.getLeadingCommentRanges(source, opening.getFullStart()) ?? []).find((range) => source.slice(range.pos, range.pos + 3) === '/**')?.pos ?? null) : null\n // A file that opens with its own comment, above its imports \u2014 Peek's and Ship's\n // way \u2014 has its header there, so the comment on its first declaration is that\n // declaration's own. Only a file with no such comment lends the first one it has.\n const topPos = file.statements[0] ? ((ts.getLeadingCommentRanges(source, file.statements[0].getFullStart()) ?? []).find((range) => source.slice(range.pos, range.pos + 3) === '/**')?.pos ?? null) : null\n // An app lends no comment to the file but one above its imports: in a file\n // with no imports the first comment sits on the first part, and is the part's.\n const aboveImports = !!file.statements[0] && ts.isImportDeclaration(file.statements[0])\n const refused = lendFirstComment ? (topPos ?? headerPos) : aboveImports ? topPos : null\n\n for (const statement of file.statements) {\n if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {\n const bindings = statement.importClause?.namedBindings\n if (bindings && ts.isNamedImports(bindings)) {\n for (const element of bindings.elements) importedFrom.set(element.name.text, { specifier: statement.moduleSpecifier.text, imported: (element.propertyName ?? element.name).text })\n }\n }\n // `export type { TopicRowProps } from './TopicRow'` hands a type on without\n // declaring it: a file that asks this one for it is sent on to the next.\n if (ts.isExportDeclaration(statement) && statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier) && statement.exportClause && ts.isNamedExports(statement.exportClause)) {\n for (const element of statement.exportClause.elements) importedFrom.set(element.name.text, { specifier: statement.moduleSpecifier.text, imported: (element.propertyName ?? element.name).text })\n }\n if (ts.isTypeAliasDeclaration(statement)) aliases.set(statement.name.text, statement.type)\n if (ts.isInterfaceDeclaration(statement)) {\n shapes.set(statement.name.text, [...statement.members])\n // The whole clause, not its name: `extends Omit<IdentityMenuProps,\n // 'compact'>` reads as the name `Omit` and loses both the type it wraps\n // and the key it drops.\n const extended = (statement.heritageClauses ?? []).flatMap((clause) => [...clause.types])\n if (extended.length) bases.set(statement.name.text, extended)\n }\n if (ts.isTypeAliasDeclaration(statement) && ts.isTypeLiteralNode(statement.type)) shapes.set(statement.name.text, [...statement.type.members])\n\n // Every top-level function, class and constant, exported or not. The package\n // exports at the declaration, so for it the two are the same; an app also\n // writes `function Row() {\u2026}` and `export { Row }` or `export default Row`\n // further down, and the name is still read here, with its comment and props.\n if (ts.isClassDeclaration(statement)) {\n // `class ErrorBoundary extends Component<Props, State>`: its props are the\n // first type argument of what it extends. `export default class extends \u2026`\n // has no name of its own, and is kept under `default`.\n const base = (statement.heritageClauses ?? []).find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword)?.types[0]\n const name = statement.name?.text ?? (ts.getModifiers(statement)?.some((m) => m.kind === ts.SyntaxKind.DefaultKeyword) ? 'default' : null)\n if (name) declarations.set(name, { doc: docAbove(source, statement, refused), deprecated: false, propsType: base?.typeArguments?.[0] })\n continue\n }\n // `export default memo(() => \u2026)` and `export default function () {\u2026}`: a part\n // an app writes as its file's default, with no name of its own. Kept under\n // `default`, with its comment and its props.\n if (ts.isExportAssignment(statement) && !statement.isExportEquals && !ts.isIdentifier(statement.expression)) {\n declarations.set('default', { doc: docAbove(source, statement, refused), deprecated: false, propsType: propsOfInitializer(statement.expression) })\n continue\n }\n if (ts.isFunctionDeclaration(statement) && !statement.name && ts.getModifiers(statement)?.some((m) => m.kind === ts.SyntaxKind.DefaultKeyword)) {\n declarations.set('default', { doc: docAbove(source, statement, refused), deprecated: false, propsType: propsTypeOf(statement.parameters) })\n continue\n }\n if (!ts.isFunctionDeclaration(statement) && !ts.isVariableStatement(statement)) continue\n const doc = docAbove(source, statement, refused)\n const deprecated = /(^|\\n)@deprecated\\b/.test(doc) || /\\*\\s*@deprecated\\b/.test(source.slice(Math.max(0, statement.getFullStart()), statement.getStart()))\n\n if (ts.isFunctionDeclaration(statement) && statement.name) {\n // Overloads: the first signature carries the comment and the props a caller\n // sees; a later one, or the body, only fills in a comment the first lacks.\n const held = declarations.get(statement.name.text)\n if (held) {\n if (!held.doc && doc) held.doc = doc\n continue\n }\n declarations.set(statement.name.text, { doc, deprecated, propsType: propsTypeOf(statement.parameters) })\n continue\n }\n if (ts.isVariableStatement(statement)) {\n for (const declaration of statement.declarationList.declarations) {\n if (!ts.isIdentifier(declaration.name)) continue\n declarations.set(declaration.name.text, { doc, deprecated, propsType: propsOfInitializer(declaration.initializer) ?? propsOfAnnotation(declaration.type) })\n }\n }\n }\n /**\n * A type's props and its word-choices, **resolved in the file that declares\n * them**.\n *\n * This is the whole shape of the thing, and the reason for it is a bug that\n * looked like nothing: a `ts.TypeElement` carries positions into *its own*\n * source text, so handing a sibling's node to this file's `getText`, `aliases`\n * and `docAbove` reads the wrong file at those offsets. `ToolbarButton` came\n * out with `variant: \"ats over what it a\"` and `children: \"omeAndEndK\"` \u2014\n * real prop names, and slices of another file for their types. Nothing caught\n * it: the names were right, and the cross-check against `react-docgen`\n * compared names.\n *\n * So a sibling never returns nodes. It returns finished props, read by the\n * module that owns them, and this file only merges them.\n */\n const EMPTY: Resolved = { props: [], variants: [] }\n\n /** The keys named by an `Omit`/`Pick` argument: `'a'` or `'a' | 'b'`. */\n const keysOf = (type: ts.TypeNode | undefined): string[] | null => {\n if (!type) return null\n if (ts.isLiteralTypeNode(type) && ts.isStringLiteral(type.literal)) return [type.literal.text]\n if (!ts.isUnionTypeNode(type)) return null\n const keys: string[] = []\n for (const member of type.types) {\n if (!ts.isLiteralTypeNode(member) || !ts.isStringLiteral(member.literal)) return null\n keys.push(member.literal.text)\n }\n return keys\n }\n\n /** `Omit` drops the keys it names, `Pick` keeps only them. Unreadable keys change nothing. */\n const narrow = (resolved: Resolved, how: 'Omit' | 'Pick', keys: string[] | null): Resolved => {\n if (!keys) return resolved\n const named = new Set(keys)\n const keep = (name: string) => (how === 'Omit' ? !named.has(name) : named.has(name))\n return { props: resolved.props.filter((prop) => keep(prop.name)), variants: resolved.variants.filter((variant) => keep(variant.prop)) }\n }\n\n /** The first of each name wins, so what a type declares itself beats what it inherits. */\n const merge = (parts: Resolved[]): Resolved => {\n const props: EntryProp[] = []\n const variants: EntryVariant[] = []\n const seenProp = new Set<string>()\n const seenVariant = new Set<string>()\n for (const part of parts) {\n for (const prop of part.props) if (!seenProp.has(prop.name)) (seenProp.add(prop.name), props.push(prop))\n for (const variant of part.variants) if (!seenVariant.has(variant.prop)) (seenVariant.add(variant.prop), variants.push(variant))\n }\n return { props, variants }\n }\n\n /**\n * What a prop takes, in a word a person reads. The type as written is the\n * fallback, not the answer: `(next: string) => void` tells a reader nothing\n * they cannot guess, and \"a handler\" tells them what to pass.\n */\n const takes = (type: ts.TypeNode | undefined, values: string[] | null): string => {\n if (values) return values.join(' | ')\n if (!type) return 'anything'\n const written = type.getText(file).replace(/\\s+/g, ' ').trim()\n if (written === 'boolean') return 'true/false'\n if (written === 'number') return 'number'\n if (written === 'string') return 'text'\n if (/^React(Node|Element)\\b/.test(written)) return 'anything'\n if (written.includes('=>')) return 'a handler'\n return written.length > 60 ? `${written.slice(0, 57)}\u2026` : written\n }\n\n /** Members of this file, read with this file's text and aliases. */\n const fromMembers = (members: readonly ts.TypeElement[]): Resolved => {\n const props: EntryProp[] = []\n const variants: EntryVariant[] = []\n for (const member of members) {\n const name = propName(member)\n if (name === null || !ts.isPropertySignature(member)) continue\n const values = literalUnion(member.type, aliases)\n const note = firstSentence(docAbove(source, member))\n props.push({ name, takes: takes(member.type, values), required: !member.questionToken, note: note || null })\n if (values) variants.push({ prop: name, values })\n }\n return { props, variants }\n }\n\n const resolveNode = (type: ts.TypeNode | undefined, seen: Set<string>): Resolved => {\n if (!type || seen.size > 12) return EMPTY\n // `{ tone?: 'primary' | 'secondary' }` written out at the parameter.\n if (ts.isTypeLiteralNode(type)) return fromMembers(type.members)\n if (ts.isIntersectionTypeNode(type)) return merge(type.types.map((side) => resolveNode(side, seen)))\n if (ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName)) {\n const named = type.typeName.text\n if (named === 'Omit' || named === 'Pick') {\n return narrow(resolveNode(type.typeArguments?.[0], seen), named, keysOf(type.typeArguments?.[1]))\n }\n return resolveName(named, seen)\n }\n return EMPTY\n }\n\n /** A heritage clause is not a `TypeNode`, and carries the same `Omit<\u2026>` shapes. */\n const resolveBase = (base: ts.ExpressionWithTypeArguments, seen: Set<string>): Resolved => {\n if (!ts.isIdentifier(base.expression)) return EMPTY\n const named = base.expression.text\n if (named === 'Omit' || named === 'Pick') {\n return narrow(resolveNode(base.typeArguments?.[0], seen), named, keysOf(base.typeArguments?.[1]))\n }\n return resolveName(named, seen)\n }\n\n /**\n * A named type: its own props, plus everything it extends **within this\n * package**.\n *\n * It stops at React and Base UI on purpose. `ToolbarButtonProps extends\n * IconButtonProps` is ours, and `variant`, `pressed` and `tooltip` are things\n * `ToolbarButton` genuinely takes; `ButtonProps extends\n * ComponentPropsWithRef<'button'>` is the DOM, and listing `onCopy` and\n * `spellCheck` would bury the answer. The rule is where the type is declared,\n * not what it is called.\n */\n function resolveName(name: string, seen: Set<string>): Resolved {\n if (seen.has(name) || seen.size > 12) return EMPTY\n seen.add(name)\n const own = shapes.get(name)\n if (own) {\n const inherited = (bases.get(name) ?? []).map((base) => resolveBase(base, seen))\n return merge([fromMembers(own), ...inherited])\n }\n // `type ToolbarInputProps = TextInputProps` \u2014 an alias, not an interface.\n const alias = aliases.get(name)\n if (alias) return resolveNode(alias, seen)\n // Not declared here at all. Follow the import; the caller says where it may go.\n const from = importedFrom.get(name)\n return (from ? sibling(from.specifier, from.imported) : undefined) ?? EMPTY\n }\n\n /** What one declaration's first parameter takes. */\n const resolve = (propsType: ts.TypeNode | undefined): Resolved => resolveNode(propsType, new Set())\n\n // The file's own description, for an app's file of one part: the first `/**`\n // at the very top, above the imports \u2014 where Peek and Ship write it \u2014 or else\n // the one directly above the first thing that is not an import.\n const jsdocAt = (node: ts.Node | undefined) => (node ? (ts.getLeadingCommentRanges(source, node.getFullStart()) ?? []).find((range) => source.slice(range.pos, range.pos + 3) === '/**') : undefined)\n const headerRange = jsdocAt(file.statements[0]) ?? jsdocAt(opening)\n return { declarations, headerDoc: headerRange ? headerComment(source, headerRange) : '', resolve, resolveName: (name: string) => resolveName(name, new Set()) }\n}\n\n/** The file's own header comment, cleaned the way `docAbove` cleans a declaration's. */\nfunction headerComment(source: string, range: ts.CommentRange): string {\n return source\n .slice(range.pos, range.end)\n .split(/\\r?\\n/)\n .map((line) => line.trim().replace(/^\\/\\*\\*/, '').replace(/\\*\\/$/, '').replace(/^\\*/, '').trim())\n .join('\\n')\n .trim()\n}\n\n/** The `title` a stories file gives Storybook, and the stories it exports. */\nexport function readStories(source: string): { title: string | null; stories: string[] } {\n const file = ts.createSourceFile('x.stories.tsx', source, ts.ScriptTarget.Latest, true)\n let title: string | null = null\n const stories: string[] = []\n for (const statement of file.statements) {\n if (ts.isVariableStatement(statement)) {\n for (const declaration of statement.declarationList.declarations) {\n if (!ts.isIdentifier(declaration.name)) continue\n const initializer = declaration.initializer\n const object = initializer && ts.isSatisfiesExpression(initializer) ? initializer.expression : initializer\n if (declaration.name.text === 'meta' && object && ts.isObjectLiteralExpression(object)) {\n for (const property of object.properties) {\n if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && property.name.text === 'title' && ts.isStringLiteral(property.initializer)) {\n title = property.initializer.text\n }\n }\n }\n const exported = ts.getModifiers(statement)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)\n if (exported && declaration.name.text !== 'meta') stories.push(declaration.name.text)\n }\n }\n }\n return { title, stories }\n}\n\nconst isAllCaps = (name: string) => /^[A-Z0-9_]+$/.test(name)\n\n/** What a name is. A constant and a function are both helpers; only a `use\u2026` is a hook. */\nfunction kindOf(name: string): EntryKind {\n if (/^use[A-Z]/.test(name)) return 'hook'\n return /^[A-Z]/.test(name) && !isAllCaps(name) ? 'component' : 'helper'\n}\n\n/** What UIG-8's enumeration says this component owns. */\nfunction behavioursOf(name: string): EntryBehaviour[] {\n return OWNED_BEHAVIOURS.filter((owned) => owned.owners.includes(name)).map((owned) => ({ id: owned.id, behaviour: owned.behaviour }))\n}\n\n/**\n * Read the repository and return the catalogue.\n *\n * Throws on anything it cannot explain \u2014 a missing sibling, a name with no\n * purpose anywhere. A registry that quietly drops what it could not read is\n * worse than no registry, because a reader cannot tell the difference between\n * \"we have nothing for that\" and \"the builder gave up\".\n */\nexport function buildRegistry({ root = process.cwd(), repo = 'estiva-ui' }: BuildOptions = {}): Registry {\n const src = join(root, 'src')\n const manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')) as { name: string; version: string }\n const files = new Set(readdirSync(src))\n const exported = readIndexExports(readFileSync(join(src, 'index.ts'), 'utf8'))\n const values = exported.filter((entry) => !entry.isType)\n\n type Module = ReturnType<typeof readModule> & { file: string }\n const modules = new Map<string, Module>()\n const moduleOf = (name: string): Module => {\n const held = modules.get(name)\n if (held) return held\n const file = ['.tsx', '.ts'].map((extension) => `${name}${extension}`).find((candidate) => files.has(candidate))\n if (!file) throw new Error(`src/index.ts exports from './${name}', which is not a file in src/`)\n // The callback lets one file's props type reach a type declared in another\n // \u2014 `ToolbarButtonProps extends IconButtonProps`. It is only called later,\n // by which time this module is in the cache, so the recursion terminates.\n const read = { ...readModule(readFileSync(join(src, file), 'utf8'), (specifier, typeName) => (specifier.startsWith('./') ? moduleOf(specifier.slice(2)).resolveName(typeName) : undefined)), file: `src/${file}` }\n modules.set(name, read)\n return read\n }\n\n const problems: string[] = []\n const entries: RegistryEntry[] = []\n // What each part looks like (UIG-25), read once per file.\n const looksCache = new Map<string, ReturnType<typeof parseForLooks>>()\n const looksFor = (file: string, name: string) => {\n if (!looksCache.has(file)) looksCache.set(file, parseForLooks(join(src, file.replace(/^src\\//, '')), readFileSync(join(src, file.replace(/^src\\//, '')), 'utf8')))\n return looksOf(looksCache.get(file)!, [name]).get(name) ?? []\n }\n\n for (const value of values) {\n const module = moduleOf(value.module)\n const declared = module.declarations.get(value.name)\n if (!declared) {\n problems.push(`${value.name} is exported from './${value.module}' but is not declared there`)\n continue\n }\n\n // A name with a page of its own takes its purpose from the page; the rest\n // are documented on a sibling's page, and take it from the comment above\n // the export. Every one of them has one \u2014 the build fails below if not.\n const pageFile = files.has(`${value.name}.mdx`) ? `src/${value.name}.mdx` : null\n const fromPage = pageFile ? firstSentence(pageOpening(readFileSync(join(root, pageFile), 'utf8'))) : ''\n const fromComment = firstSentence(declared.doc)\n const purpose = fromPage || fromComment\n if (!purpose) {\n problems.push(`${value.name} has no purpose: no opening paragraph on its page, and no doc comment above it in ${module.file}`)\n continue\n }\n\n // A name with stories of its own uses them; otherwise the sibling's, which\n // is the page that documents it.\n const storiesFile = files.has(`${value.name}.stories.tsx`) ? `${value.name}.stories.tsx` : files.has(`${value.module}.stories.tsx`) ? `${value.module}.stories.tsx` : null\n const stories = storiesFile ? readStories(readFileSync(join(src, storiesFile), 'utf8')) : { title: null, stories: [] }\n const title = stories.title\n const story = stories.stories.includes(value.name) ? value.name : stories.stories[0]\n\n const shape = module.resolve(declared.propsType)\n\n entries.push({\n name: value.name,\n repo,\n kind: kindOf(value.name),\n importPath: PACKAGE_IMPORT,\n sourceFile: module.file,\n purpose,\n purposeFrom: fromPage ? 'page' : 'comment',\n props: shape.props,\n variants: shape.variants,\n ownsBehaviours: behavioursOf(value.name),\n status: declared.deprecated ? 'deprecated' : 'stable',\n migrationStage: null,\n docsId: title ? `${sanitize(title)}--docs` : null,\n storyId: title && story ? toId(title, story) : null,\n docPage: pageFile,\n app: null,\n looks: kindOf(value.name) === 'component' ? looksFor(module.file, value.name) : [],\n })\n }\n\n if (problems.length) throw new Error(`the registry cannot be built:\\n ${problems.join('\\n ')}`)\n\n // What each part owns, from what it draws (B9): the Base UI parts in it, and\n // every part of the package inside it, followed; UIG-8's list is the floor.\n const moduleByName = new Map(values.map((v) => [v.name, v.module]))\n const drawing = new Map<string, { drawn: Map<string, Set<string>>; roots: Map<string, Set<string>>; imports: ReturnType<typeof importsOf> }>()\n const drawingOf = (moduleName: string) => {\n if (!drawing.has(moduleName)) {\n const file = moduleOf(moduleName).file\n const sf = ts.createSourceFile(file, readFileSync(join(root, file), 'utf8'), ts.ScriptTarget.Latest, true, file.endsWith('x') ? ts.ScriptKind.TSX : ts.ScriptKind.TS)\n drawing.set(moduleName, { drawn: drawnIn(sf), roots: rootsIn(sf), imports: importsOf(sf) })\n }\n return drawing.get(moduleName)!\n }\n const owns = (name: string, seen: Set<string>): Set<string> => {\n const out = new Set(behavioursOf(name).map((b) => b.id))\n const moduleName = moduleByName.get(name)\n if (!moduleName || seen.has(name)) return out\n seen.add(name)\n const { drawn, roots, imports } = drawingOf(moduleName)\n // The Base UI parts it draws, anywhere in it.\n for (const tag of drawn.get(name) ?? []) {\n const [local, piece] = splitTag(tag)\n const from = imports.get(local)\n if (from && isBaseUi(from.specifier)) for (const id of baseUiBehaviours(from.imported, piece)) out.add(id)\n }\n // The parts it is: what it hands back at its root.\n for (const tag of roots.get(name) ?? []) {\n const [local] = splitTag(tag)\n const from = imports.get(local)\n const part = from?.specifier.startsWith('./') ? from.imported : !from && local !== name ? local : undefined\n if (part && moduleByName.has(part)) for (const id of handedOn(part, owns(part, seen))) out.add(id)\n }\n return out\n }\n for (const entry of entries) if (entry.kind === 'component') entry.ownsBehaviours = asBehaviours(owns(entry.name, new Set()))\n\n entries.sort((a, b) => a.name.localeCompare(b.name))\n\n return {\n schemaVersion: SCHEMA_VERSION,\n builtFrom: {\n kind: 'package',\n repo,\n package: manifest.name,\n packageVersion: manifest.version,\n exports: values.length,\n typeExports: exported.length - values.length,\n files: null,\n },\n storybook: {\n docsPath: '/?path=/docs/{docsId}',\n storyPath: '/?path=/story/{storyId}',\n devUrl: 'http://localhost:6008',\n },\n entries,\n // Nothing is excluded: every value export is an entry, helpers and the one\n // hook included, each marked by `kind`. The field stays because the count\n // has to reconcile out loud \u2014 see validateRegistry.\n excluded: [],\n filesWithoutParts: [],\n }\n}\n\n/** The committed file's text, so a check and a write produce the same bytes. */\nexport function serializeRegistry(registry: Registry): string {\n return `${JSON.stringify(registry, null, 2)}\\n`\n}\n", "/**\n * What a part owns, worked out from what it draws (Katerina's ruling B9,\n * 25 September).\n *\n * The plan's Gate 0 asked for \"the behaviours it owns \u2014 derived from which Base\n * UI parts it imports\". Until 0.36.0 only \"is built on Base UI\" was; the rest\n * was UIG-8's hand list of owners, which is right for the part that does the\n * work and silent for every part built from it: ConfirmDialog draws DialogShell,\n * whose page says it keeps focus inside, and the catalogue listed no focus for\n * ConfirmDialog. Every app entry listed nothing at all.\n *\n * Now a part owns:\n *\n * - what the Base UI parts it draws do, from UIG-8's enumeration (`baseUi` on\n * each behaviour, read from Base UI's source): all of it for a whole part\n * (`Menu.Root`), what it is for a piece (`Menu.Item`);\n * - what the whole of the part it **is** does (floating, focus, keys, scroll):\n * the part it hands back at its root, followed through parts inside parts, in\n * the package and in an app. ConfirmDialog returns a DialogShell, so it keeps\n * focus inside; a page with a menu somewhere in it does not float, and a\n * tooltip's floating stays the tooltip's;\n * - and, in the package, what UIG-8's list says (the floor: a part like `Link`\n * is reachable with Tab without any Base UI in it).\n *\n * Read from the code: a JSX tag inside the part's own declaration, or inside a\n * function of the same file it draws. A root on one branch of a condition\n * still counts, so the list says what a part can be, not what one screen shows.\n */\nimport ts from 'typescript'\nimport { OWNED_BEHAVIOURS } from '../eslint/index'\nimport type { EntryBehaviour } from './schema'\n\n/** `@base-ui/react`, its sub-paths, and the old `@base-ui-components/react` spelling. */\nexport const isBaseUi = (specifier: string) => /^@base-ui(?:-components)?\\/react(?:\\/|$)/.test(specifier)\n\n/**\n * What drawing a Base UI part gives, by behaviour id. The whole part (`Menu.Root`,\n * or a part of one piece: `<Separator>`, `<Toggle>`) does all UIG-8 lists for it;\n * a piece of one (`Menu.Item`, `Toolbar.Button`) only says what it is.\n */\nexport function baseUiBehaviours(part: string, piece?: string): string[] {\n const whole = !piece || piece === 'Root' || piece === 'Provider'\n return OWNED_BEHAVIOURS.filter((owned) => owned.id === 'base-ui' || (owned.baseUi.includes(part) && (whole || owned.id === 'role'))).map((owned) => owned.id)\n}\n\n/**\n * What a part hands on to the parts drawn around it: what the whole thing does.\n * Being built on Base UI, a role and a Tab stop stay the inner part's: a banner\n * with a button in it is not itself reachable with Tab.\n */\nexport const HANDED_ON = new Set(['portal', 'press-outside', 'page-keys', 'focus', 'scroll-lock', 'follow', 'scroll'])\n\n/** A hint drawn beside a part: its floating is its own, never the part's. */\nexport const HINTS = new Set(['Tooltip', 'WithTooltip', 'TooltipProvider', 'PreviewCard'])\n\n/** What a part drawn inside another hands on to it. */\nexport const handedOn = (name: string, owned: Iterable<string>) => (HINTS.has(name) ? [] : [...owned].filter((id) => HANDED_ON.has(id)))\n\n/** Behaviour ids as the catalogue writes them: in UIG-8's order, each once. */\nexport function asBehaviours(ids: Iterable<string>): EntryBehaviour[] {\n const held = new Set(ids)\n return OWNED_BEHAVIOURS.filter((owned) => held.has(owned.id)).map((owned) => ({ id: owned.id, behaviour: owned.behaviour }))\n}\n\n/** A tag as written: `Dialog.Popup`, `Button`. */\nfunction tagText(tag: ts.JsxTagNameExpression): string | null {\n if (ts.isIdentifier(tag)) return tag.text\n if (ts.isPropertyAccessExpression(tag)) {\n const inner = tagText(tag.expression as ts.JsxTagNameExpression)\n return inner && `${inner}.${tag.name.text}`\n }\n return null\n}\n\n/** A tag's name and its piece: `['Dialog', 'Popup']`, `['Button', undefined]`. */\nexport const splitTag = (tag: string): [string, string | undefined] => {\n const [root, piece] = tag.split('.')\n return [root, piece]\n}\n\n/** Every tag drawn anywhere under `node`, as written. */\nfunction tagsUnder(node: ts.Node): Set<string> {\n const found = new Set<string>()\n const visit = (n: ts.Node) => {\n if (ts.isJsxOpeningElement(n) || ts.isJsxSelfClosingElement(n)) {\n const tag = tagText(n.tagName)\n if (tag && /^[A-Z]/.test(tag)) found.add(tag)\n }\n ts.forEachChild(n, visit)\n }\n visit(node)\n return found\n}\n\n/**\n * For each name a file declares at its top (a function, a `const`, a class):\n * the tags drawn inside it, with the file's own functions it draws followed, so\n * what is left are names the file imports or declares without a body.\n */\nexport function drawnIn(sf: ts.SourceFile): Map<string, Set<string>> {\n const direct = new Map<string, Set<string>>()\n for (const statement of sf.statements) {\n if ((ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name) direct.set(statement.name.text, tagsUnder(statement))\n else if (ts.isVariableStatement(statement)) {\n for (const d of statement.declarationList.declarations) if (ts.isIdentifier(d.name) && d.initializer) direct.set(d.name.text, tagsUnder(d.initializer))\n }\n }\n const closed = new Map<string, Set<string>>()\n for (const name of direct.keys()) {\n const out = new Set<string>()\n const seen = new Set([name])\n const stack = [name]\n while (stack.length) {\n for (const tag of direct.get(stack.pop() as string) ?? []) {\n out.add(tag)\n if (direct.has(tag) && !seen.has(tag)) {\n seen.add(tag)\n stack.push(tag)\n }\n }\n }\n closed.set(name, out)\n }\n return closed\n}\n\n/** The tags an expression hands back at its top: both sides of a condition, never a fragment's children. */\nfunction rootsOfExpression(e: ts.Node | undefined, out: Set<string>): void {\n if (!e) return\n if (ts.isParenthesizedExpression(e) || ts.isAsExpression(e) || ts.isSatisfiesExpression(e) || ts.isNonNullExpression(e)) return rootsOfExpression(e.expression, out)\n if (ts.isConditionalExpression(e)) {\n rootsOfExpression(e.whenTrue, out)\n rootsOfExpression(e.whenFalse, out)\n return\n }\n if (ts.isBinaryExpression(e)) {\n if (e.operatorToken.kind !== ts.SyntaxKind.AmpersandAmpersandToken) rootsOfExpression(e.left, out)\n rootsOfExpression(e.right, out)\n return\n }\n // A fragment is several things side by side (a page and the dialog it opens):\n // the part is none of them alone.\n if (ts.isJsxFragment(e)) return\n const tag = ts.isJsxElement(e) ? tagText(e.openingElement.tagName) : ts.isJsxSelfClosingElement(e) ? tagText(e.tagName) : null\n if (tag && /^[A-Z]/.test(tag)) out.add(tag)\n}\n\n/** The tags a function hands back: every `return`, or an arrow's body, never a nested function's. */\nfunction rootsOfFunction(fn: ts.Node): Set<string> {\n const out = new Set<string>()\n if (ts.isArrowFunction(fn) && !ts.isBlock(fn.body)) rootsOfExpression(fn.body, out)\n const visit = (n: ts.Node) => {\n if (n !== fn && (ts.isFunctionLike(n) || ts.isClassLike(n))) return\n if (ts.isReturnStatement(n)) rootsOfExpression(n.expression, out)\n ts.forEachChild(n, visit)\n }\n visit(fn)\n return out\n}\n\n/** The function a declaration's value is: itself, or the one inside `forwardRef(\u2026)`, `memo(\u2026)`. */\nfunction functionOf(node: ts.Node | undefined): ts.Node | undefined {\n if (!node) return undefined\n if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node)) return node\n if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isSatisfiesExpression(node)) return functionOf(node.expression)\n if (ts.isCallExpression(node)) for (const argument of node.arguments) {\n const fn = functionOf(argument)\n if (fn) return fn\n }\n return undefined\n}\n\n/**\n * For each function a file declares at its top: the parts it **is** \u2014 the tags it\n * hands back at its root, following the file's own functions it hands back.\n * `ConfirmDialog` returns a `DialogShell`, so it is one; a page with a menu\n * somewhere in it is not a menu.\n */\nexport function rootsIn(sf: ts.SourceFile): Map<string, Set<string>> {\n const direct = new Map<string, Set<string>>()\n for (const statement of sf.statements) {\n if (ts.isFunctionDeclaration(statement) && statement.name) direct.set(statement.name.text, rootsOfFunction(statement))\n else if (ts.isVariableStatement(statement)) {\n for (const d of statement.declarationList.declarations) {\n const fn = functionOf(d.initializer)\n if (ts.isIdentifier(d.name) && fn) direct.set(d.name.text, rootsOfFunction(fn))\n }\n }\n }\n const closed = new Map<string, Set<string>>()\n for (const name of direct.keys()) {\n const out = new Set<string>()\n const seen = new Set([name])\n const stack = [name]\n while (stack.length) {\n for (const tag of direct.get(stack.pop() as string) ?? []) {\n if (direct.has(tag)) {\n if (!seen.has(tag)) {\n seen.add(tag)\n stack.push(tag)\n }\n } else out.add(tag)\n }\n }\n closed.set(name, out)\n }\n return closed\n}\n\n/** Each imported value name \u2192 where it came from. */\nexport function importsOf(sf: ts.SourceFile): Map<string, { specifier: string; imported: string }> {\n const out = new Map<string, { specifier: string; imported: string }>()\n for (const statement of sf.statements) {\n if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) continue\n const clause = statement.importClause\n if (!clause || clause.isTypeOnly) continue\n const specifier = statement.moduleSpecifier.text\n if (clause.name) out.set(clause.name.text, { specifier, imported: 'default' })\n const bindings = clause.namedBindings\n if (bindings && ts.isNamedImports(bindings)) for (const e of bindings.elements) if (!e.isTypeOnly) out.set(e.name.text, { specifier, imported: (e.propertyName ?? e.name).text })\n }\n return out\n}\n", "import { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join, resolve as resolvePath } from 'node:path'\nimport ts from 'typescript'\n\n/**\n * What a component looks like, read from its source: every class list it\n * writes (UIG-25). Shared by the catalogue, which records each part's looks in\n * `registry.json`, and by `estiva/no-copied-look`, which compares a class list\n * typed by hand against them \u2014 so the two always mean the same thing by \"look\".\n *\n * A class list is read wherever it is written: a `className` (or any\n * `\u2026ClassName`), through `cn()`/`clsx()`, a ternary, a `&&`, a template, a\n * `const` in the file, or a class map indexed by a key; and every string that\n * is a class list on its own. A constant imported from another file is not\n * followed: a look written once and imported is not a copy.\n *\n * Only the **look words** count \u2014 colour, text, border, corner, shadow.\n * Placement (where it sits, how much room it takes) is everyone's and says\n * nothing about which part a list is copied from.\n */\n\n/** Where a thing sits and how much room it takes: never part of a look (the same list as `no-restyled-part`'s PLACEMENT). */\nconst PLACEMENT = [\n /^m[xytrblse]?-/,\n /^p[xytrblse]?-/,\n /^(?:w|h|size|min-w|min-h|max-w|max-h)-/,\n /^(?:hidden|block|inline|inline-block|inline-flex|inline-grid|flex|grid|contents|flow-root)$/,\n /^(?:grow|shrink)$|^(?:flex|basis|grow|shrink|order|gap|gap-x|gap-y|space-x|space-y|col|row|grid-cols|grid-rows|grid-flow|auto-cols|auto-rows)-/,\n /^(?:self|justify|justify-items|justify-self|items|place-content|place-items|place-self)-|^content-(?!\\[)/,\n /^(?:static|relative|absolute|fixed|sticky)$|^(?:inset|inset-x|inset-y|top|right|bottom|left|start|end|z)-/,\n /^(?:group|peer)(?:\\/[\\w-]+)?$/,\n]\nconst bare = (token: string) => token.replace(/^(?:[^:\\s[\\]]+:)+/, '')\nexport const isPlacementWord = (token: string) => PLACEMENT.some((pattern) => pattern.test(bare(token)))\n\n/** A word that could be a Tailwind class: lower case, dashes, variants, arbitrary values. */\nconst CLASSY = /^!?(?:[a-z0-9-]+:|\\[[^\\]\\s]+\\]:)*-?[a-z@][a-z0-9-]*(?:-\\[[^\\]\\s]+\\]|\\/[\\w.[\\]-]+|-[\\w.]+)*$|^\\[[^\\]\\s]+\\]$/\nconst words = (text: string) => text.split(/\\s+/).filter(Boolean)\nconst CLASS_FUNCTIONS = new Set(['cn', 'clsx', 'cx', 'twMerge', 'classNames'])\nconst CLASS_PROP = /^(?:className|[a-z][A-Za-z]*ClassName)$/\n\n/** A string is a class list on its own when every word could be a class, and two at least have a dash or a variant. */\nfunction isClassList(text: string): boolean {\n const list = words(text)\n return list.length >= 3 && list.every((w) => CLASSY.test(w)) && list.filter((w) => /[-:[]/.test(w)).length >= 2\n}\n\nexport interface ClassUnit {\n /** Every class of the list, placement included, as written. */\n tokens: string[]\n /** Its look words only. */\n look: string[]\n /** Offsets in the file, for a report. */\n start: number\n end: number\n /** A `className` (resolved through the file), or a string that is a class list on its own. */\n via: 'attribute' | 'literal'\n /** Where an escape for it is read: the element a `className` is on, or the string itself. */\n anchor: number\n /** The value of an exported `\u2026_CLASSES` constant: a shared look, where it is written once. */\n shared: boolean\n}\n\nconst CAP = 24\n\n/**\n * Every class list a file writes. `follow` resolves a name the file imports,\n * for a part's own look: what it draws includes a look it takes from a shared\n * file. A list being checked is never followed \u2014 using a shared look is not\n * copying it.\n */\nexport function classUnits(source: ts.SourceFile, follow?: (name: string) => ts.Expression | undefined): ClassUnit[] {\n const consts = new Map<string, ts.Expression>()\n const collect = (node: ts.Node) => {\n if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer && ts.isVariableDeclarationList(node.parent) && node.parent.flags & ts.NodeFlags.Const) {\n consts.set(node.name.text, node.initializer)\n }\n ts.forEachChild(node, collect)\n }\n collect(source)\n\n const product = (lists: string[][][]): string[][] => {\n let out: string[][] = [[]]\n for (const alternatives of lists) {\n const next: string[][] = []\n for (const a of out) for (const b of alternatives) if (next.length < CAP) next.push([...a, ...b])\n out = next\n }\n return out\n }\n const resolve = (node: ts.Node | undefined, depth = 0): string[][] => {\n if (!node || depth > 8) return [[]]\n if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return [words(node.text)]\n if (ts.isTemplateExpression(node)) return product([[words(node.head.text)], ...node.templateSpans.flatMap((span) => [resolve(span.expression, depth + 1), [words(span.literal.text)]])])\n if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isSatisfiesExpression(node) || ts.isNonNullExpression(node)) return resolve(node.expression, depth + 1)\n if (ts.isJsxExpression(node)) return resolve(node.expression, depth + 1)\n if (ts.isCallExpression(node)) return ts.isIdentifier(node.expression) && CLASS_FUNCTIONS.has(node.expression.text) ? product(node.arguments.map((a) => resolve(a, depth + 1))) : [[]]\n if (ts.isConditionalExpression(node)) return [...resolve(node.whenTrue, depth + 1), ...resolve(node.whenFalse, depth + 1)].slice(0, CAP)\n if (ts.isBinaryExpression(node)) {\n // Off first: a look is the part at rest, with each option taken one at a time, never all at once.\n if (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) return [[], ...resolve(node.right, depth + 1)]\n if (node.operatorToken.kind === ts.SyntaxKind.BarBarToken || node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) return [...resolve(node.left, depth + 1), ...resolve(node.right, depth + 1)].slice(0, CAP)\n return [[]]\n }\n if (ts.isArrayLiteralExpression(node)) return product(node.elements.map((e) => resolve(e, depth + 1)))\n if (ts.isObjectLiteralExpression(node)) return [[], node.properties.flatMap((p) => (p.name && (ts.isIdentifier(p.name) || ts.isStringLiteral(p.name)) ? words(p.name.text) : []))]\n if (ts.isIdentifier(node)) {\n const init = consts.get(node.text) ?? follow?.(node.text)\n return init ? resolve(init, depth + 1) : [[]]\n }\n if (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) {\n let target: ts.Expression | undefined = node.expression\n if (ts.isIdentifier(target)) target = consts.get(target.text) ?? follow?.(target.text)\n while (target && (ts.isAsExpression(target) || ts.isSatisfiesExpression(target) || ts.isParenthesizedExpression(target))) target = target.expression\n if (!target || !ts.isObjectLiteralExpression(target)) return [[]]\n const key = ts.isPropertyAccessExpression(node) ? node.name.text : ts.isStringLiteral(node.argumentExpression) ? node.argumentExpression.text : null\n return target.properties\n .filter((p): p is ts.PropertyAssignment => ts.isPropertyAssignment(p) && (key === null || (!!p.name && (ts.isIdentifier(p.name) || ts.isStringLiteral(p.name)) && p.name.text === key)))\n .flatMap((p) => resolve(p.initializer, depth + 1))\n .slice(0, CAP)\n }\n return [[]]\n }\n\n const units: ClassUnit[] = []\n const seen = new Set<string>()\n const sharedAt = (node: ts.Node) => {\n for (let at: ts.Node | undefined = node; at; at = at.parent) {\n if (ts.isVariableDeclaration(at)) return ts.isIdentifier(at.name) && /_CLASSES$/.test(at.name.text) && !!at.parent?.parent && ts.isVariableStatement(at.parent.parent) && !!at.parent.parent.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)\n }\n return false\n }\n // A string's escape is read above the line it starts: the widest thing that starts on that line.\n const lineStart = (node: ts.Node) => {\n const line = source.getLineAndCharacterOfPosition(node.getStart(source)).line\n let at = node\n while (at.parent && !ts.isSourceFile(at.parent) && source.getLineAndCharacterOfPosition(at.parent.getStart(source)).line === line) at = at.parent\n return at.getStart(source)\n }\n const add = (tokens: string[], node: ts.Node, via: ClassUnit['via'], anchor = via === 'literal' ? lineStart(node) : node.getStart(source)) => {\n const list = [...new Set(tokens.filter((t) => CLASSY.test(t)))]\n const look = list.filter((t) => !isPlacementWord(t))\n if (look.length === 0) return\n const key = `${via}:${node.getStart(source)}:${[...list].sort().join(' ')}`\n if (seen.has(key)) return\n seen.add(key)\n units.push({ tokens: list, look, start: node.getStart(source), end: node.getEnd(), via, anchor, shared: via === 'literal' && sharedAt(node) })\n }\n const visit = (node: ts.Node) => {\n if (ts.isJsxAttribute(node) && ts.isIdentifier(node.name) && CLASS_PROP.test(node.name.text) && node.initializer) {\n // An escape goes on the line above the element, as it does for every rule of the plugin.\n const element = node.parent.parent\n for (const alternative of resolve(node.initializer)) add(alternative, node, 'attribute', element.getStart(source))\n }\n if ((ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) && isClassList(node.text)) add(words(node.text), node, 'literal')\n ts.forEachChild(node, visit)\n }\n visit(source)\n return units\n}\n\n/** The function components a file declares, by name, with where each one's body is. */\nexport function componentsOf(source: ts.SourceFile): Map<string, { start: number; end: number }> {\n const found = new Map<string, { start: number; end: number }>()\n const fn = (node: ts.Expression | undefined): ts.Node | undefined => {\n let current = node\n while (current && ts.isCallExpression(current) && current.arguments.length) current = current.arguments[0]\n return current && (ts.isArrowFunction(current) || ts.isFunctionExpression(current)) ? current : undefined\n }\n for (const statement of source.statements) {\n if (ts.isFunctionDeclaration(statement) && statement.name && /^[A-Z]/.test(statement.name.text)) found.set(statement.name.text, { start: statement.getStart(source), end: statement.getEnd() })\n if (ts.isVariableStatement(statement)) {\n for (const declaration of statement.declarationList.declarations) {\n const body = fn(declaration.initializer)\n if (ts.isIdentifier(declaration.name) && /^[A-Z]/.test(declaration.name.text) && body) found.set(declaration.name.text, { start: body.getStart(source), end: body.getEnd() })\n }\n }\n }\n return found\n}\n\n/** A look is worth comparing when it has this many look words at least: fewer is a text style, not a part. */\nexport const MIN_LOOK_WORDS = 4\n\n/**\n * Each named component's looks: its class lists' look words, one space-joined\n * string per list, those with `MIN_LOOK_WORDS` or more. A list written outside\n * every component of the file (a top-level constant, a class map) belongs to\n * every component in it.\n */\nexport function looksOf(source: ts.SourceFile, names?: Iterable<string>): Map<string, string[]> {\n const components = componentsOf(source)\n const units = classUnits(source, importedConstants(source)).filter((u) => u.look.length >= MIN_LOOK_WORDS)\n const inside = (u: ClassUnit, r: { start: number; end: number }) => u.start >= r.start && u.start < r.end\n const out = new Map<string, string[]>()\n for (const name of names ?? components.keys()) {\n const range = components.get(name)\n const mine = units.filter((u) => (range ? inside(u, range) : false) || ![...components.values()].some((r) => inside(u, r)))\n out.set(name, [...new Set(mine.map((u) => u.look.join(' ')))])\n }\n return out\n}\n\n/** Read and parse a file for looks. */\nexport function parseForLooks(fileName: string, text: string): ts.SourceFile {\n return ts.createSourceFile(fileName, text, ts.ScriptTarget.Latest, true, fileName.endsWith('x') ? ts.ScriptKind.TSX : ts.ScriptKind.TS)\n}\n\n/** How much of a look a class list must share to be a copy of it (UIG-25, Katerina 24 September). */\nexport const MIN_SHARED = 4\nexport const MIN_COVER = 0.8\n\n/** The look words a list shares with a look, when it is a copy of it; otherwise null. */\nexport function copies(list: string[], look: string[]): string[] | null {\n const mine = new Set(list)\n const shared = look.filter((word) => mine.has(word))\n if (shared.length < MIN_SHARED) return null\n return shared.length / Math.min(list.length, look.length) >= MIN_COVER ? shared : null\n}\n\n/** The file a relative or `@/` import names, from the file that imports it. */\nfunction importTarget(fromFile: string, specifier: string): string | null {\n let base: string\n if (specifier.startsWith('.')) base = resolvePath(dirname(fromFile), specifier)\n else if (specifier.startsWith('@/')) {\n let dir = dirname(resolvePath(fromFile))\n while (!existsSync(join(dir, 'package.json')) && dirname(dir) !== dir) dir = dirname(dir)\n base = join(dir, 'src', specifier.slice(2))\n } else return null\n for (const candidate of [`${base}.ts`, `${base}.tsx`, join(base, 'index.ts')]) if (existsSync(candidate)) return candidate\n return null\n}\n\nconst constantsCache = new Map<string, Map<string, ts.Expression>>()\n/** A file's top-level `const`s, by name. */\nfunction constantsOf(file: string): Map<string, ts.Expression> {\n const cached = constantsCache.get(file)\n if (cached) return cached\n const found = new Map<string, ts.Expression>()\n const source = parseForLooks(file, readFileSync(file, 'utf8'))\n for (const statement of source.statements) {\n if (!ts.isVariableStatement(statement)) continue\n for (const d of statement.declarationList.declarations) if (ts.isIdentifier(d.name) && d.initializer) found.set(d.name.text, d.initializer)\n }\n constantsCache.set(file, found)\n return found\n}\n\n/** A resolver for the class constants a file imports from its own repo: `FIELD_BOX_CLASSES` from `./looks`. */\nexport function importedConstants(source: ts.SourceFile): (name: string) => ts.Expression | undefined {\n const imported = new Map<string, { file: string; name: string }>()\n for (const statement of source.statements) {\n if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) continue\n const bindings = statement.importClause?.namedBindings\n if (!bindings || !ts.isNamedImports(bindings)) continue\n const target = importTarget(source.fileName, statement.moduleSpecifier.text)\n if (!target) continue\n for (const element of bindings.elements) {\n const local = element.name.text\n if (/_CLASSES$/.test(element.propertyName?.text ?? local)) imported.set(local, { file: target, name: element.propertyName?.text ?? local })\n }\n }\n return (name) => {\n const from = imported.get(name)\n if (!from) return undefined\n try {\n return constantsOf(from.file).get(from.name)\n } catch {\n return undefined\n }\n }\n}\n\n/**\n * The shared looks a file declares: each exported `\u2026_CLASSES` constant, a string\n * or a map of strings, by name (`FIELD_SIZE_CLASSES.small`). A hand-typed copy of\n * one is told to use it.\n */\nexport function sharedLooksOf(source: ts.SourceFile): Map<string, string[]> {\n const out = new Map<string, string[]>()\n const lookWords = (text: string) => words(text).filter((w) => CLASSY.test(w) && !isPlacementWord(w))\n for (const statement of source.statements) {\n if (!ts.isVariableStatement(statement) || !statement.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) continue\n for (const d of statement.declarationList.declarations) {\n if (!ts.isIdentifier(d.name) || !/_CLASSES$/.test(d.name.text) || !d.initializer) continue\n let init: ts.Expression = d.initializer\n while (ts.isAsExpression(init) || ts.isSatisfiesExpression(init) || ts.isParenthesizedExpression(init)) init = init.expression\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const look = lookWords(init.text)\n if (look.length >= MIN_LOOK_WORDS) out.set(d.name.text, [look.join(' ')])\n } else if (ts.isObjectLiteralExpression(init)) {\n for (const p of init.properties) {\n if (!ts.isPropertyAssignment(p) || !p.name || !(ts.isIdentifier(p.name) || ts.isStringLiteral(p.name))) continue\n if (!(ts.isStringLiteral(p.initializer) || ts.isNoSubstitutionTemplateLiteral(p.initializer))) continue\n const look = lookWords(p.initializer.text)\n if (look.length >= MIN_LOOK_WORDS) out.set(`${d.name.text}.${p.name.text}`, [look.join(' ')])\n }\n }\n }\n }\n return out\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;AAiBA,SAAqB,gBAAAA,eAAc,mBAAmB;AACtD,SAAS,QAAAC,aAAY;AACrB,OAAOC,SAAQ;AACf,SAAS,oBAAAC,yBAAwB;;;ACQjC,OAAO,QAAQ;AACf,SAAS,wBAAwB;AAI1B,IAAM,WAAW,CAAC,cAAsB,2CAA2C,KAAK,SAAS;AAOjG,SAAS,iBAAiB,MAAc,OAA0B;AACvE,QAAM,QAAQ,CAAC,SAAS,UAAU,UAAU,UAAU;AACtD,SAAO,iBAAiB,OAAO,CAAC,UAAU,MAAM,OAAO,aAAc,MAAM,OAAO,SAAS,IAAI,MAAM,SAAS,MAAM,OAAO,OAAQ,EAAE,IAAI,CAAC,UAAU,MAAM,EAAE;AAC9J;AAOO,IAAM,YAAY,oBAAI,IAAI,CAAC,UAAU,iBAAiB,aAAa,SAAS,eAAe,UAAU,QAAQ,CAAC;AAG9G,IAAM,QAAQ,oBAAI,IAAI,CAAC,WAAW,eAAe,mBAAmB,aAAa,CAAC;AAGlF,IAAM,WAAW,CAAC,MAAc,UAA6B,MAAM,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,EAAE,OAAO,CAAC,OAAO,UAAU,IAAI,EAAE,CAAC;AAG/H,SAAS,aAAa,KAAyC;AACpE,QAAM,OAAO,IAAI,IAAI,GAAG;AACxB,SAAO,iBAAiB,OAAO,CAAC,UAAU,KAAK,IAAI,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,MAAM,IAAI,WAAW,MAAM,UAAU,EAAE;AAC7H;AAGA,SAAS,QAAQ,KAA6C;AAC5D,MAAI,GAAG,aAAa,GAAG,EAAG,QAAO,IAAI;AACrC,MAAI,GAAG,2BAA2B,GAAG,GAAG;AACtC,UAAM,QAAQ,QAAQ,IAAI,UAAqC;AAC/D,WAAO,SAAS,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI;AAAA,EAC3C;AACA,SAAO;AACT;AAGO,IAAM,WAAW,CAAC,QAA8C;AACrE,QAAM,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,GAAG;AACnC,SAAO,CAAC,MAAM,KAAK;AACrB;AAGA,SAAS,UAAU,MAA4B;AAC7C,QAAM,QAAQ,oBAAI,IAAY;AAC9B,QAAM,QAAQ,CAAC,MAAe;AAC5B,QAAI,GAAG,oBAAoB,CAAC,KAAK,GAAG,wBAAwB,CAAC,GAAG;AAC9D,YAAM,MAAM,QAAQ,EAAE,OAAO;AAC7B,UAAI,OAAO,SAAS,KAAK,GAAG,EAAG,OAAM,IAAI,GAAG;AAAA,IAC9C;AACA,OAAG,aAAa,GAAG,KAAK;AAAA,EAC1B;AACA,QAAM,IAAI;AACV,SAAO;AACT;AAOO,SAAS,QAAQ,IAA6C;AACnE,QAAM,SAAS,oBAAI,IAAyB;AAC5C,aAAW,aAAa,GAAG,YAAY;AACrC,SAAK,GAAG,sBAAsB,SAAS,KAAK,GAAG,mBAAmB,SAAS,MAAM,UAAU,KAAM,QAAO,IAAI,UAAU,KAAK,MAAM,UAAU,SAAS,CAAC;AAAA,aAC5I,GAAG,oBAAoB,SAAS,GAAG;AAC1C,iBAAW,KAAK,UAAU,gBAAgB,aAAc,KAAI,GAAG,aAAa,EAAE,IAAI,KAAK,EAAE,YAAa,QAAO,IAAI,EAAE,KAAK,MAAM,UAAU,EAAE,WAAW,CAAC;AAAA,IACxJ;AAAA,EACF;AACA,QAAM,SAAS,oBAAI,IAAyB;AAC5C,aAAW,QAAQ,OAAO,KAAK,GAAG;AAChC,UAAM,MAAM,oBAAI,IAAY;AAC5B,UAAM,OAAO,oBAAI,IAAI,CAAC,IAAI,CAAC;AAC3B,UAAM,QAAQ,CAAC,IAAI;AACnB,WAAO,MAAM,QAAQ;AACnB,iBAAW,OAAO,OAAO,IAAI,MAAM,IAAI,CAAW,KAAK,CAAC,GAAG;AACzD,YAAI,IAAI,GAAG;AACX,YAAI,OAAO,IAAI,GAAG,KAAK,CAAC,KAAK,IAAI,GAAG,GAAG;AACrC,eAAK,IAAI,GAAG;AACZ,gBAAM,KAAK,GAAG;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AACA,WAAO,IAAI,MAAM,GAAG;AAAA,EACtB;AACA,SAAO;AACT;AAGA,SAAS,kBAAkB,GAAwB,KAAwB;AACzE,MAAI,CAAC,EAAG;AACR,MAAI,GAAG,0BAA0B,CAAC,KAAK,GAAG,eAAe,CAAC,KAAK,GAAG,sBAAsB,CAAC,KAAK,GAAG,oBAAoB,CAAC,EAAG,QAAO,kBAAkB,EAAE,YAAY,GAAG;AACnK,MAAI,GAAG,wBAAwB,CAAC,GAAG;AACjC,sBAAkB,EAAE,UAAU,GAAG;AACjC,sBAAkB,EAAE,WAAW,GAAG;AAClC;AAAA,EACF;AACA,MAAI,GAAG,mBAAmB,CAAC,GAAG;AAC5B,QAAI,EAAE,cAAc,SAAS,GAAG,WAAW,wBAAyB,mBAAkB,EAAE,MAAM,GAAG;AACjG,sBAAkB,EAAE,OAAO,GAAG;AAC9B;AAAA,EACF;AAGA,MAAI,GAAG,cAAc,CAAC,EAAG;AACzB,QAAM,MAAM,GAAG,aAAa,CAAC,IAAI,QAAQ,EAAE,eAAe,OAAO,IAAI,GAAG,wBAAwB,CAAC,IAAI,QAAQ,EAAE,OAAO,IAAI;AAC1H,MAAI,OAAO,SAAS,KAAK,GAAG,EAAG,KAAI,IAAI,GAAG;AAC5C;AAGA,SAAS,gBAAgB,IAA0B;AACjD,QAAM,MAAM,oBAAI,IAAY;AAC5B,MAAI,GAAG,gBAAgB,EAAE,KAAK,CAAC,GAAG,QAAQ,GAAG,IAAI,EAAG,mBAAkB,GAAG,MAAM,GAAG;AAClF,QAAM,QAAQ,CAAC,MAAe;AAC5B,QAAI,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,GAAG,YAAY,CAAC,GAAI;AAC7D,QAAI,GAAG,kBAAkB,CAAC,EAAG,mBAAkB,EAAE,YAAY,GAAG;AAChE,OAAG,aAAa,GAAG,KAAK;AAAA,EAC1B;AACA,QAAM,EAAE;AACR,SAAO;AACT;AAGA,SAAS,WAAW,MAAgD;AAClE,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,GAAG,sBAAsB,IAAI,KAAK,GAAG,qBAAqB,IAAI,KAAK,GAAG,gBAAgB,IAAI,EAAG,QAAO;AACxG,MAAI,GAAG,0BAA0B,IAAI,KAAK,GAAG,eAAe,IAAI,KAAK,GAAG,sBAAsB,IAAI,EAAG,QAAO,WAAW,KAAK,UAAU;AACtI,MAAI,GAAG,iBAAiB,IAAI,EAAG,YAAW,YAAY,KAAK,WAAW;AACpE,UAAM,KAAK,WAAW,QAAQ;AAC9B,QAAI,GAAI,QAAO;AAAA,EACjB;AACA,SAAO;AACT;AAQO,SAAS,QAAQ,IAA6C;AACnE,QAAM,SAAS,oBAAI,IAAyB;AAC5C,aAAW,aAAa,GAAG,YAAY;AACrC,QAAI,GAAG,sBAAsB,SAAS,KAAK,UAAU,KAAM,QAAO,IAAI,UAAU,KAAK,MAAM,gBAAgB,SAAS,CAAC;AAAA,aAC5G,GAAG,oBAAoB,SAAS,GAAG;AAC1C,iBAAW,KAAK,UAAU,gBAAgB,cAAc;AACtD,cAAM,KAAK,WAAW,EAAE,WAAW;AACnC,YAAI,GAAG,aAAa,EAAE,IAAI,KAAK,GAAI,QAAO,IAAI,EAAE,KAAK,MAAM,gBAAgB,EAAE,CAAC;AAAA,MAChF;AAAA,IACF;AAAA,EACF;AACA,QAAM,SAAS,oBAAI,IAAyB;AAC5C,aAAW,QAAQ,OAAO,KAAK,GAAG;AAChC,UAAM,MAAM,oBAAI,IAAY;AAC5B,UAAM,OAAO,oBAAI,IAAI,CAAC,IAAI,CAAC;AAC3B,UAAM,QAAQ,CAAC,IAAI;AACnB,WAAO,MAAM,QAAQ;AACnB,iBAAW,OAAO,OAAO,IAAI,MAAM,IAAI,CAAW,KAAK,CAAC,GAAG;AACzD,YAAI,OAAO,IAAI,GAAG,GAAG;AACnB,cAAI,CAAC,KAAK,IAAI,GAAG,GAAG;AAClB,iBAAK,IAAI,GAAG;AACZ,kBAAM,KAAK,GAAG;AAAA,UAChB;AAAA,QACF,MAAO,KAAI,IAAI,GAAG;AAAA,MACpB;AAAA,IACF;AACA,WAAO,IAAI,MAAM,GAAG;AAAA,EACtB;AACA,SAAO;AACT;AAGO,SAAS,UAAU,IAAyE;AACjG,QAAM,MAAM,oBAAI,IAAqD;AACrE,aAAW,aAAa,GAAG,YAAY;AACrC,QAAI,CAAC,GAAG,oBAAoB,SAAS,KAAK,CAAC,GAAG,gBAAgB,UAAU,eAAe,EAAG;AAC1F,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,UAAU,OAAO,WAAY;AAClC,UAAM,YAAY,UAAU,gBAAgB;AAC5C,QAAI,OAAO,KAAM,KAAI,IAAI,OAAO,KAAK,MAAM,EAAE,WAAW,UAAU,UAAU,CAAC;AAC7E,UAAM,WAAW,OAAO;AACxB,QAAI,YAAY,GAAG,eAAe,QAAQ;AAAG,iBAAW,KAAK,SAAS,SAAU,KAAI,CAAC,EAAE,WAAY,KAAI,IAAI,EAAE,KAAK,MAAM,EAAE,WAAW,WAAW,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAAA;AAAA,EAClL;AACA,SAAO;AACT;;;AC9NA,SAAS,YAAY,oBAAoB;AACzC,SAAS,SAAS,MAAM,WAAW,mBAAmB;AACtD,OAAOC,SAAQ;AAoBf,IAAM,YAAY;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACA,IAAM,OAAO,CAAC,UAAkB,MAAM,QAAQ,qBAAqB,EAAE;AAC9D,IAAM,kBAAkB,CAAC,UAAkB,UAAU,KAAK,CAAC,YAAY,QAAQ,KAAK,KAAK,KAAK,CAAC,CAAC;AAGvG,IAAM,SAAS;AACf,IAAM,QAAQ,CAAC,SAAiB,KAAK,MAAM,KAAK,EAAE,OAAO,OAAO;AAChE,IAAM,kBAAkB,oBAAI,IAAI,CAAC,MAAM,QAAQ,MAAM,WAAW,YAAY,CAAC;AAC7E,IAAM,aAAa;AAGnB,SAAS,YAAY,MAAuB;AAC1C,QAAM,OAAO,MAAM,IAAI;AACvB,SAAO,KAAK,UAAU,KAAK,KAAK,MAAM,CAAC,MAAM,OAAO,KAAK,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,MAAM,QAAQ,KAAK,CAAC,CAAC,EAAE,UAAU;AAChH;AAkBA,IAAM,MAAM;AAQL,SAAS,WAAW,QAAuB,QAAmE;AACnH,QAAM,SAAS,oBAAI,IAA2B;AAC9C,QAAM,UAAU,CAAC,SAAkB;AACjC,QAAIA,IAAG,sBAAsB,IAAI,KAAKA,IAAG,aAAa,KAAK,IAAI,KAAK,KAAK,eAAeA,IAAG,0BAA0B,KAAK,MAAM,KAAK,KAAK,OAAO,QAAQA,IAAG,UAAU,OAAO;AAC3K,aAAO,IAAI,KAAK,KAAK,MAAM,KAAK,WAAW;AAAA,IAC7C;AACA,IAAAA,IAAG,aAAa,MAAM,OAAO;AAAA,EAC/B;AACA,UAAQ,MAAM;AAEd,QAAM,UAAU,CAAC,UAAoC;AACnD,QAAI,MAAkB,CAAC,CAAC,CAAC;AACzB,eAAW,gBAAgB,OAAO;AAChC,YAAM,OAAmB,CAAC;AAC1B,iBAAW,KAAK,IAAK,YAAW,KAAK,aAAc,KAAI,KAAK,SAAS,IAAK,MAAK,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;AAChG,YAAM;AAAA,IACR;AACA,WAAO;AAAA,EACT;AACA,QAAM,UAAU,CAAC,MAA2B,QAAQ,MAAkB;AACpE,QAAI,CAAC,QAAQ,QAAQ,EAAG,QAAO,CAAC,CAAC,CAAC;AAClC,QAAIA,IAAG,gBAAgB,IAAI,KAAKA,IAAG,gCAAgC,IAAI,EAAG,QAAO,CAAC,MAAM,KAAK,IAAI,CAAC;AAClG,QAAIA,IAAG,qBAAqB,IAAI,EAAG,QAAO,QAAQ,CAAC,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,GAAG,GAAG,KAAK,cAAc,QAAQ,CAAC,SAAS,CAAC,QAAQ,KAAK,YAAY,QAAQ,CAAC,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACvL,QAAIA,IAAG,0BAA0B,IAAI,KAAKA,IAAG,eAAe,IAAI,KAAKA,IAAG,sBAAsB,IAAI,KAAKA,IAAG,oBAAoB,IAAI,EAAG,QAAO,QAAQ,KAAK,YAAY,QAAQ,CAAC;AAC9K,QAAIA,IAAG,gBAAgB,IAAI,EAAG,QAAO,QAAQ,KAAK,YAAY,QAAQ,CAAC;AACvE,QAAIA,IAAG,iBAAiB,IAAI,EAAG,QAAOA,IAAG,aAAa,KAAK,UAAU,KAAK,gBAAgB,IAAI,KAAK,WAAW,IAAI,IAAI,QAAQ,KAAK,UAAU,IAAI,CAAC,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACrL,QAAIA,IAAG,wBAAwB,IAAI,EAAG,QAAO,CAAC,GAAG,QAAQ,KAAK,UAAU,QAAQ,CAAC,GAAG,GAAG,QAAQ,KAAK,WAAW,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG;AACvI,QAAIA,IAAG,mBAAmB,IAAI,GAAG;AAE/B,UAAI,KAAK,cAAc,SAASA,IAAG,WAAW,wBAAyB,QAAO,CAAC,CAAC,GAAG,GAAG,QAAQ,KAAK,OAAO,QAAQ,CAAC,CAAC;AACpH,UAAI,KAAK,cAAc,SAASA,IAAG,WAAW,eAAe,KAAK,cAAc,SAASA,IAAG,WAAW,sBAAuB,QAAO,CAAC,GAAG,QAAQ,KAAK,MAAM,QAAQ,CAAC,GAAG,GAAG,QAAQ,KAAK,OAAO,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG;AACvN,aAAO,CAAC,CAAC,CAAC;AAAA,IACZ;AACA,QAAIA,IAAG,yBAAyB,IAAI,EAAG,QAAO,QAAQ,KAAK,SAAS,IAAI,CAAC,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC;AACrG,QAAIA,IAAG,0BAA0B,IAAI,EAAG,QAAO,CAAC,CAAC,GAAG,KAAK,WAAW,QAAQ,CAAC,MAAO,EAAE,SAASA,IAAG,aAAa,EAAE,IAAI,KAAKA,IAAG,gBAAgB,EAAE,IAAI,KAAK,MAAM,EAAE,KAAK,IAAI,IAAI,CAAC,CAAE,CAAC;AACjL,QAAIA,IAAG,aAAa,IAAI,GAAG;AACzB,YAAM,OAAO,OAAO,IAAI,KAAK,IAAI,KAAK,SAAS,KAAK,IAAI;AACxD,aAAO,OAAO,QAAQ,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAAA,IAC9C;AACA,QAAIA,IAAG,2BAA2B,IAAI,KAAKA,IAAG,0BAA0B,IAAI,GAAG;AAC7E,UAAI,SAAoC,KAAK;AAC7C,UAAIA,IAAG,aAAa,MAAM,EAAG,UAAS,OAAO,IAAI,OAAO,IAAI,KAAK,SAAS,OAAO,IAAI;AACrF,aAAO,WAAWA,IAAG,eAAe,MAAM,KAAKA,IAAG,sBAAsB,MAAM,KAAKA,IAAG,0BAA0B,MAAM,GAAI,UAAS,OAAO;AAC1I,UAAI,CAAC,UAAU,CAACA,IAAG,0BAA0B,MAAM,EAAG,QAAO,CAAC,CAAC,CAAC;AAChE,YAAM,MAAMA,IAAG,2BAA2B,IAAI,IAAI,KAAK,KAAK,OAAOA,IAAG,gBAAgB,KAAK,kBAAkB,IAAI,KAAK,mBAAmB,OAAO;AAChJ,aAAO,OAAO,WACX,OAAO,CAAC,MAAkCA,IAAG,qBAAqB,CAAC,MAAM,QAAQ,QAAS,CAAC,CAAC,EAAE,SAASA,IAAG,aAAa,EAAE,IAAI,KAAKA,IAAG,gBAAgB,EAAE,IAAI,MAAM,EAAE,KAAK,SAAS,IAAK,EACtL,QAAQ,CAAC,MAAM,QAAQ,EAAE,aAAa,QAAQ,CAAC,CAAC,EAChD,MAAM,GAAG,GAAG;AAAA,IACjB;AACA,WAAO,CAAC,CAAC,CAAC;AAAA,EACZ;AAEA,QAAM,QAAqB,CAAC;AAC5B,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,WAAW,CAAC,SAAkB;AAClC,aAAS,KAA0B,MAAM,IAAI,KAAK,GAAG,QAAQ;AAC3D,UAAIA,IAAG,sBAAsB,EAAE,EAAG,QAAOA,IAAG,aAAa,GAAG,IAAI,KAAK,YAAY,KAAK,GAAG,KAAK,IAAI,KAAK,CAAC,CAAC,GAAG,QAAQ,UAAUA,IAAG,oBAAoB,GAAG,OAAO,MAAM,KAAK,CAAC,CAAC,GAAG,OAAO,OAAO,WAAW,KAAK,CAAC,MAAM,EAAE,SAASA,IAAG,WAAW,aAAa;AAAA,IAC5P;AACA,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,CAAC,SAAkB;AACnC,UAAM,OAAO,OAAO,8BAA8B,KAAK,SAAS,MAAM,CAAC,EAAE;AACzE,QAAI,KAAK;AACT,WAAO,GAAG,UAAU,CAACA,IAAG,aAAa,GAAG,MAAM,KAAK,OAAO,8BAA8B,GAAG,OAAO,SAAS,MAAM,CAAC,EAAE,SAAS,KAAM,MAAK,GAAG;AAC3I,WAAO,GAAG,SAAS,MAAM;AAAA,EAC3B;AACA,QAAM,MAAM,CAAC,QAAkB,MAAe,KAAuB,SAAS,QAAQ,YAAY,UAAU,IAAI,IAAI,KAAK,SAAS,MAAM,MAAM;AAC5I,UAAM,OAAO,CAAC,GAAG,IAAI,IAAI,OAAO,OAAO,CAAC,MAAM,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9D,UAAM,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;AACnD,QAAI,KAAK,WAAW,EAAG;AACvB,UAAM,MAAM,GAAG,GAAG,IAAI,KAAK,SAAS,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC;AACzE,QAAI,KAAK,IAAI,GAAG,EAAG;AACnB,SAAK,IAAI,GAAG;AACZ,UAAM,KAAK,EAAE,QAAQ,MAAM,MAAM,OAAO,KAAK,SAAS,MAAM,GAAG,KAAK,KAAK,OAAO,GAAG,KAAK,QAAQ,QAAQ,QAAQ,aAAa,SAAS,IAAI,EAAE,CAAC;AAAA,EAC/I;AACA,QAAM,QAAQ,CAAC,SAAkB;AAC/B,QAAIA,IAAG,eAAe,IAAI,KAAKA,IAAG,aAAa,KAAK,IAAI,KAAK,WAAW,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,aAAa;AAEhH,YAAM,UAAU,KAAK,OAAO;AAC5B,iBAAW,eAAe,QAAQ,KAAK,WAAW,EAAG,KAAI,aAAa,MAAM,aAAa,QAAQ,SAAS,MAAM,CAAC;AAAA,IACnH;AACA,SAAKA,IAAG,gBAAgB,IAAI,KAAKA,IAAG,gCAAgC,IAAI,MAAM,YAAY,KAAK,IAAI,EAAG,KAAI,MAAM,KAAK,IAAI,GAAG,MAAM,SAAS;AAC3I,IAAAA,IAAG,aAAa,MAAM,KAAK;AAAA,EAC7B;AACA,QAAM,MAAM;AACZ,SAAO;AACT;AAGO,SAAS,aAAa,QAAoE;AAC/F,QAAM,QAAQ,oBAAI,IAA4C;AAC9D,QAAM,KAAK,CAAC,SAAyD;AACnE,QAAI,UAAU;AACd,WAAO,WAAWA,IAAG,iBAAiB,OAAO,KAAK,QAAQ,UAAU,OAAQ,WAAU,QAAQ,UAAU,CAAC;AACzG,WAAO,YAAYA,IAAG,gBAAgB,OAAO,KAAKA,IAAG,qBAAqB,OAAO,KAAK,UAAU;AAAA,EAClG;AACA,aAAW,aAAa,OAAO,YAAY;AACzC,QAAIA,IAAG,sBAAsB,SAAS,KAAK,UAAU,QAAQ,SAAS,KAAK,UAAU,KAAK,IAAI,EAAG,OAAM,IAAI,UAAU,KAAK,MAAM,EAAE,OAAO,UAAU,SAAS,MAAM,GAAG,KAAK,UAAU,OAAO,EAAE,CAAC;AAC9L,QAAIA,IAAG,oBAAoB,SAAS,GAAG;AACrC,iBAAW,eAAe,UAAU,gBAAgB,cAAc;AAChE,cAAM,OAAO,GAAG,YAAY,WAAW;AACvC,YAAIA,IAAG,aAAa,YAAY,IAAI,KAAK,SAAS,KAAK,YAAY,KAAK,IAAI,KAAK,KAAM,OAAM,IAAI,YAAY,KAAK,MAAM,EAAE,OAAO,KAAK,SAAS,MAAM,GAAG,KAAK,KAAK,OAAO,EAAE,CAAC;AAAA,MAC9K;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGO,IAAM,iBAAiB;AAQvB,SAAS,QAAQ,QAAuB,OAAiD;AAC9F,QAAM,aAAa,aAAa,MAAM;AACtC,QAAM,QAAQ,WAAW,QAAQ,kBAAkB,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,UAAU,cAAc;AACzG,QAAM,SAAS,CAAC,GAAc,MAAsC,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE;AACtG,QAAM,MAAM,oBAAI,IAAsB;AACtC,aAAW,QAAQ,SAAS,WAAW,KAAK,GAAG;AAC7C,UAAM,QAAQ,WAAW,IAAI,IAAI;AACjC,UAAM,OAAO,MAAM,OAAO,CAAC,OAAO,QAAQ,OAAO,GAAG,KAAK,IAAI,UAAU,CAAC,CAAC,GAAG,WAAW,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC;AAC1H,QAAI,IAAI,MAAM,CAAC,GAAG,IAAI,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;AAAA,EAC/D;AACA,SAAO;AACT;AAGO,SAAS,cAAc,UAAkB,MAA6B;AAC3E,SAAOA,IAAG,iBAAiB,UAAU,MAAMA,IAAG,aAAa,QAAQ,MAAM,SAAS,SAAS,GAAG,IAAIA,IAAG,WAAW,MAAMA,IAAG,WAAW,EAAE;AACxI;AAeA,SAAS,aAAa,UAAkB,WAAkC;AACxE,MAAI;AACJ,MAAI,UAAU,WAAW,GAAG,EAAG,QAAO,YAAY,QAAQ,QAAQ,GAAG,SAAS;AAAA,WACrE,UAAU,WAAW,IAAI,GAAG;AACnC,QAAI,MAAM,QAAQ,YAAY,QAAQ,CAAC;AACvC,WAAO,CAAC,WAAW,KAAK,KAAK,cAAc,CAAC,KAAK,QAAQ,GAAG,MAAM,IAAK,OAAM,QAAQ,GAAG;AACxF,WAAO,KAAK,KAAK,OAAO,UAAU,MAAM,CAAC,CAAC;AAAA,EAC5C,MAAO,QAAO;AACd,aAAW,aAAa,CAAC,GAAG,IAAI,OAAO,GAAG,IAAI,QAAQ,KAAK,MAAM,UAAU,CAAC,EAAG,KAAI,WAAW,SAAS,EAAG,QAAO;AACjH,SAAO;AACT;AAEA,IAAM,iBAAiB,oBAAI,IAAwC;AAEnE,SAAS,YAAY,MAA0C;AAC7D,QAAM,SAAS,eAAe,IAAI,IAAI;AACtC,MAAI,OAAQ,QAAO;AACnB,QAAM,QAAQ,oBAAI,IAA2B;AAC7C,QAAM,SAAS,cAAc,MAAM,aAAa,MAAM,MAAM,CAAC;AAC7D,aAAW,aAAa,OAAO,YAAY;AACzC,QAAI,CAACC,IAAG,oBAAoB,SAAS,EAAG;AACxC,eAAW,KAAK,UAAU,gBAAgB,aAAc,KAAIA,IAAG,aAAa,EAAE,IAAI,KAAK,EAAE,YAAa,OAAM,IAAI,EAAE,KAAK,MAAM,EAAE,WAAW;AAAA,EAC5I;AACA,iBAAe,IAAI,MAAM,KAAK;AAC9B,SAAO;AACT;AAGO,SAAS,kBAAkB,QAAoE;AACpG,QAAM,WAAW,oBAAI,IAA4C;AACjE,aAAW,aAAa,OAAO,YAAY;AACzC,QAAI,CAACA,IAAG,oBAAoB,SAAS,KAAK,CAACA,IAAG,gBAAgB,UAAU,eAAe,EAAG;AAC1F,UAAM,WAAW,UAAU,cAAc;AACzC,QAAI,CAAC,YAAY,CAACA,IAAG,eAAe,QAAQ,EAAG;AAC/C,UAAM,SAAS,aAAa,OAAO,UAAU,UAAU,gBAAgB,IAAI;AAC3E,QAAI,CAAC,OAAQ;AACb,eAAW,WAAW,SAAS,UAAU;AACvC,YAAM,QAAQ,QAAQ,KAAK;AAC3B,UAAI,YAAY,KAAK,QAAQ,cAAc,QAAQ,KAAK,EAAG,UAAS,IAAI,OAAO,EAAE,MAAM,QAAQ,MAAM,QAAQ,cAAc,QAAQ,MAAM,CAAC;AAAA,IAC5I;AAAA,EACF;AACA,SAAO,CAAC,SAAS;AACf,UAAM,OAAO,SAAS,IAAI,IAAI;AAC9B,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI;AACF,aAAO,YAAY,KAAK,IAAI,EAAE,IAAI,KAAK,IAAI;AAAA,IAC7C,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;AF1NO,IAAM,iBAAiB;AASvB,SAAS,SAAS,MAAsB;AAC7C,SAAO,KACJ,YAAY,EACZ,QAAQ,kDAAkD,GAAG,EAC7D,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,EAAE,EACjB,QAAQ,OAAO,EAAE;AACtB;AAYA,SAAS,oBAAoB,KAAqB;AAChD,SAAO,IACJ,QAAQ,sBAAsB,OAAO,EACrC,QAAQ,yBAAyB,OAAO,EACxC,QAAQ,sBAAsB,OAAO,EACrC,QAAQ,sBAAsB,OAAO,EACrC,QAAQ,UAAU,GAAG,EACrB,KAAK;AACV;AAEO,IAAM,OAAO,CAAC,OAAe,SAAiB,GAAG,SAAS,KAAK,CAAC,KAAK,SAAS,oBAAoB,IAAI,CAAC,CAAC;AAGxG,SAAS,iBAAiB,QAA6B;AAC5D,QAAM,OAAOC,IAAG,iBAAiB,YAAY,QAAQA,IAAG,aAAa,QAAQ,IAAI;AACjF,QAAM,QAAqB,CAAC;AAC5B,aAAW,aAAa,KAAK,YAAY;AACvC,QAAI,CAACA,IAAG,oBAAoB,SAAS,EAAG;AACxC,UAAM,OAAO,UAAU;AACvB,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,QAAQ,CAACA,IAAG,gBAAgB,IAAI,KAAK,CAAC,UAAU,CAACA,IAAG,eAAe,MAAM,EAAG;AACjF,eAAW,WAAW,OAAO,UAAU;AACrC,YAAM,KAAK,EAAE,MAAM,QAAQ,KAAK,MAAM,QAAQ,KAAK,KAAK,QAAQ,SAAS,EAAE,GAAG,QAAQ,UAAU,cAAc,QAAQ,WAAW,CAAC;AAAA,IACpI;AAAA,EACF;AACA,SAAO;AACT;AAaA,SAAS,SAAS,QAAgB,MAAe,YAA2B,MAAc;AACxF,QAAM,SAASA,IAAG,wBAAwB,QAAQ,KAAK,aAAa,CAAC,KAAK,CAAC;AAC3E,QAAM,QAAQ,OAAO,OAAO,CAAC,UAAU,OAAO,MAAM,MAAM,KAAK,MAAM,MAAM,CAAC,MAAM,KAAK,EAAE,IAAI;AAC7F,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,cAAc,QAAQ,MAAM,QAAQ,UAAW,QAAO;AAK1D,QAAM,UAAU,OAAO,MAAM,MAAM,KAAK,KAAK,SAAS,CAAC;AACvD,MAAI,QAAQ,QAAQ,eAAe,EAAE,EAAE,KAAK,MAAM,GAAI,QAAO;AAC7D,SAAO,OACJ,MAAM,MAAM,KAAK,MAAM,GAAG,EAC1B,MAAM,OAAO,EACb,IAAI,CAAC,SAAS,KAAK,KAAK,EAAE,QAAQ,WAAW,EAAE,EAAE,QAAQ,SAAS,EAAE,EAAE,QAAQ,OAAO,EAAE,EAAE,KAAK,CAAC,EAC/F,KAAK,IAAI,EACT,KAAK;AACV;AAUO,SAAS,cAAc,OAAuB;AACnD,QAAM,OAAO,MACV,MAAM,SAAS,EAAE,CAAC,EAClB,MAAM,IAAI,EACV,OAAO,CAACC,UAAS,CAACA,MAAK,KAAK,EAAE,WAAW,GAAG,CAAC,EAC7C,KAAK,GAAG,EACR,QAAQ,SAAS,EAAE,EACnB,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACR,QAAM,QAAQ,KAAK,MAAM,6BAA6B;AACtD,MAAI,OAAO,MAAM,CAAC,KAAK;AACvB,MAAI,KAAK,SAAS,MAAM,MAAM,CAAC,EAAG,QAAO,GAAG,IAAI,IAAI,MAAM,CAAC,CAAC;AAC5D,SAAO,KAAK,KAAK;AACnB;AAGO,SAAS,YAAY,KAAqB;AAC/C,QAAM,QAAQ,IAAI,MAAM,OAAO;AAC/B,QAAM,UAAU,MAAM,UAAU,CAAC,SAAS,UAAU,KAAK,IAAI,CAAC;AAC9D,MAAI,UAAU,EAAG,QAAO;AACxB,QAAM,YAAsB,CAAC;AAC7B,aAAW,QAAQ,MAAM,MAAM,UAAU,CAAC,GAAG;AAC3C,UAAM,OAAO,KAAK,KAAK;AACvB,QAAI,SAAS,IAAI;AACf,UAAI,UAAU,OAAQ;AACtB;AAAA,IACF;AAGA,QAAI,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,EAAG;AAClD,cAAU,KAAK,IAAI;AAAA,EACrB;AACA,SAAO,UAAU,KAAK,GAAG;AAC3B;AAWA,SAAS,SAAS,QAAuC;AACvD,MAAI,CAAC,OAAO,KAAM,QAAO;AACzB,MAAID,IAAG,aAAa,OAAO,IAAI,KAAKA,IAAG,gBAAgB,OAAO,IAAI,EAAG,QAAO,OAAO,KAAK;AACxF,SAAO;AACT;AAGA,SAAS,aAAa,MAA+B,SAAmC,OAAO,oBAAI,IAAY,GAAoB;AACjI,MAAI,CAAC,KAAM,QAAO;AAClB,MAAIA,IAAG,oBAAoB,IAAI,KAAKA,IAAG,aAAa,KAAK,QAAQ,GAAG;AAClE,UAAM,OAAO,KAAK,SAAS;AAC3B,QAAI,KAAK,IAAI,IAAI,EAAG,QAAO;AAC3B,SAAK,IAAI,IAAI;AACb,UAAM,QAAQ,QAAQ,IAAI,IAAI;AAC9B,WAAO,QAAQ,aAAa,OAAO,SAAS,IAAI,IAAI;AAAA,EACtD;AACA,MAAIA,IAAG,kBAAkB,IAAI,KAAKA,IAAG,gBAAgB,KAAK,OAAO,EAAG,QAAO,CAAC,KAAK,QAAQ,IAAI;AAC7F,MAAI,CAACA,IAAG,gBAAgB,IAAI,EAAG,QAAO;AACtC,QAAM,SAAmB,CAAC;AAC1B,aAAW,UAAU,KAAK,OAAO;AAE/B,QAAI,OAAO,SAASA,IAAG,WAAW,oBAAoB,OAAO,SAASA,IAAG,WAAW,YAAa;AACjG,UAAM,QAAQ,aAAa,QAAQ,SAAS,IAAI;AAChD,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO,KAAK,GAAG,KAAK;AAAA,EACtB;AACA,SAAO,OAAO,SAAS,IAAI,SAAS;AACtC;AA0BO,SAAS,WAAW,QAAgB,UAAmB,MAAM,QAAW,EAAE,mBAAmB,KAAK,IAAiB,CAAC,GAAG;AAC5H,QAAM,OAAOA,IAAG,iBAAiB,cAAc,QAAQA,IAAG,aAAa,QAAQ,IAAI;AACnF,QAAM,eAAe,oBAAI,IAAsB;AAC/C,QAAM,UAAU,oBAAI,IAAyB;AAC7C,QAAM,SAAS,oBAAI,IAA8B;AAEjD,QAAM,QAAQ,oBAAI,IAA8C;AAEhE,QAAM,eAAe,oBAAI,IAAqD;AAE9E,QAAM,cAAc,CAAC,eAA4E,WAAW,CAAC,GAAG;AAShH,QAAM,qBAAqB,CAAC,gBAAoE;AAC9F,QAAI,CAAC,YAAa,QAAO;AACzB,QAAIA,IAAG,gBAAgB,WAAW,KAAKA,IAAG,qBAAqB,WAAW,EAAG,QAAO,YAAY,YAAY,UAAU;AACtH,QAAIA,IAAG,iBAAiB,WAAW,GAAG;AACpC,YAAM,SAASA,IAAG,2BAA2B,YAAY,UAAU,IAAI,YAAY,WAAW,KAAK,OAAOA,IAAG,aAAa,YAAY,UAAU,IAAI,YAAY,WAAW,OAAO;AAClL,UAAI,WAAW,gBAAgB,YAAY,gBAAgB,CAAC,EAAG,QAAO,YAAY,cAAc,CAAC;AAGjG,YAAM,UAAU,YAAY,UAAU,KAAK,CAAC,aAAaA,IAAG,gBAAgB,QAAQ,KAAKA,IAAG,qBAAqB,QAAQ,CAAC;AAC1H,UAAI,QAAS,QAAO,YAAa,QAAqD,UAAU;AAAA,IAClG;AACA,WAAO;AAAA,EACT;AAOA,QAAM,oBAAoB,CAAC,SAA2D;AACpF,QAAI,CAAC,QAAQ,CAACA,IAAG,oBAAoB,IAAI,EAAG,QAAO;AACnD,UAAM,QAAQA,IAAG,aAAa,KAAK,QAAQ,IAAI,KAAK,SAAS,OAAO,KAAK,SAAS,MAAM;AACxF,WAAO,UAAU,QAAQ,UAAU,sBAAsB,KAAK,gBAAgB,CAAC,IAAI;AAAA,EACrF;AAIA,QAAM,UAAU,KAAK,WAAW,KAAK,CAAC,cAAc,CAACA,IAAG,oBAAoB,SAAS,CAAC;AACtF,QAAM,YAAY,WAAYA,IAAG,wBAAwB,QAAQ,QAAQ,aAAa,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,UAAU,OAAO,MAAM,MAAM,KAAK,MAAM,MAAM,CAAC,MAAM,KAAK,GAAG,OAAO,OAAQ;AAIlL,QAAM,SAAS,KAAK,WAAW,CAAC,KAAMA,IAAG,wBAAwB,QAAQ,KAAK,WAAW,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,UAAU,OAAO,MAAM,MAAM,KAAK,MAAM,MAAM,CAAC,MAAM,KAAK,GAAG,OAAO,OAAQ;AAGrM,QAAM,eAAe,CAAC,CAAC,KAAK,WAAW,CAAC,KAAKA,IAAG,oBAAoB,KAAK,WAAW,CAAC,CAAC;AACtF,QAAM,UAAU,mBAAoB,UAAU,YAAa,eAAe,SAAS;AAEnF,aAAW,aAAa,KAAK,YAAY;AACvC,QAAIA,IAAG,oBAAoB,SAAS,KAAKA,IAAG,gBAAgB,UAAU,eAAe,GAAG;AACtF,YAAM,WAAW,UAAU,cAAc;AACzC,UAAI,YAAYA,IAAG,eAAe,QAAQ,GAAG;AAC3C,mBAAW,WAAW,SAAS,SAAU,cAAa,IAAI,QAAQ,KAAK,MAAM,EAAE,WAAW,UAAU,gBAAgB,MAAM,WAAW,QAAQ,gBAAgB,QAAQ,MAAM,KAAK,CAAC;AAAA,MACnL;AAAA,IACF;AAGA,QAAIA,IAAG,oBAAoB,SAAS,KAAK,UAAU,mBAAmBA,IAAG,gBAAgB,UAAU,eAAe,KAAK,UAAU,gBAAgBA,IAAG,eAAe,UAAU,YAAY,GAAG;AAC1L,iBAAW,WAAW,UAAU,aAAa,SAAU,cAAa,IAAI,QAAQ,KAAK,MAAM,EAAE,WAAW,UAAU,gBAAgB,MAAM,WAAW,QAAQ,gBAAgB,QAAQ,MAAM,KAAK,CAAC;AAAA,IACjM;AACA,QAAIA,IAAG,uBAAuB,SAAS,EAAG,SAAQ,IAAI,UAAU,KAAK,MAAM,UAAU,IAAI;AACzF,QAAIA,IAAG,uBAAuB,SAAS,GAAG;AACxC,aAAO,IAAI,UAAU,KAAK,MAAM,CAAC,GAAG,UAAU,OAAO,CAAC;AAItD,YAAM,YAAY,UAAU,mBAAmB,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,OAAO,KAAK,CAAC;AACxF,UAAI,SAAS,OAAQ,OAAM,IAAI,UAAU,KAAK,MAAM,QAAQ;AAAA,IAC9D;AACA,QAAIA,IAAG,uBAAuB,SAAS,KAAKA,IAAG,kBAAkB,UAAU,IAAI,EAAG,QAAO,IAAI,UAAU,KAAK,MAAM,CAAC,GAAG,UAAU,KAAK,OAAO,CAAC;AAM7I,QAAIA,IAAG,mBAAmB,SAAS,GAAG;AAIpC,YAAM,QAAQ,UAAU,mBAAmB,CAAC,GAAG,KAAK,CAAC,WAAW,OAAO,UAAUA,IAAG,WAAW,cAAc,GAAG,MAAM,CAAC;AACvH,YAAM,OAAO,UAAU,MAAM,SAASA,IAAG,aAAa,SAAS,GAAG,KAAK,CAAC,MAAM,EAAE,SAASA,IAAG,WAAW,cAAc,IAAI,YAAY;AACrI,UAAI,KAAM,cAAa,IAAI,MAAM,EAAE,KAAK,SAAS,QAAQ,WAAW,OAAO,GAAG,YAAY,OAAO,WAAW,MAAM,gBAAgB,CAAC,EAAE,CAAC;AACtI;AAAA,IACF;AAIA,QAAIA,IAAG,mBAAmB,SAAS,KAAK,CAAC,UAAU,kBAAkB,CAACA,IAAG,aAAa,UAAU,UAAU,GAAG;AAC3G,mBAAa,IAAI,WAAW,EAAE,KAAK,SAAS,QAAQ,WAAW,OAAO,GAAG,YAAY,OAAO,WAAW,mBAAmB,UAAU,UAAU,EAAE,CAAC;AACjJ;AAAA,IACF;AACA,QAAIA,IAAG,sBAAsB,SAAS,KAAK,CAAC,UAAU,QAAQA,IAAG,aAAa,SAAS,GAAG,KAAK,CAAC,MAAM,EAAE,SAASA,IAAG,WAAW,cAAc,GAAG;AAC9I,mBAAa,IAAI,WAAW,EAAE,KAAK,SAAS,QAAQ,WAAW,OAAO,GAAG,YAAY,OAAO,WAAW,YAAY,UAAU,UAAU,EAAE,CAAC;AAC1I;AAAA,IACF;AACA,QAAI,CAACA,IAAG,sBAAsB,SAAS,KAAK,CAACA,IAAG,oBAAoB,SAAS,EAAG;AAChF,UAAM,MAAM,SAAS,QAAQ,WAAW,OAAO;AAC/C,UAAM,aAAa,sBAAsB,KAAK,GAAG,KAAK,qBAAqB,KAAK,OAAO,MAAM,KAAK,IAAI,GAAG,UAAU,aAAa,CAAC,GAAG,UAAU,SAAS,CAAC,CAAC;AAEzJ,QAAIA,IAAG,sBAAsB,SAAS,KAAK,UAAU,MAAM;AAGzD,YAAM,OAAO,aAAa,IAAI,UAAU,KAAK,IAAI;AACjD,UAAI,MAAM;AACR,YAAI,CAAC,KAAK,OAAO,IAAK,MAAK,MAAM;AACjC;AAAA,MACF;AACA,mBAAa,IAAI,UAAU,KAAK,MAAM,EAAE,KAAK,YAAY,WAAW,YAAY,UAAU,UAAU,EAAE,CAAC;AACvG;AAAA,IACF;AACA,QAAIA,IAAG,oBAAoB,SAAS,GAAG;AACrC,iBAAW,eAAe,UAAU,gBAAgB,cAAc;AAChE,YAAI,CAACA,IAAG,aAAa,YAAY,IAAI,EAAG;AACxC,qBAAa,IAAI,YAAY,KAAK,MAAM,EAAE,KAAK,YAAY,WAAW,mBAAmB,YAAY,WAAW,KAAK,kBAAkB,YAAY,IAAI,EAAE,CAAC;AAAA,MAC5J;AAAA,IACF;AAAA,EACF;AAiBA,QAAM,QAAkB,EAAE,OAAO,CAAC,GAAG,UAAU,CAAC,EAAE;AAGlD,QAAM,SAAS,CAAC,SAAmD;AACjE,QAAI,CAAC,KAAM,QAAO;AAClB,QAAIA,IAAG,kBAAkB,IAAI,KAAKA,IAAG,gBAAgB,KAAK,OAAO,EAAG,QAAO,CAAC,KAAK,QAAQ,IAAI;AAC7F,QAAI,CAACA,IAAG,gBAAgB,IAAI,EAAG,QAAO;AACtC,UAAM,OAAiB,CAAC;AACxB,eAAW,UAAU,KAAK,OAAO;AAC/B,UAAI,CAACA,IAAG,kBAAkB,MAAM,KAAK,CAACA,IAAG,gBAAgB,OAAO,OAAO,EAAG,QAAO;AACjF,WAAK,KAAK,OAAO,QAAQ,IAAI;AAAA,IAC/B;AACA,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,CAAC,UAAoB,KAAsB,SAAoC;AAC5F,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,QAAQ,IAAI,IAAI,IAAI;AAC1B,UAAM,OAAO,CAAC,SAAkB,QAAQ,SAAS,CAAC,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI;AAClF,WAAO,EAAE,OAAO,SAAS,MAAM,OAAO,CAAC,SAAS,KAAK,KAAK,IAAI,CAAC,GAAG,UAAU,SAAS,SAAS,OAAO,CAAC,YAAY,KAAK,QAAQ,IAAI,CAAC,EAAE;AAAA,EACxI;AAGA,QAAM,QAAQ,CAAC,UAAgC;AAC7C,UAAM,QAAqB,CAAC;AAC5B,UAAM,WAA2B,CAAC;AAClC,UAAM,WAAW,oBAAI,IAAY;AACjC,UAAM,cAAc,oBAAI,IAAY;AACpC,eAAW,QAAQ,OAAO;AACxB,iBAAW,QAAQ,KAAK,MAAO,KAAI,CAAC,SAAS,IAAI,KAAK,IAAI,EAAG,CAAC,SAAS,IAAI,KAAK,IAAI,GAAG,MAAM,KAAK,IAAI;AACtG,iBAAW,WAAW,KAAK,SAAU,KAAI,CAAC,YAAY,IAAI,QAAQ,IAAI,EAAG,CAAC,YAAY,IAAI,QAAQ,IAAI,GAAG,SAAS,KAAK,OAAO;AAAA,IAChI;AACA,WAAO,EAAE,OAAO,SAAS;AAAA,EAC3B;AAOA,QAAM,QAAQ,CAAC,MAA+B,WAAoC;AAChF,QAAI,OAAQ,QAAO,OAAO,KAAK,KAAK;AACpC,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,UAAU,KAAK,QAAQ,IAAI,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC7D,QAAI,YAAY,UAAW,QAAO;AAClC,QAAI,YAAY,SAAU,QAAO;AACjC,QAAI,YAAY,SAAU,QAAO;AACjC,QAAI,yBAAyB,KAAK,OAAO,EAAG,QAAO;AACnD,QAAI,QAAQ,SAAS,IAAI,EAAG,QAAO;AACnC,WAAO,QAAQ,SAAS,KAAK,GAAG,QAAQ,MAAM,GAAG,EAAE,CAAC,WAAM;AAAA,EAC5D;AAGA,QAAM,cAAc,CAAC,YAAiD;AACpE,UAAM,QAAqB,CAAC;AAC5B,UAAM,WAA2B,CAAC;AAClC,eAAW,UAAU,SAAS;AAC5B,YAAM,OAAO,SAAS,MAAM;AAC5B,UAAI,SAAS,QAAQ,CAACA,IAAG,oBAAoB,MAAM,EAAG;AACtD,YAAM,SAAS,aAAa,OAAO,MAAM,OAAO;AAChD,YAAM,OAAO,cAAc,SAAS,QAAQ,MAAM,CAAC;AACnD,YAAM,KAAK,EAAE,MAAM,OAAO,MAAM,OAAO,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,eAAe,MAAM,QAAQ,KAAK,CAAC;AAC3G,UAAI,OAAQ,UAAS,KAAK,EAAE,MAAM,MAAM,OAAO,CAAC;AAAA,IAClD;AACA,WAAO,EAAE,OAAO,SAAS;AAAA,EAC3B;AAEA,QAAM,cAAc,CAAC,MAA+B,SAAgC;AAClF,QAAI,CAAC,QAAQ,KAAK,OAAO,GAAI,QAAO;AAEpC,QAAIA,IAAG,kBAAkB,IAAI,EAAG,QAAO,YAAY,KAAK,OAAO;AAC/D,QAAIA,IAAG,uBAAuB,IAAI,EAAG,QAAO,MAAM,KAAK,MAAM,IAAI,CAAC,SAAS,YAAY,MAAM,IAAI,CAAC,CAAC;AACnG,QAAIA,IAAG,oBAAoB,IAAI,KAAKA,IAAG,aAAa,KAAK,QAAQ,GAAG;AAClE,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,UAAU,UAAU,UAAU,QAAQ;AACxC,eAAO,OAAO,YAAY,KAAK,gBAAgB,CAAC,GAAG,IAAI,GAAG,OAAO,OAAO,KAAK,gBAAgB,CAAC,CAAC,CAAC;AAAA,MAClG;AACA,aAAO,YAAY,OAAO,IAAI;AAAA,IAChC;AACA,WAAO;AAAA,EACT;AAGA,QAAM,cAAc,CAAC,MAAsC,SAAgC;AACzF,QAAI,CAACA,IAAG,aAAa,KAAK,UAAU,EAAG,QAAO;AAC9C,UAAM,QAAQ,KAAK,WAAW;AAC9B,QAAI,UAAU,UAAU,UAAU,QAAQ;AACxC,aAAO,OAAO,YAAY,KAAK,gBAAgB,CAAC,GAAG,IAAI,GAAG,OAAO,OAAO,KAAK,gBAAgB,CAAC,CAAC,CAAC;AAAA,IAClG;AACA,WAAO,YAAY,OAAO,IAAI;AAAA,EAChC;AAaA,WAAS,YAAY,MAAc,MAA6B;AAC9D,QAAI,KAAK,IAAI,IAAI,KAAK,KAAK,OAAO,GAAI,QAAO;AAC7C,SAAK,IAAI,IAAI;AACb,UAAM,MAAM,OAAO,IAAI,IAAI;AAC3B,QAAI,KAAK;AACP,YAAM,aAAa,MAAM,IAAI,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,YAAY,MAAM,IAAI,CAAC;AAC/E,aAAO,MAAM,CAAC,YAAY,GAAG,GAAG,GAAG,SAAS,CAAC;AAAA,IAC/C;AAEA,UAAM,QAAQ,QAAQ,IAAI,IAAI;AAC9B,QAAI,MAAO,QAAO,YAAY,OAAO,IAAI;AAEzC,UAAM,OAAO,aAAa,IAAI,IAAI;AAClC,YAAQ,OAAO,QAAQ,KAAK,WAAW,KAAK,QAAQ,IAAI,WAAc;AAAA,EACxE;AAGA,QAAM,UAAU,CAAC,cAAiD,YAAY,WAAW,oBAAI,IAAI,CAAC;AAKlG,QAAM,UAAU,CAAC,SAA+B,QAAQA,IAAG,wBAAwB,QAAQ,KAAK,aAAa,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,UAAU,OAAO,MAAM,MAAM,KAAK,MAAM,MAAM,CAAC,MAAM,KAAK,IAAI;AAC3L,QAAM,cAAc,QAAQ,KAAK,WAAW,CAAC,CAAC,KAAK,QAAQ,OAAO;AAClE,SAAO,EAAE,cAAc,WAAW,cAAc,cAAc,QAAQ,WAAW,IAAI,IAAI,SAAS,aAAa,CAAC,SAAiB,YAAY,MAAM,oBAAI,IAAI,CAAC,EAAE;AAChK;AAGA,SAAS,cAAc,QAAgB,OAAgC;AACrE,SAAO,OACJ,MAAM,MAAM,KAAK,MAAM,GAAG,EAC1B,MAAM,OAAO,EACb,IAAI,CAAC,SAAS,KAAK,KAAK,EAAE,QAAQ,WAAW,EAAE,EAAE,QAAQ,SAAS,EAAE,EAAE,QAAQ,OAAO,EAAE,EAAE,KAAK,CAAC,EAC/F,KAAK,IAAI,EACT,KAAK;AACV;AAGO,SAAS,YAAY,QAA6D;AACvF,QAAM,OAAOA,IAAG,iBAAiB,iBAAiB,QAAQA,IAAG,aAAa,QAAQ,IAAI;AACtF,MAAI,QAAuB;AAC3B,QAAM,UAAoB,CAAC;AAC3B,aAAW,aAAa,KAAK,YAAY;AACvC,QAAIA,IAAG,oBAAoB,SAAS,GAAG;AACrC,iBAAW,eAAe,UAAU,gBAAgB,cAAc;AAChE,YAAI,CAACA,IAAG,aAAa,YAAY,IAAI,EAAG;AACxC,cAAM,cAAc,YAAY;AAChC,cAAM,SAAS,eAAeA,IAAG,sBAAsB,WAAW,IAAI,YAAY,aAAa;AAC/F,YAAI,YAAY,KAAK,SAAS,UAAU,UAAUA,IAAG,0BAA0B,MAAM,GAAG;AACtF,qBAAW,YAAY,OAAO,YAAY;AACxC,gBAAIA,IAAG,qBAAqB,QAAQ,KAAKA,IAAG,aAAa,SAAS,IAAI,KAAK,SAAS,KAAK,SAAS,WAAWA,IAAG,gBAAgB,SAAS,WAAW,GAAG;AACrJ,sBAAQ,SAAS,YAAY;AAAA,YAC/B;AAAA,UACF;AAAA,QACF;AACA,cAAM,WAAWA,IAAG,aAAa,SAAS,GAAG,KAAK,CAAC,MAAM,EAAE,SAASA,IAAG,WAAW,aAAa;AAC/F,YAAI,YAAY,YAAY,KAAK,SAAS,OAAQ,SAAQ,KAAK,YAAY,KAAK,IAAI;AAAA,MACtF;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,OAAO,QAAQ;AAC1B;AAEA,IAAM,YAAY,CAAC,SAAiB,eAAe,KAAK,IAAI;AAG5D,SAAS,OAAO,MAAyB;AACvC,MAAI,YAAY,KAAK,IAAI,EAAG,QAAO;AACnC,SAAO,SAAS,KAAK,IAAI,KAAK,CAAC,UAAU,IAAI,IAAI,cAAc;AACjE;AAGA,SAAS,aAAa,MAAgC;AACpD,SAAOE,kBAAiB,OAAO,CAAC,UAAU,MAAM,OAAO,SAAS,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,MAAM,IAAI,WAAW,MAAM,UAAU,EAAE;AACtI;AAUO,SAAS,cAAc,EAAE,OAAO,QAAQ,IAAI,GAAG,OAAO,YAAY,IAAkB,CAAC,GAAa;AACvG,QAAM,MAAMC,MAAK,MAAM,KAAK;AAC5B,QAAM,WAAW,KAAK,MAAMC,cAAaD,MAAK,MAAM,cAAc,GAAG,MAAM,CAAC;AAC5E,QAAM,QAAQ,IAAI,IAAI,YAAY,GAAG,CAAC;AACtC,QAAM,WAAW,iBAAiBC,cAAaD,MAAK,KAAK,UAAU,GAAG,MAAM,CAAC;AAC7E,QAAM,SAAS,SAAS,OAAO,CAAC,UAAU,CAAC,MAAM,MAAM;AAGvD,QAAM,UAAU,oBAAI,IAAoB;AACxC,QAAM,WAAW,CAAC,SAAyB;AACzC,UAAM,OAAO,QAAQ,IAAI,IAAI;AAC7B,QAAI,KAAM,QAAO;AACjB,UAAM,OAAO,CAAC,QAAQ,KAAK,EAAE,IAAI,CAAC,cAAc,GAAG,IAAI,GAAG,SAAS,EAAE,EAAE,KAAK,CAAC,cAAc,MAAM,IAAI,SAAS,CAAC;AAC/G,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,gCAAgC,IAAI,gCAAgC;AAI/F,UAAM,OAAO,EAAE,GAAG,WAAWC,cAAaD,MAAK,KAAK,IAAI,GAAG,MAAM,GAAG,CAAC,WAAW,aAAc,UAAU,WAAW,IAAI,IAAI,SAAS,UAAU,MAAM,CAAC,CAAC,EAAE,YAAY,QAAQ,IAAI,MAAU,GAAG,MAAM,OAAO,IAAI,GAAG;AACjN,YAAQ,IAAI,MAAM,IAAI;AACtB,WAAO;AAAA,EACT;AAEA,QAAM,WAAqB,CAAC;AAC5B,QAAM,UAA2B,CAAC;AAElC,QAAM,aAAa,oBAAI,IAA8C;AACrE,QAAM,WAAW,CAAC,MAAc,SAAiB;AAC/C,QAAI,CAAC,WAAW,IAAI,IAAI,EAAG,YAAW,IAAI,MAAM,cAAcA,MAAK,KAAK,KAAK,QAAQ,UAAU,EAAE,CAAC,GAAGC,cAAaD,MAAK,KAAK,KAAK,QAAQ,UAAU,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC;AACjK,WAAO,QAAQ,WAAW,IAAI,IAAI,GAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,KAAK,CAAC;AAAA,EAC9D;AAEA,aAAW,SAAS,QAAQ;AAC1B,UAAM,SAAS,SAAS,MAAM,MAAM;AACpC,UAAM,WAAW,OAAO,aAAa,IAAI,MAAM,IAAI;AACnD,QAAI,CAAC,UAAU;AACb,eAAS,KAAK,GAAG,MAAM,IAAI,wBAAwB,MAAM,MAAM,6BAA6B;AAC5F;AAAA,IACF;AAKA,UAAM,WAAW,MAAM,IAAI,GAAG,MAAM,IAAI,MAAM,IAAI,OAAO,MAAM,IAAI,SAAS;AAC5E,UAAM,WAAW,WAAW,cAAc,YAAYC,cAAaD,MAAK,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,IAAI;AACrG,UAAM,cAAc,cAAc,SAAS,GAAG;AAC9C,UAAM,UAAU,YAAY;AAC5B,QAAI,CAAC,SAAS;AACZ,eAAS,KAAK,GAAG,MAAM,IAAI,qFAAqF,OAAO,IAAI,EAAE;AAC7H;AAAA,IACF;AAIA,UAAM,cAAc,MAAM,IAAI,GAAG,MAAM,IAAI,cAAc,IAAI,GAAG,MAAM,IAAI,iBAAiB,MAAM,IAAI,GAAG,MAAM,MAAM,cAAc,IAAI,GAAG,MAAM,MAAM,iBAAiB;AACtK,UAAM,UAAU,cAAc,YAAYC,cAAaD,MAAK,KAAK,WAAW,GAAG,MAAM,CAAC,IAAI,EAAE,OAAO,MAAM,SAAS,CAAC,EAAE;AACrH,UAAM,QAAQ,QAAQ;AACtB,UAAM,QAAQ,QAAQ,QAAQ,SAAS,MAAM,IAAI,IAAI,MAAM,OAAO,QAAQ,QAAQ,CAAC;AAEnF,UAAM,QAAQ,OAAO,QAAQ,SAAS,SAAS;AAE/C,YAAQ,KAAK;AAAA,MACX,MAAM,MAAM;AAAA,MACZ;AAAA,MACA,MAAM,OAAO,MAAM,IAAI;AAAA,MACvB,YAAY;AAAA,MACZ,YAAY,OAAO;AAAA,MACnB;AAAA,MACA,aAAa,WAAW,SAAS;AAAA,MACjC,OAAO,MAAM;AAAA,MACb,UAAU,MAAM;AAAA,MAChB,gBAAgB,aAAa,MAAM,IAAI;AAAA,MACvC,QAAQ,SAAS,aAAa,eAAe;AAAA,MAC7C,gBAAgB;AAAA,MAChB,QAAQ,QAAQ,GAAG,SAAS,KAAK,CAAC,WAAW;AAAA,MAC7C,SAAS,SAAS,QAAQ,KAAK,OAAO,KAAK,IAAI;AAAA,MAC/C,SAAS;AAAA,MACT,KAAK;AAAA,MACL,OAAO,OAAO,MAAM,IAAI,MAAM,cAAc,SAAS,OAAO,MAAM,MAAM,IAAI,IAAI,CAAC;AAAA,IACnF,CAAC;AAAA,EACH;AAEA,MAAI,SAAS,OAAQ,OAAM,IAAI,MAAM;AAAA,IAAoC,SAAS,KAAK,MAAM,CAAC,EAAE;AAIhG,QAAM,eAAe,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAClE,QAAM,UAAU,oBAAI,IAAyH;AAC7I,QAAM,YAAY,CAAC,eAAuB;AACxC,QAAI,CAAC,QAAQ,IAAI,UAAU,GAAG;AAC5B,YAAM,OAAO,SAAS,UAAU,EAAE;AAClC,YAAM,KAAKH,IAAG,iBAAiB,MAAMI,cAAaD,MAAK,MAAM,IAAI,GAAG,MAAM,GAAGH,IAAG,aAAa,QAAQ,MAAM,KAAK,SAAS,GAAG,IAAIA,IAAG,WAAW,MAAMA,IAAG,WAAW,EAAE;AACpK,cAAQ,IAAI,YAAY,EAAE,OAAO,QAAQ,EAAE,GAAG,OAAO,QAAQ,EAAE,GAAG,SAAS,UAAU,EAAE,EAAE,CAAC;AAAA,IAC5F;AACA,WAAO,QAAQ,IAAI,UAAU;AAAA,EAC/B;AACA,QAAM,OAAO,CAAC,MAAc,SAAmC;AAC7D,UAAM,MAAM,IAAI,IAAI,aAAa,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AACvD,UAAM,aAAa,aAAa,IAAI,IAAI;AACxC,QAAI,CAAC,cAAc,KAAK,IAAI,IAAI,EAAG,QAAO;AAC1C,SAAK,IAAI,IAAI;AACb,UAAM,EAAE,OAAO,OAAO,QAAQ,IAAI,UAAU,UAAU;AAEtD,eAAW,OAAO,MAAM,IAAI,IAAI,KAAK,CAAC,GAAG;AACvC,YAAM,CAAC,OAAO,KAAK,IAAI,SAAS,GAAG;AACnC,YAAM,OAAO,QAAQ,IAAI,KAAK;AAC9B,UAAI,QAAQ,SAAS,KAAK,SAAS,EAAG,YAAW,MAAM,iBAAiB,KAAK,UAAU,KAAK,EAAG,KAAI,IAAI,EAAE;AAAA,IAC3G;AAEA,eAAW,OAAO,MAAM,IAAI,IAAI,KAAK,CAAC,GAAG;AACvC,YAAM,CAAC,KAAK,IAAI,SAAS,GAAG;AAC5B,YAAM,OAAO,QAAQ,IAAI,KAAK;AAC9B,YAAM,OAAO,MAAM,UAAU,WAAW,IAAI,IAAI,KAAK,WAAW,CAAC,QAAQ,UAAU,OAAO,QAAQ;AAClG,UAAI,QAAQ,aAAa,IAAI,IAAI,EAAG,YAAW,MAAM,SAAS,MAAM,KAAK,MAAM,IAAI,CAAC,EAAG,KAAI,IAAI,EAAE;AAAA,IACnG;AACA,WAAO;AAAA,EACT;AACA,aAAW,SAAS,QAAS,KAAI,MAAM,SAAS,YAAa,OAAM,iBAAiB,aAAa,KAAK,MAAM,MAAM,oBAAI,IAAI,CAAC,CAAC;AAE5H,UAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAEnD,SAAO;AAAA,IACL,eAAe;AAAA,IACf,WAAW;AAAA,MACT,MAAM;AAAA,MACN;AAAA,MACA,SAAS,SAAS;AAAA,MAClB,gBAAgB,SAAS;AAAA,MACzB,SAAS,OAAO;AAAA,MAChB,aAAa,SAAS,SAAS,OAAO;AAAA,MACtC,OAAO;AAAA,IACT;AAAA,IACA,WAAW;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,MACX,QAAQ;AAAA,IACV;AAAA,IACA;AAAA;AAAA;AAAA;AAAA,IAIA,UAAU,CAAC;AAAA,IACX,mBAAmB,CAAC;AAAA,EACtB;AACF;AAGO,SAAS,kBAAkB,UAA4B;AAC5D,SAAO,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA;AAC7C;",
|
|
6
|
+
"names": ["readFileSync", "join", "ts", "OWNED_BEHAVIOURS", "ts", "ts", "ts", "line", "OWNED_BEHAVIOURS", "join", "readFileSync"]
|
|
7
|
+
}
|
|
@@ -32,7 +32,7 @@ function linkProblems(registry, ids) {
|
|
|
32
32
|
}
|
|
33
33
|
return problems;
|
|
34
34
|
}
|
|
35
|
-
function contractProblems(registry, root) {
|
|
35
|
+
function contractProblems(registry, root, known = new Set(registry.entries.map((e) => e.name))) {
|
|
36
36
|
const problems = [];
|
|
37
37
|
for (const entry of registry.entries) {
|
|
38
38
|
const cls = entry.app?.class;
|
|
@@ -46,15 +46,27 @@ function contractProblems(registry, root) {
|
|
|
46
46
|
const text = readFileSync(join(root, page), "utf8");
|
|
47
47
|
const problem = pageProblem(text);
|
|
48
48
|
if (problem) problems.push(`${where}: ${page} has ${problem}`);
|
|
49
|
+
const whenNot = whenNotProblem(text, [entry.name], known);
|
|
50
|
+
if (whenNot) problems.push(`${where}: ${page}: ${whenNot}`);
|
|
49
51
|
if (entry.storyId === null && !hasSeenIn(text)) {
|
|
50
52
|
problems.push(`${where} is drawn nowhere: give it a story, or write a "**Seen in**" line on ${page} naming the stories that draw it, or why none can`);
|
|
51
53
|
}
|
|
54
|
+
if (entry.storyId === null && entry.docsId === null) {
|
|
55
|
+
problems.push(`${where} links to nothing in Storybook: give ${page} a \`<Meta title="\u2026" />\`, or give the part a story`);
|
|
56
|
+
}
|
|
52
57
|
}
|
|
53
58
|
return problems;
|
|
54
59
|
}
|
|
55
60
|
var toStoryId = (title) => title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
56
61
|
function namedParts(section) {
|
|
57
|
-
return [...section.matchAll(
|
|
62
|
+
return [...section.matchAll(/\*\*`?([A-Z][A-Za-z0-9]+)`?\*\*|`([A-Z][A-Za-z0-9]+)`/g)].map((m) => m[1] ?? m[2]);
|
|
63
|
+
}
|
|
64
|
+
var NO_ALTERNATIVE = /^No alternative:/m;
|
|
65
|
+
function whenNotProblem(source, own, known) {
|
|
66
|
+
const section = source.replace(/\r\n/g, "\n").split(/^##\s+When not\s*$/m)[1]?.split(/^##\s/m)[0];
|
|
67
|
+
if (section === void 0 || NO_ALTERNATIVE.test(section)) return null;
|
|
68
|
+
if (namedParts(section).some((name) => known.has(name) && !own.includes(name))) return null;
|
|
69
|
+
return '"When not" names no other part: name the part to use instead, as **Name** or `Name`, or start a line "No alternative:" that says why there is none';
|
|
58
70
|
}
|
|
59
71
|
function nameProblems(registry, root, { known, titles, packageIds = [] }) {
|
|
60
72
|
const problems = [];
|
|
@@ -268,10 +280,13 @@ export {
|
|
|
268
280
|
hasSeenIn,
|
|
269
281
|
linkProblems,
|
|
270
282
|
contractProblems,
|
|
283
|
+
namedParts,
|
|
284
|
+
NO_ALTERNATIVE,
|
|
285
|
+
whenNotProblem,
|
|
271
286
|
nameProblems,
|
|
272
287
|
findInRegistry,
|
|
273
288
|
findInRegistries,
|
|
274
289
|
docsLink,
|
|
275
290
|
formatFindings
|
|
276
291
|
};
|
|
277
|
-
//# sourceMappingURL=chunk-
|
|
292
|
+
//# sourceMappingURL=chunk-XK747STJ.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/registry/contract.ts", "../../src/registry/find.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * The usage-page contract, checked against an app's catalogue (UIG-19).\n *\n * Every part an app classifies **reusable** (or **promote-candidate**) has a\n * page beside it \u2014 `<PartName>.mdx` in the component's own folder \u2014 that opens\n * with a line saying what the part is, then `When`, `When not`, `How` (with\n * code) and `What it owns`, in that order. And it is drawn somewhere: a story\n * of its own, or a **Seen in** line on its page naming the stories that draw\n * it, or saying why none can (Katerina, 21 and 23 September 2026). A one-off\n * needs only its class and a purpose line, which the catalogue already refuses\n * to build without.\n *\n * This is the one copy. Peek and Ship each used to carry their own, pasted into\n * their `scripts/gates-checks.mjs` and run only by `gates:status`, so a page\n * could lose its `When not` and still merge. `estiva-ui check` runs this in\n * every app's `gate` job (docs/GATES.md \u00A723: one copy, in the package).\n *\n * The package's own pages keep the fuller contract in `src/pages.test.ts`,\n * which also reads `What it owns` back against the lint rule.\n */\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { Registry } from './schema'\n\n/** The four headings, in the order a page carries them. */\nexport const PAGE_SECTIONS = ['When', 'When not', 'How', 'What it owns'] as const\n\n/** The classes that owe a page and a picture. */\nexport const CONTRACT_KINDS = ['reusable', 'promote-candidate'] as const\n\n/** The line that stands in for a story of the part's own. */\nconst SEEN_IN = /^\\*\\*Seen in\\*\\*/m\n\n/**\n * Why a page breaks the contract, or null when it keeps it.\n *\n * Read on normalised text: the apps are checked out with CRLF on Windows.\n */\nexport function pageProblem(source: string): string | null {\n const text = source.replace(/\\r\\n/g, '\\n')\n const heads = [...text.matchAll(/^##+\\s+(.+?)\\s*$/gm)].map((m) => m[1])\n const at = PAGE_SECTIONS.map((s) => heads.indexOf(s))\n const missing = PAGE_SECTIONS.filter((_, i) => at[i] < 0)\n if (missing.length) return `no ${missing.map((s) => `\"${s}\"`).join(', ')} section`\n if (at.some((i, n) => n > 0 && i < at[n - 1])) return `sections out of order: they go ${PAGE_SECTIONS.join(', ')}`\n // The opening line: the first paragraph under the title that is not markup.\n const opening = text\n .split(/^# .*$/m)[1]\n ?.split(/^##\\s/m)[0]\n ?.split(/\\n\\s*\\n/)\n .map((s) => s.trim())\n .find((s) => s && !s.startsWith('<') && !s.startsWith('import '))\n if (!opening) return 'no opening line under the title saying what the part is'\n // Only the How section: the code block must sit under How, not in a later section\n // (a page with none under How and one under What it owns passed, R18).\n const how = text.split(/^##\\s+How\\s*$/m)[1]?.split(/^##\\s/m)[0] ?? ''\n if (!/```tsx?\\n/.test(how)) return 'no code under \"How\"'\n return null\n}\n\n/** Whether a page records where the part is drawn, in place of a story of its own. */\nexport function hasSeenIn(source: string): boolean {\n return SEEN_IN.test(source.replace(/\\r\\n/g, '\\n'))\n}\n\n/**\n * Every catalogue link that names a story or a docs page its Storybook does not\n * have (UIG-19: a dead link is a build failure, not a dead end found six weeks\n * later). `ids` is every entry id in the Storybook's own index \u2014 what\n * `storybook index` writes \u2014 so this is Storybook's answer, not a guess at how\n * it builds an id.\n */\nexport function linkProblems(registry: Registry, ids: ReadonlySet<string>): string[] {\n const problems: string[] = []\n for (const entry of registry.entries) {\n for (const key of ['storyId', 'docsId'] as const) {\n const id = entry[key]\n if (id && !ids.has(id)) problems.push(`${entry.name} (${entry.sourceFile}) links to ${key === 'storyId' ? 'a story' : 'a docs page'} its Storybook does not have: ${id}`)\n }\n }\n return problems\n}\n\n/**\n * Every way an app's catalogue breaks the contract, one line each, naming the\n * part, its file and what to do. Empty when it keeps it.\n *\n * `root` is the app's own folder: the one its catalogue's paths are relative to.\n */\nexport function contractProblems(registry: Registry, root: string, known: ReadonlySet<string> = new Set(registry.entries.map((e) => e.name))): string[] {\n const problems: string[] = []\n for (const entry of registry.entries) {\n const cls = entry.app?.class\n if (!cls || !(CONTRACT_KINDS as readonly string[]).includes(cls)) continue\n // Where the page must be: beside the component, named after the part \u2014\n // the same place the catalogue looks (src/registry/app.ts).\n const page = join(entry.sourceFile.replace(/[^/\\\\]+$/, ''), `${entry.name}.mdx`).replace(/\\\\/g, '/')\n const where = `${entry.name} (${cls}, ${entry.sourceFile})`\n if (!existsSync(join(root, page))) {\n problems.push(`${where} has no usage page: write ${page}, with an opening line, then ${PAGE_SECTIONS.join(', ')}`)\n continue\n }\n const text = readFileSync(join(root, page), 'utf8')\n const problem = pageProblem(text)\n if (problem) problems.push(`${where}: ${page} has ${problem}`)\n const whenNot = whenNotProblem(text, [entry.name], known)\n if (whenNot) problems.push(`${where}: ${page}: ${whenNot}`)\n if (entry.storyId === null && !hasSeenIn(text)) {\n problems.push(`${where} is drawn nowhere: give it a story, or write a \"**Seen in**\" line on ${page} naming the stories that draw it, or why none can`)\n }\n // A reusable part links to its page or a story (Katerina's ruling B10, 25 September):\n // the catalogue reads the page's `<Meta title>`, so a page without one leaves it unlinked.\n if (entry.storyId === null && entry.docsId === null) {\n problems.push(`${where} links to nothing in Storybook: give ${page} a \\`<Meta title=\"\u2026\" />\\`, or give the part a story`)\n }\n }\n return problems\n}\n\n/** Storybook's id for a title: lower case, every run of other characters one hyphen. */\nconst toStoryId = (title: string) =>\n title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n\n/** The names a page's section writes as a part: bold or in backticks, starting with a capital. */\nexport function namedParts(section: string): string[] {\n return [...section.matchAll(/\\*\\*`?([A-Z][A-Za-z0-9]+)`?\\*\\*|`([A-Z][A-Za-z0-9]+)`/g)].map((m) => m[1] ?? m[2])\n}\n\n/** The line a \"When not\" starts where no part stands in (Katerina's ruling B8). */\nexport const NO_ALTERNATIVE = /^No alternative:/m\n\n/**\n * Why a page's `When not` breaks the ruling B8 (25 September), or null. The plan\n * asked for \"When not \u2014 naming the alternative\"; CI checked only that the\n * heading was there, and 29 pages across the three repos named nothing. Now the\n * section names a real part other than the page's own (`own`), from `known`, or\n * a line of it starts \"No alternative:\" and says why there is none.\n */\nexport function whenNotProblem(source: string, own: readonly string[], known: ReadonlySet<string>): string | null {\n const section = source.replace(/\\r\\n/g, '\\n').split(/^##\\s+When not\\s*$/m)[1]?.split(/^##\\s/m)[0]\n // A missing section is pageProblem's to report.\n if (section === undefined || NO_ALTERNATIVE.test(section)) return null\n if (namedParts(section).some((name) => known.has(name) && !own.includes(name))) return null\n return '\"When not\" names no other part: name the part to use instead, as **Name** or `Name`, or start a line \"No alternative:\" that says why there is none'\n}\n\n/**\n * What an app's usage pages name that is not there (the re-review after the audit\n * before UIG-26, R14): a part named under When or When not that no catalogue has \u2014\n * Peek's StartTopicDialog sent readers to CreateTopicDialog, deleted by FOL-23 \u2014\n * and a story a **Seen in** line names that no Storybook has. `known` is every part\n * of the package and the app; `titles` is the app's Storybook titles, when there\n * is an index to read them from; `packageIds` the package's story and docs ids, so\n * a page may send readers to the package's Storybook too.\n */\nexport function nameProblems(registry: Registry, root: string, { known, titles, packageIds = [] }: { known: Set<string>; titles?: Set<string>; packageIds?: string[] }): string[] {\n const problems: string[] = []\n for (const entry of registry.entries) {\n if (!entry.docPage || !existsSync(join(root, entry.docPage))) continue\n const text = readFileSync(join(root, entry.docPage), 'utf8').replace(/\\r\\n/g, '\\n')\n for (const heading of ['When', 'When not']) {\n const section = text.split(new RegExp(`^##\\\\s+${heading}\\\\s*$`, 'm'))[1]?.split(/^##\\s/m)[0] ?? ''\n for (const name of new Set(namedParts(section).filter((n) => !known.has(n)))) {\n problems.push(`${entry.docPage}: \"${heading}\" names ${name}, which is no part of the package or this app`)\n }\n }\n if (!titles) continue\n const seenIn = text.match(/^\\*\\*Seen in\\*\\*[^\\n]*(?:\\n(?!\\n)[^\\n]*)*/m)?.[0] ?? ''\n for (const [, raw] of seenIn.matchAll(/\\*([A-Z][^*/]*\\/[^*]+)\\*/g)) {\n // A title may wrap across lines, and a line may break after its slash.\n const title = raw.replace(/\\s+/g, ' ').replace(/\\s*\\/\\s*/g, '/').trim()\n const id = toStoryId(title)\n if (titles.has(title) || packageIds.some((p) => p.startsWith(`${id}--`))) continue\n problems.push(`${entry.docPage}: \"Seen in\" names ${title}, which no Storybook has`)\n }\n }\n return problems\n}\n", "/**\n * The catalogue's reader (UIG-12): `ui:find <words>`.\n *\n * It exists to prove the format. A schema nobody consumes is a schema nobody\n * has tested, and the questions it has to answer are regression tests, not the\n * scope: \"floating panel\" must find `Popover`, \"scrolling\" `ScrollArea`,\n * \"empty\" `EmptyState`.\n *\n * It is also the answer to \"what do we have for this?\", which is the question\n * the wall cannot answer: a lint rule refuses the wrong thing, and this is\n * where the right one is named (UIG-20 makes a session ask it first).\n */\nimport type { Registry, RegistryEntry } from './schema'\n\nexport interface Finding {\n entry: RegistryEntry\n /** How many of the query's words matched anywhere. Ranked on this first. */\n matched: number\n score: number\n /** Which fields matched, for the reader to say why. */\n where: string[]\n /**\n * The props the query named **by name**, so the answer shows those rather\n * than all of them. A prop whose note merely carries one of the words counts\n * towards the score and is not shown: on \"floating panel\", six of `Popover`'s\n * notes say \"panel\", and printing all six buries the answer.\n */\n props: string[]\n}\n\n/**\n * Words that are in nearly every sentence, and so tell a search nothing.\n *\n * Measured: `ui:find \"truncate a long link\"` printed `Link`'s `external` prop,\n * because its note says \"in **a** new tab\" and the one-letter word matched\n * itself exactly. The minimum length in `alike` only guards a *prefix* match;\n * an exact match short-circuits it, which is right for `tab` and useless for `a`.\n */\nconst STOP = new Set([\n 'a', 'an', 'and', 'are', 'as', 'at', 'be', 'but', 'by', 'can', 'do', 'for', 'from', 'how', 'i', 'if', 'in', 'is', 'it', 'its', 'me', 'my', 'no', 'not', 'of',\n 'on', 'or', 'our', 'so', 'that', 'the', 'their', 'them', 'then', 'there', 'they', 'this', 'to', 'up', 'was', 'we', 'what', 'when', 'which', 'with', 'you', 'your',\n])\n\n/**\n * The words of a piece of text, with names taken apart.\n *\n * `CommandPalette` is kept whole *and* split, so \"palette\" reaches it and\n * \"commandpalette\" still does. Prose is already words; this costs it nothing.\n */\nfunction words(text: string): string[] {\n const found: string[] = []\n for (const token of text.match(/[A-Za-z0-9]+/g) ?? []) {\n found.push(token.toLowerCase())\n const parts = token.split(/(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/)\n if (parts.length > 1) found.push(...parts.map((part) => part.toLowerCase()))\n }\n return found\n}\n\n/**\n * Whether a word of the query means a word of the text.\n *\n * Either being a prefix of the other covers \"scroll\" against \"scrolling\"; the\n * five-letter key covers \"scrolls\" against \"scrolling\", where neither is. Crude\n * on purpose \u2014 a stemmer is a dependency and a surprise, and the failure here\n * is an extra row in a list of five, not a wrong answer.\n *\n * **Three letters at least**, or a prefix match is no match at all: `person's`\n * puts the word \"s\" in the text, and every query on earth starts with some\n * letter. Measured \u2014 before this, \"scrolling\" found `Avatar`.\n */\nfunction alike(query: string, text: string): boolean {\n if (query === text) return true\n if (Math.min(query.length, text.length) < 3) return false\n if (text.startsWith(query) || query.startsWith(text)) return true\n return query.slice(0, 5) === text.slice(0, 5)\n}\n\nconst hit = (query: string, text: string) => words(text).some((word) => alike(query, word))\n\n/**\n * Search name, purpose, behaviours and variants.\n *\n * A row that answers more of the question comes first, whatever it scored:\n * \"floating panel\" has to reach `Popover`, whose purpose carries both words,\n * over `MenuPanel`, whose name carries one of them loudly.\n */\nexport function findInRegistry(registry: Registry, query: string, { limit = 5 }: { limit?: number } = {}): Finding[] {\n return findInRegistries([registry], query, { limit })\n}\n\n/**\n * Search several catalogues as one: the package's, the app's own, and any app\n * beside it (UIG-13).\n *\n * An app's pass-on is not a result of its own \u2014 it is the package's part, and\n * the package's entry answers for it, saying which apps hand it on. At the\n * same strength the package's part comes first: it is the one to reach for.\n * And a package part whose name carries one of the words comes before an app's\n * part answering as many words, whatever each scored: \"panel header\" put an\n * app's own `Header`, whose whole name is one of the words, above the package's\n * `ContainerHeader` (UIG-20). Only by name: a package part the words reach\n * through its notes alone would bury the app part that is the answer.\n */\nexport function findInRegistries(registries: Registry[], query: string, { limit = 5 }: { limit?: number } = {}): Finding[] {\n const all = words(query)\n // Drop the words that mean nothing. If the question was only those, keep them\n // rather than answer nothing at all.\n const carrying = all.filter((word) => word.length >= 3 && !STOP.has(word))\n const asked = carrying.length ? carrying : all\n if (asked.length === 0) return []\n\n const findings: Finding[] = []\n const entries = registries.flatMap((registry) => registry.entries).filter((entry) => entry.app?.class !== 're-export')\n for (const entry of entries) {\n let score = 0\n let matched = 0\n const where = new Set<string>()\n const byName = new Set<string>()\n const byNote = new Set<string>()\n for (const word of asked) {\n let best = 0\n if (entry.name.toLowerCase() === word) {\n best = 100\n where.add('name')\n } else if (hit(word, entry.name)) {\n best = 40\n where.add('name')\n }\n if (hit(word, entry.purpose)) {\n best = Math.max(best, 20)\n where.add('purpose')\n }\n for (const owned of entry.ownsBehaviours) {\n if (hit(word, owned.behaviour) || hit(word, owned.id)) {\n best = Math.max(best, 15)\n where.add('behaviour')\n }\n }\n for (const variant of entry.variants) {\n if (variant.values.some((value) => hit(word, value)) || hit(word, variant.prop)) {\n best = Math.max(best, 8)\n where.add('variant')\n byName.add(variant.prop)\n }\n }\n // What it can do. \"does Link already truncate?\" is the question this\n // answers, and answering it is what stops the thing being built twice.\n for (const prop of entry.props) {\n // A prop the question named by name is the answer; one whose note\n // happens to carry the word is a hint. Named ones go first, so a short\n // answer shows the right lines.\n if (hit(word, prop.name)) {\n best = Math.max(best, 14)\n where.add('prop')\n byName.add(prop.name)\n } else if (prop.note !== null && hit(word, prop.note)) {\n best = Math.max(best, 10)\n where.add('prop')\n byNote.add(prop.name)\n }\n }\n if (best > 0) matched += 1\n score += best\n }\n if (matched > 0) findings.push({ entry, matched, score, where: [...where], props: [...byName] })\n }\n\n const fromPackage = (finding: Finding) => (finding.entry.app === null ? 0 : 1)\n const namedInPackage = (finding: Finding) => (finding.entry.app === null && finding.where.includes('name') ? 0 : 1)\n findings.sort(\n (a, b) =>\n b.matched - a.matched || namedInPackage(a) - namedInPackage(b) || b.score - a.score || fromPackage(a) - fromPackage(b) || a.entry.name.localeCompare(b.entry.name),\n )\n return findings.slice(0, limit)\n}\n\n/** `http://localhost:6008/?path=/docs/overlays-popover--docs`, or `null` where the entry has no page. */\nexport function docsLink(registry: Registry, entry: RegistryEntry): string | null {\n if (!entry.docsId) return null\n return registry.storybook.devUrl + registry.storybook.docsPath.replace('{docsId}', entry.docsId)\n}\n\n/** What an app's part is, in the words the search prints. */\nconst CLASS_WORDS: Record<string, string> = {\n 'one-off': 'used in one place',\n reusable: 'used in several places',\n 'promote-candidate': 'used in several places; could move into the package',\n unused: 'used nowhere in the app',\n}\n\n/** What the command prints: the import line first, because that is what the reader came for. */\nexport function formatFindings(searched: Registry | Registry[], findings: Finding[], query: string): string {\n const registries = Array.isArray(searched) ? searched : [searched]\n if (findings.length === 0) {\n return [\n `Nothing in ${registries.map((registry) => registry.builtFrom.repo).join(', ')} matches \"${query}\".`,\n 'If nothing here does what you need, say so and ask \u2014 do not invent a component.',\n ].join('\\n')\n }\n const registryOf = (entry: RegistryEntry) => registries.find((registry) => registry.builtFrom.repo === entry.repo) ?? registries[0]\n // Which apps hand a package part on, and from where: in Peek, `Button` is\n // imported from `@/components/ui/Button`, and the answer should say so.\n const handedOn = new Map<string, string[]>()\n for (const registry of registries) {\n for (const entry of registry.entries) {\n if (entry.app?.class !== 're-export' || entry.app.handsOn === null) continue\n handedOn.set(entry.app.handsOn, [...(handedOn.get(entry.app.handsOn) ?? []), `${entry.repo} hands it on${entry.name === entry.app.handsOn ? '' : ` as ${entry.name}`} from ${entry.importPath}`])\n }\n }\n\n const blocks = findings.map((finding) => {\n const { entry } = finding\n const facts = entry.app\n const lines = [\n `${entry.name} \u00B7 ${facts ? CLASS_WORDS[facts.class] ?? facts.class : entry.kind} \u00B7 ${entry.repo} (matched ${finding.where.join(', ')})`,\n ` ${entry.purpose}`,\n facts?.defaultExport ? ` import ${entry.name} from '${entry.importPath}'` : ` import { ${entry.name} } from '${entry.importPath}'`,\n ]\n if (!facts) for (const said of handedOn.get(entry.name) ?? []) lines.push(` ${said}`)\n if (facts?.packageNamesake) lines.push(` the package has a ${facts.packageNamesake} too: check it first`)\n if (facts && facts.usedIn.length) lines.push(` used in ${facts.usedIn.slice(0, 2).join(', ')}${facts.usedIn.length > 2 ? ` and ${facts.usedIn.length - 2} more` : ''}`)\n if (entry.ownsBehaviours.length) lines.push(` owns: ${entry.ownsBehaviours.map((owned) => owned.behaviour).join(' \u00B7 ')}`)\n if (entry.variants.length) lines.push(` ${entry.variants.map((variant) => `${variant.prop}: ${variant.values.join(' | ')}`).join(' ')}`)\n // The props the question named, with their own line \u2014 not all of them. A\n // component with twenty props would bury its own answer.\n const shown = finding.props\n .filter((name) => !entry.variants.some((variant) => variant.prop === name))\n .slice(0, 3)\n .map((name) => entry.props.find((prop) => prop.name === name))\n for (const prop of shown) {\n if (prop) lines.push(` ${prop.name}: ${prop.takes}${prop.note ? ` \u2014 ${prop.note}` : ''}`)\n }\n if (entry.props.length) lines.push(` ${entry.props.length} props in all; see ${entry.docsId ? 'the page' : entry.sourceFile} for the rest`)\n const link = docsLink(registryOf(entry), entry)\n if (link) lines.push(` ${link}`)\n return lines.join('\\n')\n })\n\n return blocks.join('\\n\\n')\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/registry/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
formatFindings,
|
|
7
7
|
linkProblems,
|
|
8
8
|
nameProblems
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-XK747STJ.js";
|
|
10
10
|
import {
|
|
11
11
|
CLASSES,
|
|
12
12
|
validateRegistry
|
|
@@ -258,8 +258,8 @@ function storyMapProblems(root2, { registry, real = sidebarHeadings(root2) } = {
|
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
// src/registry/cli.ts
|
|
261
|
-
var packageBuilder = () => import("./build-
|
|
262
|
-
var appBuilder = () => import("./app-
|
|
261
|
+
var packageBuilder = () => import("./build-3EANARLQ.js");
|
|
262
|
+
var appBuilder = () => import("./app-YMABQII6.js");
|
|
263
263
|
var gatedScan = () => import("./gated-5CPIUQAW.js");
|
|
264
264
|
var [command, ...rest] = process.argv.slice(2);
|
|
265
265
|
var VALUED = ["--limit", "--out", "--file", "--root", "--repo", "--also"];
|
|
@@ -455,7 +455,9 @@ ${more.slice(0, 3).join("\n")}${more.length > 3 ? `
|
|
|
455
455
|
const registry = await buildApp(root, value("repo"));
|
|
456
456
|
process.stdout.write(`${summary(registry)}
|
|
457
457
|
`);
|
|
458
|
-
const
|
|
458
|
+
const pkg = readPackageRegistry();
|
|
459
|
+
const known = new Set([...pkg.entries, ...registry.entries].map((e) => e.name));
|
|
460
|
+
const broken = contractProblems(registry, root, known);
|
|
459
461
|
if (broken.length) {
|
|
460
462
|
process.stderr.write(`${broken.length === 1 ? "a part breaks" : `${broken.length} parts break`} the usage-page contract:
|
|
461
463
|
${broken.join("\n ")}
|
|
@@ -469,9 +471,8 @@ ${more.slice(0, 3).join("\n")}${more.length > 3 ? `
|
|
|
469
471
|
const shown2 = await checkGated(registry, root);
|
|
470
472
|
const loaded2 = checkLoader();
|
|
471
473
|
const mapped2 = checkStoryMap(root, registry, linked2.headings);
|
|
472
|
-
const pkg = readPackageRegistry();
|
|
473
474
|
const stale = nameProblems(registry, root, {
|
|
474
|
-
known
|
|
475
|
+
known,
|
|
475
476
|
...linked2.titles ? { titles: linked2.titles } : {},
|
|
476
477
|
packageIds: pkg.entries.flatMap((e) => [e.storyId, e.docsId].filter((id) => Boolean(id)))
|
|
477
478
|
});
|