react-pdf-levelup 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/fn/aggAlias.js +21 -0
- package/fn/moveComponents.js +129 -0
- package/fn/postinstall.js +66 -0
- package/fn/upVersion.js +12 -0
- package/fn/updateTsconfig.js +10 -0
- package/next.config.mjs +6 -0
- package/package.json +39 -0
- package/public/bg-login.jpg +0 -0
- package/public/codigo_guardado.js +1 -0
- package/public/css/style.css +751 -0
- package/public/dboard/logo.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/fonts/TimesNewerRoman-Bold.otf +0 -0
- package/public/fonts/TimesNewerRoman-BoldItalic.otf +0 -0
- package/public/fonts/TimesNewerRoman-Italic.otf +0 -0
- package/public/fonts/TimesNewerRoman-Regular.otf +0 -0
- package/public/header-pdf.jpg +0 -0
- package/public/home/bgHome.jpg +0 -0
- package/public/home/bgHome2.jpg +0 -0
- package/public/home/download.jpg +0 -0
- package/public/home/undraw_elements_re_25t9.svg +1 -0
- package/public/home/undraw_project_completed_re_jr7u.svg +1 -0
- package/public/home/undraw_shared_goals_re_jvqd.svg +1 -0
- package/public/home/undraw_spread_love_re_v3cl.svg +1 -0
- package/public/home/undraw_target_re_fi8j.svg +1 -0
- package/public/home/undraw_visionary_technology_re_jfp7.svg +1 -0
- package/public/logo.png +0 -0
- package/public/marca/logo.svg +1 -0
- package/src/components/PDF/components/DocumentoTemplate.tsx +140 -0
- package/src/components/PDF/components/PDFContent.tsx +192 -0
- package/src/components/PDF/core/Etiquetas.tsx +152 -0
- package/src/components/PDF/core/Grid.tsx +101 -0
- package/src/components/PDF/core/Img.tsx +22 -0
- package/src/components/PDF/core/LayoutPDF.tsx +186 -0
- package/src/components/PDF/core/Listas.tsx +10 -0
- package/src/components/PDF/core/MakePDF.tsx +50 -0
- package/src/components/PDF/core/PageElements.tsx +50 -0
- package/src/components/PDF/core/Position.tsx +33 -0
- package/src/components/PDF/core/Tablet.tsx +121 -0
- package/src/components/PDF/core/index.tsx +56 -0
- package/src/components/PDF/lib/pdfParser.ts +620 -0
- package/src/components/PDF/services/apiService.ts +17 -0
- package/src/components/PDF/templates/AllTemplate.tsx +134 -0
- package/src/components/PDF/templates/BusinessCardTemplate.tsx +139 -0
- package/src/components/PDF/templates/CertificateTemplate.tsx +31 -0
- package/src/components/PDF/templates/HeaderFooterTemplate.tsx +61 -0
- package/src/components/PDF/templates/InvoiceTemplate.tsx +53 -0
- package/src/components/PDF/templates/ProposalTemplate.tsx +246 -0
- package/src/components/PDF/templates/ReportTemplate.tsx +57 -0
- package/src/components/PDF/templates/ResumeTemplate.tsx +170 -0
- package/src/components/PDF/templates/TablasTemplate.tsx +307 -0
- package/src/components/PDF/templates/index.ts +9 -0
- package/src/components/PDF/view/ColorPicker.tsx +147 -0
- package/src/components/PDF/view/Header.tsx +102 -0
- package/src/components/PDF/view/HomePDF.tsx +177 -0
- package/src/components/PDF/view/SettingsPanel.tsx +703 -0
- package/src/pages/AllTemplate.tsx +53 -0
- package/src/pages/Documento2.tsx +45 -0
- package/src/pages/_app.tsx +6 -0
- package/src/pages/_document.tsx +13 -0
- package/src/pages/api/generatePDF.ts +74 -0
- package/src/pages/api/hello.ts +13 -0
- package/src/pages/api/readFile.ts +18 -0
- package/src/pages/api/readTemplateFile.ts +26 -0
- package/src/pages/api/save.ts +22 -0
- package/src/pages/api/saveFile.ts +20 -0
- package/src/pages/index.tsx +13 -0
- package/src/pages/template/[template].tsx +250 -0
- package/tsconfig.json +63 -0
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
// lib/pdfParser.ts
|
|
2
|
+
export interface ParsedNode {
|
|
3
|
+
type: string
|
|
4
|
+
content: (string | ParsedNode | any)[]
|
|
5
|
+
props?: Record<string, any>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const parseJSX = (jsx: string): ParsedNode[] => {
|
|
9
|
+
// Extrae el contexto del código antes del return (variables, etc.)
|
|
10
|
+
|
|
11
|
+
const extractCodeContext = (fullCode: string) => {
|
|
12
|
+
try {
|
|
13
|
+
// Creamos un objeto para almacenar variables
|
|
14
|
+
const context: Record<string, any> = {}
|
|
15
|
+
|
|
16
|
+
// Extraemos el código antes del return
|
|
17
|
+
const beforeReturn = fullCode.split("return")[0]
|
|
18
|
+
|
|
19
|
+
// Buscamos declaraciones de variables (const|let|var)
|
|
20
|
+
const varRegex = /(const|let|var)\s+(\w+)\s*=\s*([^;]+);?/g
|
|
21
|
+
let match
|
|
22
|
+
|
|
23
|
+
while ((match = varRegex.exec(beforeReturn)) !== null) {
|
|
24
|
+
const [_, declarationType, varName, varValue] = match
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// Evaluamos el valor de la variable y lo guardamos en el contexto
|
|
28
|
+
context[varName] = new Function(`return ${varValue}`)()
|
|
29
|
+
} catch (e) {
|
|
30
|
+
console.error(`Error evaluating variable ${varName}:`, e)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return context
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error("Error extracting code context:", error)
|
|
37
|
+
return {}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Obtenemos el contexto a partir del código completo
|
|
42
|
+
const codeContext = extractCodeContext(jsx)
|
|
43
|
+
|
|
44
|
+
// Helper function to access nested properties and array elements
|
|
45
|
+
const getNestedProperty = (obj: any, path: string) => {
|
|
46
|
+
try {
|
|
47
|
+
// Handle array indexing like data.departmentData[0].responsable
|
|
48
|
+
const arrayIndexRegex = /(\w+)\[(\d+)\]\.(\w+)/
|
|
49
|
+
const arrayMatch = path.match(arrayIndexRegex)
|
|
50
|
+
|
|
51
|
+
if (arrayMatch) {
|
|
52
|
+
const [_, arrayName, indexStr, propName] = arrayMatch
|
|
53
|
+
const index = Number.parseInt(indexStr, 10)
|
|
54
|
+
|
|
55
|
+
// Handle nested arrays like data.departmentData
|
|
56
|
+
if (arrayName.includes(".")) {
|
|
57
|
+
const parts = arrayName.split(".")
|
|
58
|
+
let current = obj
|
|
59
|
+
|
|
60
|
+
for (const part of parts) {
|
|
61
|
+
if (current && typeof current === "object") {
|
|
62
|
+
current = current[part]
|
|
63
|
+
} else {
|
|
64
|
+
return undefined
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (Array.isArray(current) && current.length > index) {
|
|
69
|
+
return current[index][propName]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Handle direct arrays like departmentData
|
|
73
|
+
else if (obj[arrayName] && Array.isArray(obj[arrayName]) && obj[arrayName].length > index) {
|
|
74
|
+
return obj[arrayName][index][propName]
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return undefined
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Handle regular nested properties like data.departmentData
|
|
81
|
+
if (path.includes(".")) {
|
|
82
|
+
const parts = path.split(".")
|
|
83
|
+
let current = obj
|
|
84
|
+
|
|
85
|
+
for (const part of parts) {
|
|
86
|
+
if (current && typeof current === "object") {
|
|
87
|
+
current = current[part]
|
|
88
|
+
} else {
|
|
89
|
+
return undefined
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return current
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Handle simple properties
|
|
97
|
+
return obj[path]
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error(`Error accessing nested property: ${path}`, error)
|
|
100
|
+
return undefined
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Find all data arrays that might be used in map functions
|
|
105
|
+
const findDataArrays = () => {
|
|
106
|
+
const arrays: Record<string, any[]> = {}
|
|
107
|
+
|
|
108
|
+
// Look for arrays in the context
|
|
109
|
+
for (const [key, value] of Object.entries(codeContext)) {
|
|
110
|
+
if (Array.isArray(value)) {
|
|
111
|
+
arrays[key] = value
|
|
112
|
+
} else if (value && typeof value === "object") {
|
|
113
|
+
// Look for arrays in nested objects (like data.departmentData)
|
|
114
|
+
for (const [nestedKey, nestedValue] of Object.entries(value)) {
|
|
115
|
+
if (Array.isArray(nestedValue)) {
|
|
116
|
+
arrays[`${key}.${nestedKey}`] = nestedValue
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return arrays
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const dataArrays = findDataArrays()
|
|
126
|
+
|
|
127
|
+
// Process array indexing expressions like data.departmentData[0].responsable
|
|
128
|
+
const processArrayIndexing = (text: string) => {
|
|
129
|
+
try {
|
|
130
|
+
const arrayIndexRegex = /(\w+(?:\.\w+)*)\[(\d+)\]\.(\w+)/g
|
|
131
|
+
|
|
132
|
+
return text.replace(arrayIndexRegex, (match, arrayPath, indexStr, propName) => {
|
|
133
|
+
try {
|
|
134
|
+
const index = Number.parseInt(indexStr, 10)
|
|
135
|
+
|
|
136
|
+
// Get the array from the context
|
|
137
|
+
let array
|
|
138
|
+
if (arrayPath.includes(".")) {
|
|
139
|
+
// Handle nested properties like data.departmentData
|
|
140
|
+
array = getNestedProperty(codeContext, arrayPath)
|
|
141
|
+
} else {
|
|
142
|
+
array = codeContext[arrayPath]
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (Array.isArray(array) && array.length > index && array[index][propName] !== undefined) {
|
|
146
|
+
return JSON.stringify(array[index][propName])
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return match
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error(`Error processing array indexing: ${match}`, error)
|
|
152
|
+
return match
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error("Error in processArrayIndexing:", error)
|
|
157
|
+
return text
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Función para procesar expresiones utilizando el contexto extraído
|
|
162
|
+
const processExpressions = (text: string, localContext: Record<string, any> = {}) => {
|
|
163
|
+
try {
|
|
164
|
+
// First process array indexing expressions
|
|
165
|
+
let processedText = processArrayIndexing(text)
|
|
166
|
+
|
|
167
|
+
// Special handling for row references
|
|
168
|
+
if (processedText.includes("row.")) {
|
|
169
|
+
const rowRefs = processedText.match(/row\.(\w+)/g)
|
|
170
|
+
if (rowRefs) {
|
|
171
|
+
for (const rowRef of rowRefs) {
|
|
172
|
+
const prop = rowRef.split(".")[1]
|
|
173
|
+
|
|
174
|
+
if (localContext.row && localContext.row[prop] !== undefined) {
|
|
175
|
+
const value = JSON.stringify(localContext.row[prop])
|
|
176
|
+
processedText = processedText.replace(new RegExp(rowRef, "g"), value)
|
|
177
|
+
} else {
|
|
178
|
+
// Recorremos los data arrays y concatenamos los valores de todos los elementos
|
|
179
|
+
for (const array of Object.values(dataArrays)) {
|
|
180
|
+
if (array.length > 0 && array[0][prop] !== undefined) {
|
|
181
|
+
const values = array.map((item) => JSON.stringify(item[prop])).join(", ") // Puedes cambiar el delimitador según lo necesites
|
|
182
|
+
processedText = processedText.replace(new RegExp(rowRef, "g"), values)
|
|
183
|
+
break
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Busca expresiones del tipo {data.hola}, {variable}, etc.
|
|
192
|
+
return processedText.replace(/\{([^}]+)\}/g, (match, expression) => {
|
|
193
|
+
console.log(match, expression)
|
|
194
|
+
try {
|
|
195
|
+
// First check if the expression contains array indexing
|
|
196
|
+
if (expression.match(/\w+(?:\.\w+)*\[\d+\]\.\w+/)) {
|
|
197
|
+
try {
|
|
198
|
+
// Process the array indexing
|
|
199
|
+
const processedExpr = processArrayIndexing(expression)
|
|
200
|
+
// Try to evaluate the processed expression
|
|
201
|
+
return new Function(`return ${processedExpr}`)()
|
|
202
|
+
} catch (e) {
|
|
203
|
+
console.error(`Error evaluating array indexing expression: ${expression}`, e)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Handle row references in expressions
|
|
208
|
+
if (expression.includes("row.")) {
|
|
209
|
+
const rowRefs = expression.match(/row\.(\w+)/g)
|
|
210
|
+
if (rowRefs) {
|
|
211
|
+
let processedExpr = expression
|
|
212
|
+
|
|
213
|
+
for (const rowRef of rowRefs) {
|
|
214
|
+
const prop = rowRef.split(".")[1]
|
|
215
|
+
|
|
216
|
+
// If we have a row in the local context, use it
|
|
217
|
+
if (localContext.row && localContext.row[prop] !== undefined) {
|
|
218
|
+
processedExpr = processedExpr.replace(new RegExp(rowRef, "g"), JSON.stringify(localContext.row[prop]))
|
|
219
|
+
}
|
|
220
|
+
// Otherwise, try to find it in the data arrays
|
|
221
|
+
else {
|
|
222
|
+
// Look through all data arrays to find a matching property
|
|
223
|
+
for (const array of Object.values(dataArrays)) {
|
|
224
|
+
if (array.length > 0 && array[0][prop] !== undefined) {
|
|
225
|
+
// Use the first item's property as a fallback
|
|
226
|
+
processedExpr = processedExpr.replace(new RegExp(rowRef, "g"), JSON.stringify(array[0][prop]))
|
|
227
|
+
break
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Try to evaluate the processed expression
|
|
234
|
+
try {
|
|
235
|
+
return new Function(`return ${processedExpr}`)()
|
|
236
|
+
} catch (e) {
|
|
237
|
+
console.error(`Error evaluating processed row expression: ${processedExpr}`, e)
|
|
238
|
+
return match
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Maneja valores booleanos y numéricos directamente
|
|
244
|
+
if (expression === "true") return true
|
|
245
|
+
if (expression === "false") return false
|
|
246
|
+
if (!isNaN(Number(expression))) return Number(expression)
|
|
247
|
+
|
|
248
|
+
// Combine global context with local context
|
|
249
|
+
const combinedContext = { ...codeContext, ...localContext }
|
|
250
|
+
const keys = Object.keys(combinedContext)
|
|
251
|
+
const values = Object.values(combinedContext)
|
|
252
|
+
const evaluator = new Function(...keys, `return ${expression}`)
|
|
253
|
+
|
|
254
|
+
return evaluator(...values)
|
|
255
|
+
} catch (e) {
|
|
256
|
+
console.error(`Error evaluating expression ${expression}:`, e)
|
|
257
|
+
return match // Si falla, se retorna la expresión sin evaluar
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
} catch (error) {
|
|
261
|
+
console.error("Error processing expressions:", error)
|
|
262
|
+
return text
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Function to detect and process map expressions in JSX
|
|
267
|
+
const detectAndProcessMapExpressions = (jsxContent: string): string => {
|
|
268
|
+
// Expresión regular mejorada para capturar correctamente las expresiones map
|
|
269
|
+
// Esta versión es más robusta para manejar diferentes formatos de código
|
|
270
|
+
const mapRegex = /\{([\s\S]*?)\.map$$\(([\s\S]*?)(?:,\s*([\s\S]*?))?$$\s*=>\s*([\s\S]*?)\)\}/g
|
|
271
|
+
|
|
272
|
+
return jsxContent.replace(mapRegex, (match, arrayExpr, itemParam, indexParam, mapBody) => {
|
|
273
|
+
try {
|
|
274
|
+
// Limpiar espacios en blanco
|
|
275
|
+
const arrayName = arrayExpr.trim()
|
|
276
|
+
itemParam = itemParam.trim()
|
|
277
|
+
|
|
278
|
+
console.log("Array name:", arrayName)
|
|
279
|
+
console.log("Item param:", itemParam)
|
|
280
|
+
console.log("Map body:", mapBody)
|
|
281
|
+
|
|
282
|
+
// Obtener el array del contexto
|
|
283
|
+
let array
|
|
284
|
+
if (arrayName.includes(".")) {
|
|
285
|
+
// Manejar propiedades anidadas como data.departmentData
|
|
286
|
+
array = getNestedProperty(codeContext, arrayName)
|
|
287
|
+
} else {
|
|
288
|
+
array = codeContext[arrayName]
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (!Array.isArray(array)) {
|
|
292
|
+
console.error(`Array ${arrayName} not found in context or not an array`)
|
|
293
|
+
return match
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
console.log("Array data:", array)
|
|
297
|
+
|
|
298
|
+
// Procesar cada elemento del array y generar JSX
|
|
299
|
+
let result = ""
|
|
300
|
+
array.forEach((item, index) => {
|
|
301
|
+
// Crear un contexto local con el elemento actual
|
|
302
|
+
const localContext = {
|
|
303
|
+
[itemParam]: item,
|
|
304
|
+
row: item, // Agregar row como alias para el elemento actual
|
|
305
|
+
index: index,
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Clonar el cuerpo del map para esta iteración
|
|
309
|
+
let processedBody = mapBody
|
|
310
|
+
|
|
311
|
+
// Reemplazar todas las ocurrencias de itemParam con las propiedades reales del elemento
|
|
312
|
+
const itemRegex = new RegExp(`${itemParam}\\.([\\w]+)`, "g")
|
|
313
|
+
processedBody = processedBody.replace(itemRegex, (_, prop) => {
|
|
314
|
+
return JSON.stringify(item[prop])
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
// Reemplazar todas las ocurrencias de row con las propiedades reales del elemento
|
|
318
|
+
const rowRegex = /row\.([\w]+)/g
|
|
319
|
+
processedBody = processedBody.replace(rowRegex, (_, prop) => {
|
|
320
|
+
return JSON.stringify(item[prop])
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
// Reemplazar referencias al índice si es necesario
|
|
324
|
+
if (indexParam) {
|
|
325
|
+
const indexRegex = new RegExp(`${indexParam}`, "g")
|
|
326
|
+
processedBody = processedBody.replace(indexRegex, index.toString())
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Agregar una key única a cada elemento si no tiene una
|
|
330
|
+
if (!processedBody.includes("key={") && processedBody.trim().startsWith("<")) {
|
|
331
|
+
const tagEnd = processedBody.indexOf(">")
|
|
332
|
+
if (tagEnd > 0) {
|
|
333
|
+
processedBody = processedBody.substring(0, tagEnd) + ` key={${index}}` + processedBody.substring(tagEnd)
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
result += processedBody
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
return result
|
|
341
|
+
} catch (error) {
|
|
342
|
+
console.error("Error processing map expression:", error)
|
|
343
|
+
return match
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Pre-process the JSX to handle map expressions
|
|
349
|
+
const processedJSX = detectAndProcessMapExpressions(jsx)
|
|
350
|
+
|
|
351
|
+
// Función auxiliar para manejar tokens de texto o expresión
|
|
352
|
+
const handleTextToken = (token: string, parent: ParsedNode) => {
|
|
353
|
+
const trimmedToken = token.trim()
|
|
354
|
+
|
|
355
|
+
// Si el token es una expresión completa, se evalúa directamente
|
|
356
|
+
if (trimmedToken.startsWith("{") && trimmedToken.endsWith("}")) {
|
|
357
|
+
const expressionContent = trimmedToken.slice(1, -1)
|
|
358
|
+
|
|
359
|
+
// Handle array indexing expressions
|
|
360
|
+
if (expressionContent.match(/\w+(?:\.\w+)*\[\d+\]\.\w+/)) {
|
|
361
|
+
try {
|
|
362
|
+
// Process the array indexing
|
|
363
|
+
const processedExpr = processArrayIndexing(expressionContent)
|
|
364
|
+
// Try to evaluate the processed expression
|
|
365
|
+
const result = new Function(`return ${processedExpr}`)()
|
|
366
|
+
parent.content.push(result)
|
|
367
|
+
return
|
|
368
|
+
} catch (e) {
|
|
369
|
+
console.error(`Error evaluating array indexing expression: ${expressionContent}`, e)
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Handle row references in the expression
|
|
374
|
+
if (expressionContent.includes("row.")) {
|
|
375
|
+
try {
|
|
376
|
+
// Process the expression with row references
|
|
377
|
+
const processedExpr = processExpressions(`{${expressionContent}}`)
|
|
378
|
+
// If it's a string (which means it was processed), remove the quotes
|
|
379
|
+
if (typeof processedExpr === "string" && processedExpr.startsWith('"') && processedExpr.endsWith('"')) {
|
|
380
|
+
parent.content.push(processedExpr.slice(1, -1))
|
|
381
|
+
} else {
|
|
382
|
+
parent.content.push(processedExpr)
|
|
383
|
+
}
|
|
384
|
+
return
|
|
385
|
+
} catch (e) {
|
|
386
|
+
console.error(`Error processing row expression: ${expressionContent}`, e)
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Para expresiones normales (no mapeo)
|
|
391
|
+
try {
|
|
392
|
+
const keys = Object.keys(codeContext)
|
|
393
|
+
const values = Object.values(codeContext)
|
|
394
|
+
const evaluator = new Function(...keys, `return ${expressionContent}`)
|
|
395
|
+
const result = evaluator(...values)
|
|
396
|
+
|
|
397
|
+
if (Array.isArray(result)) {
|
|
398
|
+
result.forEach((item) => {
|
|
399
|
+
// Si el item es un objeto con 'type', asumimos que es un nodo
|
|
400
|
+
if (item && typeof item === "object" && "type" in item) {
|
|
401
|
+
parent.content.push(item)
|
|
402
|
+
} else {
|
|
403
|
+
// De lo contrario, lo agregamos como texto o lo dejamos como esté
|
|
404
|
+
parent.content.push(item)
|
|
405
|
+
}
|
|
406
|
+
})
|
|
407
|
+
} else {
|
|
408
|
+
parent.content.push(result)
|
|
409
|
+
}
|
|
410
|
+
} catch (e) {
|
|
411
|
+
console.error(`Error evaluating expression ${expressionContent}:`, e)
|
|
412
|
+
}
|
|
413
|
+
} else {
|
|
414
|
+
// Si es texto normal (que pueda contener expresiones inline) se procesa
|
|
415
|
+
const processedText = processExpressions(token)
|
|
416
|
+
const trimmedText = processedText.trim()
|
|
417
|
+
if (trimmedText) {
|
|
418
|
+
parent.content.push(trimmedText)
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Extraemos la parte JSX (entre <LayoutPDF> y </LayoutPDF>)
|
|
424
|
+
const jsxMatch = processedJSX.match(/<LayoutPDF[\s\S]*?>([\s\S]*?)<\/LayoutPDF>/)
|
|
425
|
+
const jsxContent = jsxMatch ? jsxMatch[1] : processedJSX
|
|
426
|
+
|
|
427
|
+
const tokens = jsxContent.match(/<[^>]+>|[^<]+/g) || []
|
|
428
|
+
const nodes: ParsedNode[] = []
|
|
429
|
+
const stack: ParsedNode[] = []
|
|
430
|
+
|
|
431
|
+
// Procesamos el componente LayoutPDF por separado para extraer sus props
|
|
432
|
+
const layoutPDFMatch = processedJSX.match(/<LayoutPDF([^>]*)>/)
|
|
433
|
+
if (layoutPDFMatch) {
|
|
434
|
+
const layoutProps: Record<string, any> = {}
|
|
435
|
+
const propsString = layoutPDFMatch[1]
|
|
436
|
+
|
|
437
|
+
// Extraemos props regulares (valores en cadena)
|
|
438
|
+
const regularProps = Array.from(propsString.matchAll(/(\w+)="([^"]*)"/g))
|
|
439
|
+
regularProps.forEach(([_, key, value]) => {
|
|
440
|
+
layoutProps[key] = value
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
// Extraemos props booleanas
|
|
444
|
+
const booleanProps = Array.from(propsString.matchAll(/(\w+)=\{(true|false)\}/g))
|
|
445
|
+
booleanProps.forEach(([_, key, value]) => {
|
|
446
|
+
layoutProps[key] = value === "true"
|
|
447
|
+
})
|
|
448
|
+
|
|
449
|
+
// Extraemos props numéricas
|
|
450
|
+
const numericProps = Array.from(propsString.matchAll(/(\w+)=\{(\d+(?:\.\d+)?)\}/g))
|
|
451
|
+
numericProps.forEach(([_, key, value]) => {
|
|
452
|
+
layoutProps[key] = Number(value)
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
// Creamos el nodo LayoutPDF
|
|
456
|
+
const layoutNode: ParsedNode = {
|
|
457
|
+
type: "LayoutPDF",
|
|
458
|
+
content: [],
|
|
459
|
+
props: layoutProps,
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Procesamos cada token dentro de LayoutPDF
|
|
463
|
+
tokens.forEach((token) => {
|
|
464
|
+
if (token.startsWith("</")) {
|
|
465
|
+
// Etiqueta de cierre
|
|
466
|
+
if (stack.length > 0) {
|
|
467
|
+
const node = stack.pop()!
|
|
468
|
+
if (stack.length === 0) {
|
|
469
|
+
layoutNode.content.push(node)
|
|
470
|
+
} else {
|
|
471
|
+
stack[stack.length - 1].content.push(node)
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
} else if (token.startsWith("<")) {
|
|
475
|
+
// Etiqueta de apertura
|
|
476
|
+
const tagMatch = token.match(/<(\w+)([^>]*)>/) || []
|
|
477
|
+
const tagName = tagMatch[1]
|
|
478
|
+
const propsString = tagMatch[2] || ""
|
|
479
|
+
const props: Record<string, any> = {}
|
|
480
|
+
|
|
481
|
+
// Extraemos atributos regulares
|
|
482
|
+
const regularProps = Array.from(propsString.matchAll(/(\w+)="([^"]*)"/g))
|
|
483
|
+
regularProps.forEach(([_, key, value]) => {
|
|
484
|
+
props[key] = processExpressions(value)
|
|
485
|
+
})
|
|
486
|
+
|
|
487
|
+
// Extraemos objetos de estilo
|
|
488
|
+
const styleMatch = propsString.match(/style=\{\{([^}]*)\}\}/)
|
|
489
|
+
if (styleMatch) {
|
|
490
|
+
try {
|
|
491
|
+
const styleString = `{${styleMatch[1]}}`
|
|
492
|
+
const styleObj = new Function(`return ${styleString}`)()
|
|
493
|
+
props.style = styleObj
|
|
494
|
+
} catch (error) {
|
|
495
|
+
console.error("Error parsing style object:", error)
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Extract key prop if it exists
|
|
500
|
+
const keyMatch = propsString.match(/key=\{([^}]*)\}/)
|
|
501
|
+
let keyValue = undefined
|
|
502
|
+
if (keyMatch) {
|
|
503
|
+
try {
|
|
504
|
+
const keyString = keyMatch[1]
|
|
505
|
+
keyValue = new Function(`return ${keyString}`)()
|
|
506
|
+
// Remove key from props as it will be handled separately
|
|
507
|
+
delete props.key
|
|
508
|
+
} catch (error) {
|
|
509
|
+
console.error("Error parsing key prop:", error)
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const node: ParsedNode = {
|
|
514
|
+
type: tagName,
|
|
515
|
+
content: [],
|
|
516
|
+
props,
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Add key as a separate property if it exists
|
|
520
|
+
if (keyValue !== undefined) {
|
|
521
|
+
// Ensure props exists before setting a property on it
|
|
522
|
+
if (!node.props) {
|
|
523
|
+
node.props = {}
|
|
524
|
+
}
|
|
525
|
+
node.props.key = keyValue
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
stack.push(node)
|
|
529
|
+
} else {
|
|
530
|
+
// Contenido de texto o expresión
|
|
531
|
+
if (stack.length > 0) {
|
|
532
|
+
handleTextToken(token, stack[stack.length - 1])
|
|
533
|
+
} else {
|
|
534
|
+
handleTextToken(token, layoutNode)
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
})
|
|
538
|
+
|
|
539
|
+
nodes.push(layoutNode)
|
|
540
|
+
return nodes
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Si no se encontró LayoutPDF, se procesan los tokens normalmente
|
|
544
|
+
tokens.forEach((token) => {
|
|
545
|
+
if (token.startsWith("</")) {
|
|
546
|
+
// Etiqueta de cierre
|
|
547
|
+
if (stack.length > 0) {
|
|
548
|
+
const node = stack.pop()!
|
|
549
|
+
if (stack.length === 0) {
|
|
550
|
+
nodes.push(node)
|
|
551
|
+
} else {
|
|
552
|
+
stack[stack.length - 1].content.push(node)
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
} else if (token.startsWith("<")) {
|
|
556
|
+
// Etiqueta de apertura
|
|
557
|
+
const tagMatch = token.match(/<(\w+)([^>]*)>/) || []
|
|
558
|
+
const tagName = tagMatch[1]
|
|
559
|
+
const propsString = tagMatch[2] || ""
|
|
560
|
+
const props: Record<string, any> = {}
|
|
561
|
+
|
|
562
|
+
// Procesamos atributos regulares
|
|
563
|
+
const regularProps = Array.from(propsString.matchAll(/(\w+)="([^"]*)"/g))
|
|
564
|
+
regularProps.forEach(([_, key, value]) => {
|
|
565
|
+
props[key] = processExpressions(value)
|
|
566
|
+
})
|
|
567
|
+
|
|
568
|
+
// Procesamos objetos de estilo
|
|
569
|
+
const styleMatch = propsString.match(/style=\{\{([^}]*)\}\}/)
|
|
570
|
+
if (styleMatch) {
|
|
571
|
+
try {
|
|
572
|
+
const styleString = `{${styleMatch[1]}}`
|
|
573
|
+
const styleObj = new Function(`return ${styleString}`)()
|
|
574
|
+
props.style = styleObj
|
|
575
|
+
} catch (error) {
|
|
576
|
+
console.error("Error parsing style object:", error)
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Extract key prop if it exists
|
|
581
|
+
const keyMatch = propsString.match(/key=\{([^}]*)\}/)
|
|
582
|
+
let keyValue = undefined
|
|
583
|
+
if (keyMatch) {
|
|
584
|
+
try {
|
|
585
|
+
const keyString = keyMatch[1]
|
|
586
|
+
keyValue = new Function(`return ${keyString}`)()
|
|
587
|
+
// Remove key from props as it will be handled separately
|
|
588
|
+
delete props.key
|
|
589
|
+
} catch (error) {
|
|
590
|
+
console.error("Error parsing key prop:", error)
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const node: ParsedNode = {
|
|
595
|
+
type: tagName,
|
|
596
|
+
content: [],
|
|
597
|
+
props,
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Add key as a separate property if it exists
|
|
601
|
+
if (keyValue !== undefined) {
|
|
602
|
+
// Ensure props exists before setting a property on it
|
|
603
|
+
if (!node.props) {
|
|
604
|
+
node.props = {}
|
|
605
|
+
}
|
|
606
|
+
node.props.key = keyValue
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
stack.push(node)
|
|
610
|
+
} else {
|
|
611
|
+
// Contenido de texto o expresión
|
|
612
|
+
if (stack.length > 0) {
|
|
613
|
+
handleTextToken(token, stack[stack.length - 1])
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
})
|
|
617
|
+
|
|
618
|
+
return nodes
|
|
619
|
+
}
|
|
620
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// services/apiService.ts
|
|
2
|
+
export const fetchTemplate = async (): Promise<{ content: string }> => {
|
|
3
|
+
const response = await fetch("/api/readFile");
|
|
4
|
+
const data = await response.json();
|
|
5
|
+
return data;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const saveDocumentAPI = async (filename: string, content: string): Promise<any> => {
|
|
9
|
+
const response = await fetch("/api/saveFile", {
|
|
10
|
+
method: "POST",
|
|
11
|
+
headers: { "Content-Type": "application/json" },
|
|
12
|
+
body: JSON.stringify({ filename, content }),
|
|
13
|
+
});
|
|
14
|
+
const result = await response.json();
|
|
15
|
+
return result;
|
|
16
|
+
};
|
|
17
|
+
|