vars
This commit is contained in:
@@ -106,14 +106,14 @@ export const ConfigNode = memo(function ConfigNode({ id, data, width, height }:
|
||||
|
||||
const insertVariableReference = useCallback(
|
||||
(sourceNode: any, mode: 'prepend' | 'append' | 'cursor') => {
|
||||
insertAt(`\${${sourceNode.id}}`, mode)
|
||||
insertAt(`{{ ${sourceNode.id} }}`, mode)
|
||||
},
|
||||
[insertAt]
|
||||
)
|
||||
|
||||
const insertFunctionCall = useCallback(
|
||||
(sourceNode: any, mode: 'prepend' | 'append' | 'cursor') => {
|
||||
insertAt(`\${${sourceNode.id}()}`, mode)
|
||||
insertAt(`{{ ${sourceNode.id}() }}`, mode)
|
||||
},
|
||||
[insertAt]
|
||||
)
|
||||
|
||||
@@ -191,8 +191,8 @@ export const RenderingNode = memo(function RenderingNode({ id, width, height }:
|
||||
|
||||
const resolvedIncludes = resolveIncludes(plantumlText)
|
||||
|
||||
const varMap: Record<string, string> = {}
|
||||
// Use null prototype so keys like "var", "constructor", "toString" don't collide with Object.prototype
|
||||
// Use null prototype so keys like "var", "constructor", "toString" don't collide with Object.prototype.
|
||||
// Only Nunjucks {{ var }} / {% if var %} are supported; context is built from connected variable/function nodes.
|
||||
const nunjucksContext = Object.create(null) as Record<string, unknown>
|
||||
|
||||
for (const e of edges) {
|
||||
@@ -201,7 +201,6 @@ export const RenderingNode = memo(function RenderingNode({ id, width, height }:
|
||||
if (src?.type === 'variable') {
|
||||
const v = src.data?.value
|
||||
const str = v === undefined || v === null ? '' : String(v)
|
||||
varMap[src.id] = str
|
||||
// Keep booleans/numbers for {% if %} etc.; Nunjucks treats "false" as truthy
|
||||
nunjucksContext[src.id] =
|
||||
v === undefined || v === null ? '' : typeof v === 'boolean' || typeof v === 'number' ? v : str
|
||||
@@ -229,33 +228,9 @@ export const RenderingNode = memo(function RenderingNode({ id, width, height }:
|
||||
throw new Error(`Nunjucks: ${nunjucksErr?.message ?? String(nunjucksErr)}`)
|
||||
}
|
||||
|
||||
const resolveFunctionCalls = (text: string): string => {
|
||||
const fnCallRegex = /\$\{([\w-]+)\s*\(([^)]*)\)\}/g
|
||||
return text.replace(fnCallRegex, (match, funcId: string, argsStr: string) => {
|
||||
const fnNode = nodes.find((n: any) => n.id === funcId && n.type === 'function')
|
||||
if (!fnNode) return match
|
||||
const body = fnNode.data?.body ?? 'return args[0];'
|
||||
const argIds = argsStr.split(',').map((s: string) => s.trim()).filter(Boolean)
|
||||
const argValues = argIds.map((argId: string) => varMap[argId] ?? '')
|
||||
try {
|
||||
const fn = new Function('args', body)
|
||||
const result = fn(argValues)
|
||||
if (result === undefined || result === null) return ''
|
||||
if (typeof result === 'string' || typeof result === 'number' || typeof result === 'boolean') return String(result)
|
||||
return String(result)
|
||||
} catch {
|
||||
return match
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const resolveVariables = (text: string): string =>
|
||||
text.replace(/\$\{([^}]+)\}/g, (_, varId: string) => varMap[varId.trim()] ?? '')
|
||||
|
||||
const afterFunctions = resolveFunctionCalls(afterNunjucks)
|
||||
let resolvedWithVars = resolveVariables(afterFunctions)
|
||||
let resolvedPlantuml = afterNunjucks
|
||||
if (theme === 'dark') {
|
||||
resolvedWithVars = resolvedWithVars.replace(
|
||||
resolvedPlantuml = resolvedPlantuml.replace(
|
||||
/^(\s*@startuml\s*\n)/i,
|
||||
`$1${DARK_SKINPARAMS}\n`
|
||||
)
|
||||
@@ -264,7 +239,7 @@ export const RenderingNode = memo(function RenderingNode({ id, width, height }:
|
||||
const res = await fetch(KROKI_PLANTUML_SVG, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'text/plain' },
|
||||
body: resolvedWithVars,
|
||||
body: resolvedPlantuml,
|
||||
})
|
||||
|
||||
if (cancelled || thisRunId !== runIdRef.current) return
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { CompletionContext, CompletionResult } from '@codemirror/autocomplete'
|
||||
import type { EditorState } from '@codemirror/state'
|
||||
|
||||
const NUNJUCKS_KEYWORDS = [
|
||||
'if', 'endif', 'elif', 'else', 'for', 'endfor', 'in', 'and', 'or', 'not',
|
||||
@@ -12,10 +13,15 @@ const NUNJUCKS_FILTERS = [
|
||||
'trim', 'escape', 'safe', 'striptags', 'capitalize', 'reverse', 'batch', 'slice',
|
||||
]
|
||||
|
||||
/** Get line text (CodeMirror 6: doc.line(n) is 1-based) */
|
||||
function getLineText(state: EditorState, lineNo0Based: number): string {
|
||||
return state.doc.line(lineNo0Based + 1).text
|
||||
}
|
||||
|
||||
/** Detect if position is inside {{ or {% from the start of the line */
|
||||
function insideNunjucks(doc: { getLine: (n: number) => string }, lineNo: number, pos: number): boolean {
|
||||
const line = doc.getLine(lineNo)
|
||||
const before = line.slice(0, pos)
|
||||
function insideNunjucks(state: EditorState, lineNo0Based: number, posInLine: number): boolean {
|
||||
const line = getLineText(state, lineNo0Based)
|
||||
const before = line.slice(0, posInLine)
|
||||
const openVar = before.lastIndexOf('{{')
|
||||
const openTag = before.lastIndexOf('{%')
|
||||
const closeVar = before.lastIndexOf('}}')
|
||||
@@ -26,11 +32,11 @@ function insideNunjucks(doc: { getLine: (n: number) => string }, lineNo: number,
|
||||
}
|
||||
|
||||
/** Get the word fragment before the cursor for matching */
|
||||
function wordBefore(doc: { getLine: (n: number) => string }, lineNo: number, pos: number): string {
|
||||
const line = doc.getLine(lineNo)
|
||||
let start = pos
|
||||
function wordBefore(state: EditorState, lineNo0Based: number, posInLine: number): string {
|
||||
const line = getLineText(state, lineNo0Based)
|
||||
let start = posInLine
|
||||
while (start > 0 && /[\w.-]/.test(line[start - 1])) start -= 1
|
||||
return line.slice(start, pos)
|
||||
return line.slice(start, posInLine)
|
||||
}
|
||||
|
||||
export function nunjucksCompletionSource(
|
||||
@@ -41,9 +47,9 @@ export function nunjucksCompletionSource(
|
||||
return (context: CompletionContext) => {
|
||||
const { state, pos } = context
|
||||
const line = state.doc.lineAt(pos)
|
||||
if (!insideNunjucks(state.doc, line.number - 1, pos - line.from)) return null
|
||||
if (!insideNunjucks(state, line.number - 1, pos - line.from)) return null
|
||||
|
||||
const word = wordBefore(state.doc, line.number - 1, pos - line.from)
|
||||
const word = wordBefore(state, line.number - 1, pos - line.from)
|
||||
const from = pos - word.length
|
||||
|
||||
const options: { label: string; type?: string; info?: string }[] = []
|
||||
|
||||
Reference in New Issue
Block a user