mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
Merge pull request #14460 from brandongregoryscott/fix/docs-sidebar-not-highlighting-current-position
[Doc site] Fix Database > Full Text Search sidebar highlighting + broken links
This commit is contained in:
6 files changed
+167
-23
No files matched your search
@@ -0,0 +1,30 @@
|
||||
name: Docs Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: ['master']
|
||||
paths:
|
||||
- 'apps/docs/**/*.{ts,tsx}'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install deps
|
||||
run: npm ci
|
||||
|
||||
- name: Run tests
|
||||
run: npm run test:docs
|
||||
@@ -0,0 +1,96 @@
|
||||
import { getAnchor, removeAnchor } from './CustomHTMLElements.utils'
|
||||
|
||||
describe('CustomHTMLElementsUtils', () => {
|
||||
describe('getAnchor', () => {
|
||||
describe('when value is an object', () => {
|
||||
it('returns slugified version of props.children', () => {
|
||||
const value = {
|
||||
props: {
|
||||
children: 'Full Text Search',
|
||||
},
|
||||
}
|
||||
|
||||
const result = getAnchor(value)
|
||||
|
||||
expect(result).toStrictEqual('full-text-search')
|
||||
})
|
||||
})
|
||||
|
||||
describe('when value is an array', () => {
|
||||
describe('when custom anchor exists', () => {
|
||||
it('returns inner slug', () => {
|
||||
const value = ['Proximity: <->', '[#proximity]']
|
||||
|
||||
const result = getAnchor(value)
|
||||
|
||||
expect(result).toStrictEqual('proximity')
|
||||
})
|
||||
|
||||
it('trims whitespace', () => {
|
||||
const value = ['Proximity: <->', ' [#proximity] ']
|
||||
|
||||
const result = getAnchor(value)
|
||||
|
||||
expect(result).toStrictEqual('proximity')
|
||||
})
|
||||
})
|
||||
|
||||
it('returns concatenated slug of elements', () => {
|
||||
const value = ['Full', 'Text', 'Search']
|
||||
|
||||
const result = getAnchor(value)
|
||||
|
||||
expect(result).toStrictEqual('full-text-search')
|
||||
})
|
||||
|
||||
it('trims whitespace', () => {
|
||||
const value = [' Full ', ' Text ', ' Search ']
|
||||
|
||||
const result = getAnchor(value)
|
||||
|
||||
expect(result).toStrictEqual('full-text-search')
|
||||
})
|
||||
|
||||
it('removes special characters', () => {
|
||||
const value = ['function()']
|
||||
|
||||
const result = getAnchor(value)
|
||||
|
||||
expect(result).toStrictEqual('function')
|
||||
})
|
||||
})
|
||||
|
||||
describe('when value is a string', () => {
|
||||
it('returns slugified version of string', () => {
|
||||
const value = 'My (Very) Awesome Heading'
|
||||
|
||||
const result = getAnchor(value)
|
||||
|
||||
expect(result).toStrictEqual('my-very-awesome-heading')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('removeAnchor', () => {
|
||||
describe('when value is an array', () => {
|
||||
it('filters out custom anchor elements', () => {
|
||||
const value = ['My (Very) Awesome Heading', '[#my-custom-heading]']
|
||||
|
||||
const result = removeAnchor(value)
|
||||
|
||||
expect(result).toStrictEqual(['My (Very) Awesome Heading'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('when value is a string', () => {
|
||||
it('strips out custom anchor string', () => {
|
||||
const value = 'My (Very) Awesome Heading [#my-custom-heading]'
|
||||
|
||||
const result = removeAnchor(value)
|
||||
|
||||
// Original implementation didn't trim the resulting string - not sure if it really matters
|
||||
expect(result).toStrictEqual('My (Very) Awesome Heading ')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -2,53 +2,60 @@
|
||||
export const getAnchor = (text: any): string | undefined => {
|
||||
if (typeof text === 'object') {
|
||||
if (Array.isArray(text)) {
|
||||
const customAnchor = text.find(
|
||||
(x) => typeof x === 'string' && x.includes('[#') && x.endsWith(']')
|
||||
)
|
||||
if (customAnchor !== undefined) return customAnchor.slice(2, customAnchor.indexOf(']'))
|
||||
const customAnchor = text.find((x) => typeof x === 'string' && hasCustomAnchor(x))
|
||||
if (customAnchor !== undefined) {
|
||||
return parseCustomAnchor(customAnchor)
|
||||
}
|
||||
|
||||
const formattedText = text
|
||||
.map((x) => {
|
||||
if (typeof x !== 'string') return x.props.children
|
||||
else return x.trim()
|
||||
if (typeof x !== 'string') {
|
||||
return x.props.children
|
||||
}
|
||||
|
||||
return x.trim()
|
||||
})
|
||||
.map((x) => {
|
||||
if (typeof x !== 'string') return x
|
||||
else
|
||||
if (typeof x !== 'string') {
|
||||
return x
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9- ]/g, '')
|
||||
.replace(/[ ]/g, '-')
|
||||
}
|
||||
|
||||
return slugify(x)
|
||||
})
|
||||
|
||||
return formattedText.join('-').toLowerCase()
|
||||
} else {
|
||||
const anchor = text.props.children
|
||||
if (typeof anchor === 'string') {
|
||||
return anchor
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9- ]/g, '')
|
||||
.replace(/[ ]/g, '-')
|
||||
return slugify(anchor)
|
||||
}
|
||||
return anchor
|
||||
}
|
||||
} else if (typeof text === 'string') {
|
||||
if (text.includes('[#') && text.endsWith(']')) {
|
||||
return text.slice(text.indexOf('[#') + 2, text.indexOf(']'))
|
||||
} else {
|
||||
return text
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9- ]/g, '')
|
||||
.replace(/[ ]/g, '-')
|
||||
if (hasCustomAnchor(text)) {
|
||||
return parseCustomAnchor(text)
|
||||
}
|
||||
return slugify(text)
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
const hasCustomAnchor = (value: string): boolean => value.includes('[#') && value.includes(']')
|
||||
|
||||
const parseCustomAnchor = (value: string): string =>
|
||||
value.slice(value.indexOf('[#') + 2, value.indexOf(']'))
|
||||
|
||||
const slugify = (value: string): string =>
|
||||
value
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.replace(/[^a-z0-9- ]/g, '')
|
||||
.replace(/[ ]/g, '-')
|
||||
|
||||
export const removeAnchor = (text: any) => {
|
||||
if (typeof text === 'object' && Array.isArray(text)) {
|
||||
return text.filter((x) => !(typeof x === 'string' && x.includes('[#') && x.endsWith(']')))
|
||||
return text.filter((x) => !(typeof x === 'string' && hasCustomAnchor(x)))
|
||||
} else if (typeof text === 'string') {
|
||||
if (text.indexOf('[#') > 0) return text.slice(0, text.indexOf('[#'))
|
||||
else return text
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { Config } from '@jest/types'
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
preset: 'ts-jest',
|
||||
setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],
|
||||
testEnvironment: 'jsdom',
|
||||
}
|
||||
|
||||
export default config
|
||||
@@ -9,6 +9,7 @@
|
||||
"build:analyze": "ANALYZE=true next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"test": "jest",
|
||||
"build:sitemap": "node ./internals/generate-sitemap.mjs",
|
||||
"embeddings": "tsx scripts/search/generate-embeddings.ts",
|
||||
"embeddings:refresh": "npm run embeddings -- --refresh",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"docker:up": "cd docker && docker compose up",
|
||||
"docker:down": "cd docker && docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml down --remove-orphans",
|
||||
"docker:remove": "cd docker && docker compose -f docker-compose.yml -f ./dev/docker-compose.dev.yml rm -vfs",
|
||||
"test:docs": "turbo run test --filter=docs",
|
||||
"test:ui": "turbo run test --filter=ui",
|
||||
"test:studio": "turbo run test --filter=studio",
|
||||
"perf:kong": "ab -t 5 -c 20 -T application/json http://localhost:8000/",
|
||||
|
||||
Reference in new issue
Block a user