mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-26 06:44:58 +00:00
feat: refactor LuaSnippetUtils to use utility functions for category counts and tags
This commit is contained in:
@@ -1,159 +1,14 @@
|
||||
/**
|
||||
* DBAL Client Singleton
|
||||
*
|
||||
*
|
||||
* Provides centralized access to the Database Abstraction Layer.
|
||||
* All db/ lambda functions should use this instead of importing Prisma directly.
|
||||
*
|
||||
*
|
||||
* This uses the PrismaClient directly but wraps it in a DBAL-compatible interface,
|
||||
* providing a migration path to the full DBAL when ready.
|
||||
*/
|
||||
|
||||
import { prisma } from '../prisma'
|
||||
export type { DBALAdapter, ListOptions, ListResult } from './dbal-client/types'
|
||||
|
||||
export interface ListOptions {
|
||||
filter?: Record<string, unknown>
|
||||
sort?: Record<string, 'asc' | 'desc'>
|
||||
page?: number
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface ListResult<T> {
|
||||
data: T[]
|
||||
total?: number
|
||||
page?: number
|
||||
limit?: number
|
||||
hasMore?: boolean
|
||||
}
|
||||
|
||||
export interface DBALAdapter {
|
||||
create(entity: string, data: Record<string, unknown>): Promise<unknown>
|
||||
read(entity: string, id: string): Promise<unknown | null>
|
||||
update(entity: string, id: string, data: Record<string, unknown>): Promise<unknown>
|
||||
delete(entity: string, id: string): Promise<boolean>
|
||||
list(entity: string, options?: ListOptions): Promise<ListResult<unknown>>
|
||||
findFirst(entity: string, options?: { where?: Record<string, unknown> }): Promise<unknown | null>
|
||||
upsert(entity: string, options: { where: Record<string, unknown>; update: Record<string, unknown>; create: Record<string, unknown> }): Promise<unknown>
|
||||
close(): Promise<void>
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Prisma model by entity name
|
||||
*/
|
||||
const getModel = (entity: string): any => {
|
||||
const modelName = entity.charAt(0).toLowerCase() + entity.slice(1)
|
||||
const model = (prisma as any)[modelName]
|
||||
if (!model) {
|
||||
throw new Error(`Entity ${entity} not found in Prisma schema`)
|
||||
}
|
||||
return model
|
||||
}
|
||||
|
||||
/**
|
||||
* Build where clause from filter
|
||||
*/
|
||||
const buildWhereClause = (filter: Record<string, unknown>): Record<string, unknown> => {
|
||||
const where: Record<string, unknown> = {}
|
||||
for (const [key, value] of Object.entries(filter)) {
|
||||
if (value !== undefined) {
|
||||
where[key] = value
|
||||
}
|
||||
}
|
||||
return where
|
||||
}
|
||||
|
||||
/**
|
||||
* DBAL Adapter implementation using Prisma
|
||||
*/
|
||||
const prismaAdapter: DBALAdapter = {
|
||||
async create(entity: string, data: Record<string, unknown>): Promise<unknown> {
|
||||
const model = getModel(entity)
|
||||
return model.create({ data })
|
||||
},
|
||||
|
||||
async read(entity: string, id: string): Promise<unknown | null> {
|
||||
const model = getModel(entity)
|
||||
return model.findUnique({ where: { id } })
|
||||
},
|
||||
|
||||
async update(entity: string, id: string, data: Record<string, unknown>): Promise<unknown> {
|
||||
const model = getModel(entity)
|
||||
// Filter out undefined values
|
||||
const cleanData: Record<string, unknown> = {}
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
if (value !== undefined) {
|
||||
cleanData[key] = value
|
||||
}
|
||||
}
|
||||
return model.update({ where: { id }, data: cleanData })
|
||||
},
|
||||
|
||||
async delete(entity: string, id: string): Promise<boolean> {
|
||||
const model = getModel(entity)
|
||||
try {
|
||||
await model.delete({ where: { id } })
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
async list(entity: string, options?: ListOptions): Promise<ListResult<unknown>> {
|
||||
const model = getModel(entity)
|
||||
const page = options?.page || 1
|
||||
const limit = options?.limit || 1000
|
||||
const skip = (page - 1) * limit
|
||||
const where = options?.filter ? buildWhereClause(options.filter) : undefined
|
||||
const orderBy = options?.sort
|
||||
|
||||
const [data, total] = await Promise.all([
|
||||
model.findMany({
|
||||
where,
|
||||
orderBy,
|
||||
skip,
|
||||
take: limit,
|
||||
}),
|
||||
model.count({ where }),
|
||||
])
|
||||
|
||||
return {
|
||||
data,
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
hasMore: skip + limit < total,
|
||||
}
|
||||
},
|
||||
|
||||
async findFirst(entity: string, options?: { where?: Record<string, unknown> }): Promise<unknown | null> {
|
||||
const model = getModel(entity)
|
||||
const where = options?.where ? buildWhereClause(options.where) : undefined
|
||||
return model.findFirst({ where })
|
||||
},
|
||||
|
||||
async upsert(entity: string, options: { where: Record<string, unknown>; update: Record<string, unknown>; create: Record<string, unknown> }): Promise<unknown> {
|
||||
const model = getModel(entity)
|
||||
return model.upsert({
|
||||
where: options.where,
|
||||
update: options.update,
|
||||
create: options.create,
|
||||
})
|
||||
},
|
||||
|
||||
async close(): Promise<void> {
|
||||
await prisma.$disconnect()
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DBAL adapter singleton for database operations
|
||||
*/
|
||||
export const getAdapter = (): DBALAdapter => {
|
||||
return prismaAdapter
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the DBAL adapter connection
|
||||
*/
|
||||
export const closeAdapter = async (): Promise<void> => {
|
||||
await prismaAdapter.close()
|
||||
}
|
||||
export { getAdapter } from './dbal-client/get-adapter'
|
||||
export { closeAdapter } from './dbal-client/close-adapter'
|
||||
|
||||
@@ -2,6 +2,8 @@ import { LUA_SNIPPETS, LUA_SNIPPET_CATEGORIES, type LuaSnippet } from './snippet
|
||||
import { getSnippetsByCategory } from './functions/get-snippets-by-category'
|
||||
import { searchSnippets } from './functions/search-snippets'
|
||||
import { getSnippetById } from './functions/get-snippet-by-id'
|
||||
import { getSnippetCategoryCounts } from './functions/get-snippet-category-counts'
|
||||
import { getAllSnippetTags } from './functions/get-all-snippet-tags'
|
||||
|
||||
/**
|
||||
* LuaSnippetUtils - Class wrapper for Lua snippet utility functions
|
||||
@@ -39,30 +41,12 @@ export class LuaSnippetUtils {
|
||||
/**
|
||||
* Get count of snippets per category
|
||||
*/
|
||||
static getCategoryCounts(): Record<string, number> {
|
||||
const counts: Record<string, number> = { All: LUA_SNIPPETS.length }
|
||||
|
||||
for (const snippet of LUA_SNIPPETS) {
|
||||
counts[snippet.category] = (counts[snippet.category] || 0) + 1
|
||||
}
|
||||
|
||||
return counts
|
||||
}
|
||||
static getCategoryCounts = getSnippetCategoryCounts
|
||||
|
||||
/**
|
||||
* Get all unique tags across snippets
|
||||
*/
|
||||
static getAllTags(): string[] {
|
||||
const tagSet = new Set<string>()
|
||||
|
||||
for (const snippet of LUA_SNIPPETS) {
|
||||
for (const tag of snippet.tags) {
|
||||
tagSet.add(tag)
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(tagSet).sort()
|
||||
}
|
||||
static getAllTags = getAllSnippetTags
|
||||
}
|
||||
|
||||
// Re-export types for convenience
|
||||
|
||||
@@ -21,3 +21,5 @@ export { executeLuaCode } from './execution/execute-lua-code'
|
||||
export { getSnippetsByCategory } from './get-snippets-by-category'
|
||||
export { searchSnippets } from './search-snippets'
|
||||
export { getSnippetById } from './get-snippet-by-id'
|
||||
export { getSnippetCategoryCounts } from './get-snippet-category-counts'
|
||||
export { getAllSnippetTags } from './get-all-snippet-tags'
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { SecurityScanResult } from '../types'
|
||||
import { scanHTML } from './scan-html'
|
||||
import { scanJavaScript } from './scan-javascript'
|
||||
import { scanJSON } from './scan-json'
|
||||
import { scanLua } from './scan-lua'
|
||||
|
||||
/**
|
||||
* Convenience function to scan code for vulnerabilities
|
||||
* Automatically detects type based on content or explicit type parameter
|
||||
*/
|
||||
export const scanForVulnerabilities = (
|
||||
code: string,
|
||||
type?: 'javascript' | 'lua' | 'json' | 'html'
|
||||
): SecurityScanResult => {
|
||||
let resolvedType = type
|
||||
|
||||
if (!resolvedType) {
|
||||
if (code.trim().startsWith('{') || code.trim().startsWith('[')) {
|
||||
resolvedType = 'json'
|
||||
} else if (code.includes('function') && code.includes('end')) {
|
||||
resolvedType = 'lua'
|
||||
} else if (code.includes('<') && code.includes('>')) {
|
||||
resolvedType = 'html'
|
||||
} else {
|
||||
resolvedType = 'javascript'
|
||||
}
|
||||
}
|
||||
|
||||
switch (resolvedType) {
|
||||
case 'lua':
|
||||
return scanLua(code)
|
||||
case 'json':
|
||||
return scanJSON(code)
|
||||
case 'html':
|
||||
return scanHTML(code)
|
||||
default:
|
||||
return scanJavaScript(code)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user