Files
supabase/apps/ui-library/lib/process-registry.ts
Saxon Fletcher 95ec79b98f feat: Infinite query hook block (#34650)
* infinite list

* infinite list block

* registration

* add missing supportedFrameworks

* Add tables to the supabase project. Generate the types for it.

* Refactor the infinite list query to be just a hook.

* Clean up the block. Add comments.

* Regenerate the registry.

* Fix the docs, the block is not framework-dependent.

* Set the package versions to * to be defined by other packages.

* Minor fixes to the block.

* Fix the examples.

* Fix the docs for the new hook.

* Fix the demo.

* Add more migrations to the db.

* Fix various issues with the query. Rewrote it to useSyncExternalStore.

* Fix the SSR for the hook.

* More fixes.

* Try initializing the store in a useEffect.

* Fix the pnpm-lock file.

* Minor fixes in the docs.

* Put the infinite list under a reusable components section.

* Update apps/ui-library/registry/default/blocks/infinite-query-hook/hooks/use-infinite-query.ts

* Change the example DB to use todos.

* Update the docs to be about Todos quickstart.

* List edits

* Fix link

* Regenerate the registry.

* Add query hook to the landing page.

---------

Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
Co-authored-by: Terry Sutton <saltcod@gmail.com>
2025-04-17 15:18:33 +02:00

87 lines
2.4 KiB
TypeScript

import * as fs from 'fs'
export interface RegistryNode {
name: string
path: string
originalPath: string
type: 'directory' | 'file'
children?: RegistryNode[]
content?: string
}
interface RegistryFile {
path: string
target?: string
type: string
content: string
}
const DEFAULT_PATHS = {
component: '/components',
hook: '/hooks',
util: '/lib',
} as const
/**
* Converts a flat registry array into a hierarchical file tree structure
*/
export function generateRegistryTree(registryPath: string): RegistryNode[] {
const registry = JSON.parse(fs.readFileSync(registryPath, 'utf-8')) as { files: RegistryFile[] }
const tree: RegistryNode[] = []
const sortedRegistry = [...registry.files].sort((a, b) => a.path.localeCompare(b.path))
for (const file of sortedRegistry) {
const itemPath = file.target || getDefaultPath(file)
const pathParts = itemPath.split('/').filter(Boolean)
let currentLevel = tree
for (let i = 0; i < pathParts.length; i++) {
const part = pathParts[i]
const isLast = i === pathParts.length - 1
const path = '/' + pathParts.slice(0, i + 1).join('/')
let node = currentLevel.find((n) => n.name === part)
// Remove any paths in the file content that point to the block directory.
const content = file.content
.replaceAll(/@\/registry\/default\/blocks\/.+?\//gi, '@/')
.replaceAll(/@\/registry\/default\/fixtures\//gi, '@/')
.replaceAll(/@\/registry\/default\//gi, '@/')
.replaceAll(/@\/clients\/.+?\//gi, '@/')
if (!node) {
node = {
name: part,
path,
originalPath: file.path,
type: isLast ? 'file' : 'directory',
...(isLast ? { content } : { children: [] }),
}
currentLevel.push(node)
}
if (!isLast) {
node.children = node.children || []
currentLevel = node.children
}
}
}
return tree
}
/**
* Determines the default path for an item based on its type
*/
function getDefaultPath(item: RegistryFile): string {
const type = item.type.toLowerCase() || ''
const basePath = DEFAULT_PATHS[type as keyof typeof DEFAULT_PATHS] || ''
// clean all paths that start with paths specific to this repo organization
const filePath = item.path
.replace(/registry\/default\/blocks\/.+?\//, '')
.replace(/registry\/default\/clients\/.+?\//, '')
return `${basePath}/${filePath}`
}