mirror of
https://github.com/supabase/supabase.git
synced 2026-09-07 02:20:52 +08:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Docs enhancement: Agent-ready prompt blocks on all 18 framework quickstart pages. ## What is the current behavior? Framework quickstarts do not surface a copyable AI prompt. Readers have to assemble context themselves when asking an AI coding assistant to follow the guide. ## What is the new behavior? - Partials at `apps/docs/content/_partials/ai/quickstart_prompt_{framework}.mdx` contain `<AiPrompt prompt={...} />` (Prettier multiline single-quoted JS string with `\n` escapes). - Each quickstart includes `<$Partial path="ai/quickstart_prompt_{framework}.mdx" />`. - Runtime: `AiPrompt` → `PromptPanel` (Copy AI Prompt, expandable). - Markdown export: `apps/docs/internals/markdown-schema/AiPrompt.ts` decodes Prettier single-quoted prompt expressions so exported markdown includes an **AI Prompt** section without quote leak. - Shared `$Partial` helpers live in `lib/partials.utils.ts`. - Closes DOCS-1144. ### Example before/after | | Production | Preview | | --- | --- | --- | | Next.js quickstart | [production](https://supabase.com/docs/guides/getting-started/quickstarts/nextjs) | [preview](https://docs-git-nikrichers-docs-1144-add-ai-prompt-blo-5af4d8-supabase.vercel.app/docs/guides/getting-started/quickstarts/nextjs) | **Light** | Before | After | | --- | --- | |  |  | **Dark** | Before | After | | --- | --- | |  |  | ### Test plan - [x] Preview renders AI Prompt panel with copy - [x] Spot-check Next.js, Flutter, Expo, Vue - [x] `test-quickstart-prompts` structural - [x] Markdown export includes **AI Prompt** without quote leak - [x] Format CI green after prettier/single-quote decode fix ## Additional context - Worktree: `~/GitHub/supabase/supabase-worktrees/nikrichers/docs-1144-add-ai-prompt-blocks-to-all-18-framework-quickstarts` - Skills: `generate-quickstart-prompts` / `test-quickstart-prompts`; librarian update https://github.com/supabase/docs-agent-skills/pull/21 - `PromptPanel` replaced the older GlassPanel experiment for the expandable copy UI --------- Co-authored-by: Nik Richers <nik@validmind.ai> Co-authored-by: jeremenichelli <jeremenichelli@users.noreply.github.com>
68 lines
2.3 KiB
TypeScript
68 lines
2.3 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { parsePartialVariables, substitutePartialVars } from './partials.utils'
|
|
|
|
describe('substitutePartialVars', () => {
|
|
it('substitutes provided variables', () => {
|
|
const content = 'Here is a partial that takes a {{ .var }}.'
|
|
expect(substitutePartialVars(content, { var: 'string replacement' })).toBe(
|
|
'Here is a partial that takes a string replacement.'
|
|
)
|
|
})
|
|
|
|
it('renders unprovided variables as empty strings', () => {
|
|
const content = 'Here is a partial that takes a {{ .var }}.'
|
|
expect(substitutePartialVars(content, undefined)).toBe('Here is a partial that takes a .')
|
|
})
|
|
|
|
it('ignores variables that are not referenced in the content', () => {
|
|
const content = 'Here is a partial that takes a {{ .var }}.'
|
|
expect(substitutePartialVars(content, { var: 'correct', extra: 'unused' })).toBe(
|
|
'Here is a partial that takes a correct.'
|
|
)
|
|
})
|
|
|
|
it('supports hyphenated variable names', () => {
|
|
const content = 'This partial has {{ .my-var }}, {{ .another_var }}, and {{ .myVar123 }}.'
|
|
expect(
|
|
substitutePartialVars(content, {
|
|
'my-var': 'hyphenated value',
|
|
another_var: 'underscored value',
|
|
myVar123: 'alphanumeric value',
|
|
})
|
|
).toBe('This partial has hyphenated value, underscored value, and alphanumeric value.')
|
|
})
|
|
|
|
it('handles values containing $ replacement patterns literally', () => {
|
|
expect(substitutePartialVars('Hello {{ .name }}', { name: '$& is literal' })).toBe(
|
|
'Hello $& is literal'
|
|
)
|
|
})
|
|
|
|
it('handles keys containing regex metacharacters', () => {
|
|
expect(substitutePartialVars('Hello {{ .a.b }}', { 'a.b': 'world' })).toBe('Hello world')
|
|
})
|
|
})
|
|
|
|
describe('parsePartialVariables', () => {
|
|
it('returns undefined when variables are omitted', () => {
|
|
expect(parsePartialVariables(undefined)).toBeUndefined()
|
|
})
|
|
|
|
it('parses JSON object strings', () => {
|
|
expect(parsePartialVariables('{ "product": "Auth" }')).toEqual({
|
|
product: 'Auth',
|
|
})
|
|
})
|
|
|
|
it('accepts already-parsed objects', () => {
|
|
expect(parsePartialVariables({ product: 'Auth' })).toEqual({
|
|
product: 'Auth',
|
|
})
|
|
})
|
|
|
|
it('throws on non-string values', () => {
|
|
expect(() => parsePartialVariables('{ "var": [0, 1, 2] }')).toThrow(/valid JSON/)
|
|
})
|
|
})
|