This commit is contained in:
2026-01-19 09:23:22 +00:00
parent 18b383a156
commit 9d81e9d2c1
16 changed files with 843 additions and 3 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,584 @@
---
queries:
-
pack: custom/low-code-react-migration#0
relativeQueryPath: queries/ComponentFilesWithJSX.ql
relativeBqrsPath: custom/low-code-react-migration/queries/ComponentFilesWithJSX.bqrs
metadata:
name: Component files with JSX
description: Lists component TSX files that contain JSX (candidate for JSON conversion).
kind: problem
severity: warning
id: custom/component-files-with-jsx
-
pack: custom/low-code-react-migration#0
relativeQueryPath: queries/ComponentHooksUsage.ql
relativeBqrsPath: custom/low-code-react-migration/queries/ComponentHooksUsage.bqrs
metadata:
name: React hook usage in components
description: Flags component files that call React hooks (likely needs custom
hook extraction).
kind: problem
severity: warning
id: custom/component-hooks-usage
-
pack: custom/low-code-react-migration#0
relativeQueryPath: queries/LegacyComponentImports.ql
relativeBqrsPath: custom/low-code-react-migration/queries/LegacyComponentImports.bqrs
metadata:
name: Legacy component imports
description: Finds imports still referencing legacy components instead of JSON
components.
kind: problem
severity: warning
id: custom/legacy-component-imports
extensionPacks: []
packs:
codeql/javascript-all#1:
name: codeql/javascript-all
version: 2.6.19
isLibrary: true
isExtensionPack: false
localPath: file:///Users/rmac/.codeql/packages/codeql/javascript-all/2.6.19/
localPackDefinitionFile: file:///Users/rmac/.codeql/packages/codeql/javascript-all/2.6.19/qlpack.yml
headSha: b4f4b0e6b0d0e819d1242d1911d54af219e065db
runDataExtensions: []
codeql/threat-models#2:
name: codeql/threat-models
version: 1.0.39
isLibrary: true
isExtensionPack: false
localPath: file:///Users/rmac/.codeql/packages/codeql/threat-models/1.0.39/
localPackDefinitionFile: file:///Users/rmac/.codeql/packages/codeql/threat-models/1.0.39/qlpack.yml
headSha: b4f4b0e6b0d0e819d1242d1911d54af219e065db
runDataExtensions: []
custom/low-code-react-migration#0:
name: custom/low-code-react-migration
version: 0.0.1
isLibrary: false
isExtensionPack: false
localPath: file:///Users/rmac/.claude-worktrees/low-code-react-app-b/distracted-hawking/codeql/custom-queries/
localPackDefinitionFile: file:///Users/rmac/.claude-worktrees/low-code-react-app-b/distracted-hawking/codeql/custom-queries/qlpack.yml
runDataExtensions:
-
pack: codeql/javascript-all#1
relativePath: ext/apollo-server.model.yml
index: 0
firstRowId: 0
rowCount: 1
locations:
lineNumbers: A=6
columnNumbers: A=9
-
pack: codeql/javascript-all#1
relativePath: ext/apollo-server.model.yml
index: 1
firstRowId: 1
rowCount: 2
locations:
lineNumbers: A=12+1
columnNumbers: A=9*2
-
pack: codeql/javascript-all#1
relativePath: ext/apollo-server.model.yml
index: 2
firstRowId: 3
rowCount: 10
locations:
lineNumbers: A=19+1*9
columnNumbers: A=9*10
-
pack: codeql/javascript-all#1
relativePath: ext/aws-sdk.model.yml
index: 0
firstRowId: 13
rowCount: 8
locations:
lineNumbers: A=6+1*7
columnNumbers: A=9*8
-
pack: codeql/javascript-all#1
relativePath: ext/aws-sdk.model.yml
index: 1
firstRowId: 21
rowCount: 10
locations:
lineNumbers: A=18+1*9
columnNumbers: A=9*10
-
pack: codeql/javascript-all#1
relativePath: ext/aws-sdk.model.yml
index: 2
firstRowId: 31
rowCount: 8
locations:
lineNumbers: A=32+1*7
columnNumbers: A=9*8
-
pack: codeql/javascript-all#1
relativePath: ext/aws-sdk.model.yml
index: 3
firstRowId: 39
rowCount: 9
locations:
lineNumbers: A=44+1*8
columnNumbers: A=9*9
-
pack: codeql/javascript-all#1
relativePath: ext/axios.model.yml
index: 0
firstRowId: 48
rowCount: 1
locations:
lineNumbers: A=6
columnNumbers: A=9
-
pack: codeql/javascript-all#1
relativePath: ext/axios.model.yml
index: 1
firstRowId: 49
rowCount: 1
locations:
lineNumbers: A=12
columnNumbers: A=9
-
pack: codeql/javascript-all#1
relativePath: ext/call-me-maybe.model.yml
index: 0
firstRowId: 50
rowCount: 1
locations:
lineNumbers: A=6
columnNumbers: A=9
-
pack: codeql/javascript-all#1
relativePath: ext/cors.model.yml
index: 0
firstRowId: 51
rowCount: 1
locations:
lineNumbers: A=6
columnNumbers: A=9
-
pack: codeql/javascript-all#1
relativePath: ext/default-threat-models-fixup.model.yml
index: 0
firstRowId: 52
rowCount: 1
locations:
lineNumbers: A=8
columnNumbers: A=9
-
pack: codeql/javascript-all#1
relativePath: ext/graph-ql.model.yml
index: 0
firstRowId: 53
rowCount: 1
locations:
lineNumbers: A=6
columnNumbers: A=9
-
pack: codeql/javascript-all#1
relativePath: ext/graph-ql.model.yml
index: 1
firstRowId: 54
rowCount: 1
locations:
lineNumbers: A=11
columnNumbers: A=9
-
pack: codeql/javascript-all#1
relativePath: ext/hana-db-client.model.yml
index: 0
firstRowId: 55
rowCount: 4
locations:
lineNumbers: A=6+1*3
columnNumbers: A=9*4
-
pack: codeql/javascript-all#1
relativePath: ext/hana-db-client.model.yml
index: 1
firstRowId: 59
rowCount: 2
locations:
lineNumbers: A=15+1
columnNumbers: A=9*2
-
pack: codeql/javascript-all#1
relativePath: ext/hana-db-client.model.yml
index: 2
firstRowId: 61
rowCount: 6
locations:
lineNumbers: A=22+1*5
columnNumbers: A=9*6
-
pack: codeql/javascript-all#1
relativePath: ext/make-dir.model.yml
index: 0
firstRowId: 67
rowCount: 1
locations:
lineNumbers: A=6
columnNumbers: A=9
-
pack: codeql/javascript-all#1
relativePath: ext/markdown-table.model.yml
index: 0
firstRowId: 68
rowCount: 1
locations:
lineNumbers: A=6
columnNumbers: A=9
-
pack: codeql/javascript-all#1
relativePath: ext/mkdirp.model.yml
index: 0
firstRowId: 69
rowCount: 2
locations:
lineNumbers: A=6+1
columnNumbers: A=9*2
-
pack: codeql/javascript-all#1
relativePath: ext/open.model.yml
index: 0
firstRowId: 71
rowCount: 2
locations:
lineNumbers: A=6+1
columnNumbers: A=9*2
-
pack: codeql/javascript-all#1
relativePath: ext/react-relay-threat.model.yml
index: 0
firstRowId: 73
rowCount: 10
locations:
lineNumbers: A=6+1*9
columnNumbers: A=9*10
-
pack: codeql/javascript-all#1
relativePath: ext/react.model.yml
index: 0
firstRowId: 83
rowCount: 1
locations:
lineNumbers: A=6
columnNumbers: A=9
-
pack: codeql/javascript-all#1
relativePath: ext/rimraf.model.yml
index: 0
firstRowId: 84
rowCount: 3
locations:
lineNumbers: A=6+1*2
columnNumbers: A=9*3
-
pack: codeql/javascript-all#1
relativePath: ext/shelljs.model.yml
index: 0
firstRowId: 87
rowCount: 1
locations:
lineNumbers: A=6
columnNumbers: A=9
-
pack: codeql/javascript-all#1
relativePath: ext/tanstack.model.yml
index: 0
firstRowId: 88
rowCount: 6
locations:
lineNumbers: A=6+1*5
columnNumbers: A=9*6
-
pack: codeql/javascript-all#1
relativePath: ext/underscore.string.model.yml
index: 0
firstRowId: 94
rowCount: 5
locations:
lineNumbers: A=6+1*4
columnNumbers: A=9*5
-
pack: codeql/javascript-all#1
relativePath: ext/underscore.string.model.yml
index: 1
firstRowId: 99
rowCount: 20
locations:
lineNumbers: A=16+1*19
columnNumbers: A=9*20
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/NoSQL.model.yml
index: 0
firstRowId: 119
rowCount: 4
locations:
lineNumbers: A=8+3+1*2
columnNumbers: A=9*4
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/NodeJSLib.model.yml
index: 0
firstRowId: 123
rowCount: 5
locations:
lineNumbers: A=6+1*4
columnNumbers: A=9*5
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/SQL.model.yml
index: 0
firstRowId: 128
rowCount: 5
locations:
lineNumbers: A=6+1*4
columnNumbers: A=9*5
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/SQL.model.yml
index: 1
firstRowId: 133
rowCount: 4
locations:
lineNumbers: A=16+1*3
columnNumbers: A=9*4
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/helmet/Helmet.Required.Setting.model.yml
index: 0
firstRowId: 137
rowCount: 2
locations:
lineNumbers: A=6+1
columnNumbers: A=9*2
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/minimongo/model.yml
index: 0
firstRowId: 139
rowCount: 75
locations:
lineNumbers: A=6+1*74
columnNumbers: A=9*75
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/mongodb/model.yml
index: 0
firstRowId: 214
rowCount: 26
locations:
lineNumbers: A=6+1*25
columnNumbers: A=9*26
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/mongodb/model.yml
index: 1
firstRowId: 240
rowCount: 611
locations:
lineNumbers: A=37+1*610
columnNumbers: A=9*611
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/mongodb/model.yml
index: 2
firstRowId: 851
rowCount: 32
locations:
lineNumbers: A=653+1*31
columnNumbers: A=9*32
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/mongodb/model.yml
index: 3
firstRowId: 883
rowCount: 102
locations:
lineNumbers: A=690+1*101
columnNumbers: A=9*102
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/mssql/model.yml
index: 0
firstRowId: 985
rowCount: 34
locations:
lineNumbers: A=6+1*33
columnNumbers: A=9*34
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/mysql/model.yml
index: 0
firstRowId: 1019
rowCount: 57
locations:
lineNumbers: A=6+1*56
columnNumbers: A=9*57
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/mysql/model.yml
index: 1
firstRowId: 1076
rowCount: 3
locations:
lineNumbers: A=68+1*2
columnNumbers: A=9*3
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/pg/model.yml
index: 0
firstRowId: 1079
rowCount: 65
locations:
lineNumbers: A=6+1*64
columnNumbers: A=9*65
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/pg/model.yml
index: 1
firstRowId: 1144
rowCount: 5
locations:
lineNumbers: A=76+1*4
columnNumbers: A=9*5
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/pg/model.yml
index: 2
firstRowId: 1149
rowCount: 23
locations:
lineNumbers: A=86+1*22
columnNumbers: A=9*23
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/sequelize/model.yml
index: 0
firstRowId: 1172
rowCount: 7
locations:
lineNumbers: A=6+1*6
columnNumbers: A=9*7
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/sequelize/model.yml
index: 1
firstRowId: 1179
rowCount: 248
locations:
lineNumbers: A=18+1*247
columnNumbers: A=9*248
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/sequelize/model.yml
index: 2
firstRowId: 1427
rowCount: 5
locations:
lineNumbers: A=271+1*4
columnNumbers: A=9*5
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/sequelize/model.yml
index: 3
firstRowId: 1432
rowCount: 2
locations:
lineNumbers: A=281+1
columnNumbers: A=9*2
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/spanner/model.yml
index: 0
firstRowId: 1434
rowCount: 174
locations:
lineNumbers: A=6+1*173
columnNumbers: A=9*174
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/spanner/model.yml
index: 1
firstRowId: 1608
rowCount: 5
locations:
lineNumbers: A=185+1*4
columnNumbers: A=9*5
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/sqlite3/model.yml
index: 0
firstRowId: 1613
rowCount: 15
locations:
lineNumbers: A=6+1*14
columnNumbers: A=9*15
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/frameworks/sqlite3/model.yml
index: 1
firstRowId: 1628
rowCount: 3
locations:
lineNumbers: A=26+1*2
columnNumbers: A=9*3
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/security/domains/IntegrityCheckingRequired/integrity_checking_required.model.yml
index: 0
firstRowId: 1631
rowCount: 3
locations:
lineNumbers: A=6+1*2
columnNumbers: A=9*3
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/security/domains/compromised/compromised_domains.model.yml
index: 0
firstRowId: 1634
rowCount: 1
locations:
lineNumbers: A=6
columnNumbers: A=9
-
pack: codeql/javascript-all#1
relativePath: semmle/javascript/security/domains/untrusted/untrusted_domains.model.yml
index: 0
firstRowId: 1635
rowCount: 6
locations:
lineNumbers: A=7+1+3+1*3
columnNumbers: A=9*6
-
pack: codeql/threat-models#2
relativePath: ext/supported-threat-models.model.yml
index: 0
firstRowId: 1641
rowCount: 1
locations:
lineNumbers: A=6
columnNumbers: A=9
-
pack: codeql/threat-models#2
relativePath: ext/threat-model-grouping.model.yml
index: 0
firstRowId: 1642
rowCount: 15
locations:
lineNumbers: A=8+3+1+3+1*5+3+1+5+1*3
columnNumbers: A=9*15
codeql/util#3:
name: codeql/util
version: 2.0.26
isLibrary: true
isExtensionPack: false
localPath: file:///Users/rmac/.codeql/packages/codeql/util/2.0.26/
localPackDefinitionFile: file:///Users/rmac/.codeql/packages/codeql/util/2.0.26/qlpack.yml
headSha: b4f4b0e6b0d0e819d1242d1911d54af219e065db
runDataExtensions: []

View File

@@ -9,7 +9,7 @@ import javascript
import semmle.javascript.JSX
predicate isComponentFile(File f) {
f.getRelativePath().regexpMatch("^src/components/.*\\.tsx$")
f.getRelativePath().regexpMatch("^(src/)?components/.*\\.tsx$")
}
from JsxElement jsx, File f

View File

@@ -8,7 +8,7 @@
import javascript
predicate isComponentFile(File f) {
f.getRelativePath().regexpMatch("^src/components/.*\\.tsx$")
f.getRelativePath().regexpMatch("^(src/)?components/.*\\.tsx$")
}
predicate isReactHookName(string name) {

View File

@@ -0,0 +1,143 @@
{
"id": "navigation-menu",
"type": "Sidebar",
"props": {
"side": "left",
"collapsible": "offcanvas"
},
"children": [
{
"id": "navigation-menu-header",
"type": "SidebarHeader",
"props": {
"className": "px-4 py-4 border-b"
},
"children": [
{
"id": "navigation-menu-title",
"type": "h2",
"props": {
"className": "text-lg font-semibold"
},
"bindings": {
"children": {
"source": "labels",
"transform": "data.title"
}
}
},
{
"id": "navigation-menu-controls",
"type": "div",
"props": {
"className": "flex gap-2 mt-4"
},
"children": [
{
"id": "navigation-menu-expand-all",
"type": "Button",
"props": {
"variant": "outline",
"size": "sm",
"className": "flex-1"
},
"bindings": {
"onClick": "expandAll"
},
"children": [
{
"id": "navigation-menu-expand-icon",
"type": "CaretDoubleDown",
"props": {
"size": 16,
"className": "mr-2"
}
},
{
"id": "navigation-menu-expand-label",
"type": "span",
"bindings": {
"children": {
"source": "labels",
"transform": "data.expandAll"
}
}
}
]
},
{
"id": "navigation-menu-collapse-all",
"type": "Button",
"props": {
"variant": "outline",
"size": "sm",
"className": "flex-1"
},
"bindings": {
"onClick": "collapseAll"
},
"children": [
{
"id": "navigation-menu-collapse-icon",
"type": "CaretDoubleUp",
"props": {
"size": 16,
"className": "mr-2"
}
},
{
"id": "navigation-menu-collapse-label",
"type": "span",
"bindings": {
"children": {
"source": "labels",
"transform": "data.collapseAll"
}
}
}
]
}
]
}
]
},
{
"id": "navigation-menu-content",
"type": "SidebarContent",
"children": [
{
"id": "navigation-menu-scroll",
"type": "ScrollArea",
"props": {
"className": "h-full px-4"
},
"children": [
{
"id": "navigation-menu-group-list",
"type": "div",
"props": {
"className": "space-y-2 py-4"
},
"children": [
{
"id": "navigation-menu-groups-repeat",
"type": "_repeat",
"bindings": {
"_items": {
"source": "groups",
"transform": "data || []"
},
"_renderItem": {
"source": ["toggleGroup", "onItemClick", "onItemHover", "onItemLeave"],
"transform": "(group) => { const toggleGroup = data[0]; const onItemClick = data[1]; const onItemHover = data[2]; const onItemLeave = data[3]; return { _element: 'Collapsible', _key: group.id, _props: { open: group.isExpanded, onOpenChange: () => toggleGroup(group.id) }, _children: [{ _element: 'CollapsibleTrigger', _props: { className: 'w-full flex items-center gap-2 px-2 py-2 rounded-lg hover:bg-muted transition-colors group' }, _children: [{ _element: 'CaretDown', _props: { size: 16, weight: 'bold', className: `text-muted-foreground transition-transform ${group.isExpanded ? 'rotate-0' : '-rotate-90'}` } }, { _element: 'h3', _props: { className: 'flex-1 text-left text-xs font-semibold text-muted-foreground uppercase tracking-wider' }, _children: [group.label] }, { _element: 'span', _props: { className: 'text-xs text-muted-foreground' }, _children: [group.visibleCount] }] }, { _element: 'CollapsibleContent', _props: { className: 'mt-1' }, _children: [{ _element: 'div', _props: { className: 'space-y-1 pl-2' }, _children: [{ _element: '_repeat', _props: { _items: group.items || [], _renderItem: (item) => ({ _element: 'div', _key: item.id, _props: { onMouseEnter: () => onItemHover(item.value), onMouseLeave: () => onItemLeave(item.value) }, _children: [{ _element: 'NavigationItem', _props: { icon: item.icon, label: item.label, isActive: item.isActive, badge: item.badge, onClick: () => onItemClick(item.value) } }] }) } }] }] }] }; }"
}
}
}
]
}
]
}
]
}
]
}

View File

@@ -0,0 +1,104 @@
import { useMemo, useState } from 'react'
import { navigationGroups, NavigationItemData } from '@/lib/navigation-config'
import navigationMenuCopy from '@/data/navigation-menu.json'
import { useRoutePreload } from '@/hooks/use-route-preload'
import { FeatureToggles } from '@/types/project'
interface NavigationMenuGroupItem extends NavigationItemData {
isActive: boolean
}
interface NavigationMenuGroup {
id: string
label: string
visibleCount: number
isExpanded: boolean
items: NavigationMenuGroupItem[]
}
export function useNavigationMenu(
activeTab: string,
onTabChange: (tab: string) => void,
featureToggles: FeatureToggles,
errorCount = 0
) {
const [expandedGroupIds, setExpandedGroupIds] = useState<string[]>([
'overview',
'development',
'automation',
'design',
'backend',
'testing',
'tools',
])
const { preloadRoute, cancelPreload } = useRoutePreload({ delay: 100 })
const isItemVisible = (item: NavigationItemData) => {
if (!item.featureKey) return true
return featureToggles[item.featureKey]
}
const groups = useMemo<NavigationMenuGroup[]>(() => {
return navigationGroups
.map((group) => {
const items = group.items
.filter(isItemVisible)
.map((item) => ({
...item,
badge: item.id === 'errors' ? errorCount : item.badge,
isActive: activeTab === item.value,
}))
return {
id: group.id,
label: group.label,
visibleCount: items.length,
isExpanded: expandedGroupIds.includes(group.id),
items,
}
})
.filter((group) => group.visibleCount > 0)
}, [activeTab, errorCount, expandedGroupIds, featureToggles])
const toggleGroup = (groupId: string) => {
setExpandedGroupIds((prev) =>
prev.includes(groupId) ? prev.filter((id) => id !== groupId) : [...prev, groupId]
)
}
const expandAll = () => {
const allGroupIds = navigationGroups
.filter((group) => group.items.some(isItemVisible))
.map((group) => group.id)
setExpandedGroupIds(allGroupIds)
}
const collapseAll = () => {
setExpandedGroupIds([])
}
const onItemClick = (value: string) => {
onTabChange(value)
}
const onItemHover = (value: string) => {
console.log(`[NAV] 🖱️ Hover detected on: ${value}`)
preloadRoute(value)
}
const onItemLeave = (value: string) => {
console.log(`[NAV] 👋 Hover left: ${value}`)
cancelPreload(value)
}
return {
labels: navigationMenuCopy.labels,
groups,
toggleGroup,
expandAll,
collapseAll,
onItemClick,
onItemHover,
onItemLeave,
}
}

View File

@@ -22,6 +22,7 @@ export * from './menu'
export * from './file-upload'
export * from './accordion'
export * from './binding-editor'
export * from './navigation-menu'
export * from './text-gradient'
export * from './error-badge'
export * from './app-logo'

View File

@@ -0,0 +1,8 @@
import { FeatureToggles } from '@/types/project'
export interface NavigationMenuProps {
activeTab: string
onTabChange: (tab: string) => void
featureToggles: FeatureToggles
errorCount?: number
}