@nuasite/cms-marker 0.0.71 → 0.0.73
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/dist/types/build-processor.d.ts.map +1 -1
- package/dist/types/dev-middleware.d.ts.map +1 -1
- package/dist/types/source-finder/ast-extractors.d.ts +35 -0
- package/dist/types/source-finder/ast-extractors.d.ts.map +1 -0
- package/dist/types/source-finder/ast-parser.d.ts +16 -0
- package/dist/types/source-finder/ast-parser.d.ts.map +1 -0
- package/dist/types/source-finder/cache.d.ts +18 -0
- package/dist/types/source-finder/cache.d.ts.map +1 -0
- package/dist/types/source-finder/collection-finder.d.ts +24 -0
- package/dist/types/source-finder/collection-finder.d.ts.map +1 -0
- package/dist/types/source-finder/cross-file-tracker.d.ts +29 -0
- package/dist/types/source-finder/cross-file-tracker.d.ts.map +1 -0
- package/dist/types/source-finder/element-finder.d.ts +42 -0
- package/dist/types/source-finder/element-finder.d.ts.map +1 -0
- package/dist/types/source-finder/image-finder.d.ts +16 -0
- package/dist/types/source-finder/image-finder.d.ts.map +1 -0
- package/dist/types/source-finder/index.d.ts +8 -0
- package/dist/types/source-finder/index.d.ts.map +1 -0
- package/dist/types/source-finder/search-index.d.ts +27 -0
- package/dist/types/source-finder/search-index.d.ts.map +1 -0
- package/dist/types/source-finder/snippet-utils.d.ts +49 -0
- package/dist/types/source-finder/snippet-utils.d.ts.map +1 -0
- package/dist/types/source-finder/source-lookup.d.ts +16 -0
- package/dist/types/source-finder/source-lookup.d.ts.map +1 -0
- package/dist/types/source-finder/types.d.ts +163 -0
- package/dist/types/source-finder/types.d.ts.map +1 -0
- package/dist/types/source-finder/variable-extraction.d.ts +37 -0
- package/dist/types/source-finder/variable-extraction.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/build-processor.ts +33 -1
- package/src/dev-middleware.ts +33 -1
- package/src/source-finder/ast-extractors.ts +175 -0
- package/src/source-finder/ast-parser.ts +127 -0
- package/src/source-finder/cache.ts +75 -0
- package/src/source-finder/collection-finder.ts +321 -0
- package/src/source-finder/cross-file-tracker.ts +337 -0
- package/src/source-finder/element-finder.ts +383 -0
- package/src/source-finder/image-finder.ts +189 -0
- package/src/source-finder/index.ts +26 -0
- package/src/source-finder/search-index.ts +418 -0
- package/src/source-finder/snippet-utils.ts +268 -0
- package/src/source-finder/source-lookup.ts +197 -0
- package/src/source-finder/types.ts +206 -0
- package/src/source-finder/variable-extraction.ts +355 -0
- package/dist/types/source-finder.d.ts +0 -117
- package/dist/types/source-finder.d.ts.map +0 -1
- package/src/source-finder.ts +0 -1784
package/package.json
CHANGED
package/src/build-processor.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AstroIntegrationLogger } from 'astro'
|
|
2
|
+
import { parse } from 'node-html-parser'
|
|
2
3
|
import fs from 'node:fs/promises'
|
|
3
4
|
import path from 'node:path'
|
|
4
5
|
import { fileURLToPath } from 'node:url'
|
|
@@ -165,11 +166,42 @@ async function processFile(
|
|
|
165
166
|
|
|
166
167
|
await Promise.all(entryLookups)
|
|
167
168
|
|
|
169
|
+
// Filter out entries without sourcePath - these can't be edited
|
|
170
|
+
const idsToRemove: string[] = []
|
|
171
|
+
for (const [id, entry] of Object.entries(result.entries)) {
|
|
172
|
+
// Keep collection wrapper entries even without sourcePath (they use contentPath)
|
|
173
|
+
if (entry.sourceType === 'collection') continue
|
|
174
|
+
// Remove entries that don't have a resolved sourcePath
|
|
175
|
+
if (!entry.sourcePath) {
|
|
176
|
+
idsToRemove.push(id)
|
|
177
|
+
delete result.entries[id]
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Remove CMS ID attributes from HTML for entries that were filtered out
|
|
182
|
+
let finalHtml = result.html
|
|
183
|
+
if (idsToRemove.length > 0) {
|
|
184
|
+
const root = parse(result.html, {
|
|
185
|
+
lowerCaseTagName: false,
|
|
186
|
+
comment: true,
|
|
187
|
+
})
|
|
188
|
+
for (const id of idsToRemove) {
|
|
189
|
+
const element = root.querySelector(`[${config.attributeName}="${id}"]`)
|
|
190
|
+
if (element) {
|
|
191
|
+
element.removeAttribute(config.attributeName)
|
|
192
|
+
// Also remove related CMS attributes
|
|
193
|
+
element.removeAttribute('data-cms-img')
|
|
194
|
+
element.removeAttribute('data-cms-markdown')
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
finalHtml = root.toString()
|
|
198
|
+
}
|
|
199
|
+
|
|
168
200
|
// Add to manifest writer (handles per-page manifest writes)
|
|
169
201
|
manifestWriter.addPage(pagePath, result.entries, result.components, collectionEntry)
|
|
170
202
|
|
|
171
203
|
// Write transformed HTML back
|
|
172
|
-
await fs.writeFile(filePath,
|
|
204
|
+
await fs.writeFile(filePath, finalHtml, 'utf-8')
|
|
173
205
|
|
|
174
206
|
return Object.keys(result.entries).length
|
|
175
207
|
}
|
package/src/dev-middleware.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parse } from 'node-html-parser'
|
|
1
2
|
import type { IncomingMessage, ServerResponse } from 'node:http'
|
|
2
3
|
import { processHtml } from './html-processor'
|
|
3
4
|
import type { ManifestWriter } from './manifest-writer'
|
|
@@ -237,8 +238,39 @@ async function processHtmlForDev(
|
|
|
237
238
|
}
|
|
238
239
|
}
|
|
239
240
|
|
|
241
|
+
// Filter out entries without sourcePath - these can't be edited
|
|
242
|
+
const idsToRemove: string[] = []
|
|
243
|
+
for (const [id, entry] of Object.entries(result.entries)) {
|
|
244
|
+
// Keep collection wrapper entries even without sourcePath (they use contentPath)
|
|
245
|
+
if (entry.sourceType === 'collection') continue
|
|
246
|
+
// Remove entries that don't have a resolved sourcePath
|
|
247
|
+
if (!entry.sourcePath) {
|
|
248
|
+
idsToRemove.push(id)
|
|
249
|
+
delete result.entries[id]
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Remove CMS ID attributes from HTML for entries that were filtered out
|
|
254
|
+
let finalHtml = result.html
|
|
255
|
+
if (idsToRemove.length > 0) {
|
|
256
|
+
const root = parse(result.html, {
|
|
257
|
+
lowerCaseTagName: false,
|
|
258
|
+
comment: true,
|
|
259
|
+
})
|
|
260
|
+
for (const id of idsToRemove) {
|
|
261
|
+
const element = root.querySelector(`[${config.attributeName}="${id}"]`)
|
|
262
|
+
if (element) {
|
|
263
|
+
element.removeAttribute(config.attributeName)
|
|
264
|
+
// Also remove related CMS attributes
|
|
265
|
+
element.removeAttribute('data-cms-img')
|
|
266
|
+
element.removeAttribute('data-cms-markdown')
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
finalHtml = root.toString()
|
|
270
|
+
}
|
|
271
|
+
|
|
240
272
|
return {
|
|
241
|
-
html:
|
|
273
|
+
html: finalHtml,
|
|
242
274
|
entries: result.entries,
|
|
243
275
|
components: result.components,
|
|
244
276
|
collection: collectionEntry,
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import type { BabelNode, LineTransformer, VariableDefinition } from './types'
|
|
2
|
+
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// String Value Extraction
|
|
5
|
+
// ============================================================================
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Extract string value from a Babel node (StringLiteral or simple TemplateLiteral)
|
|
9
|
+
*/
|
|
10
|
+
export function getStringValue(node: BabelNode): string | null {
|
|
11
|
+
if (node.type === 'StringLiteral') {
|
|
12
|
+
return node.value as string
|
|
13
|
+
}
|
|
14
|
+
if (node.type === 'TemplateLiteral') {
|
|
15
|
+
const quasis = node.quasis as Array<{ value: { cooked: string | null } }> | undefined
|
|
16
|
+
const expressions = node.expressions as unknown[] | undefined
|
|
17
|
+
if (quasis?.length === 1 && expressions?.length === 0) {
|
|
18
|
+
return quasis[0]?.value.cooked ?? null
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Object and Array Extraction
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Recursively extract properties from an object expression
|
|
30
|
+
* @param objNode - The ObjectExpression node
|
|
31
|
+
* @param parentPath - The full path to this object (e.g., 'config' or 'config.nav')
|
|
32
|
+
* @param definitions - Array to collect definitions into
|
|
33
|
+
* @param lineTransformer - Transforms Babel line numbers to file line numbers
|
|
34
|
+
*/
|
|
35
|
+
export function extractObjectProperties(
|
|
36
|
+
objNode: BabelNode,
|
|
37
|
+
parentPath: string,
|
|
38
|
+
definitions: VariableDefinition[],
|
|
39
|
+
lineTransformer: LineTransformer,
|
|
40
|
+
): void {
|
|
41
|
+
const properties = objNode.properties as BabelNode[] | undefined
|
|
42
|
+
for (const prop of properties ?? []) {
|
|
43
|
+
if (prop.type !== 'ObjectProperty') continue
|
|
44
|
+
const key = prop.key as BabelNode | undefined
|
|
45
|
+
const value = prop.value as BabelNode | undefined
|
|
46
|
+
if (!key || key.type !== 'Identifier' || !value) continue
|
|
47
|
+
|
|
48
|
+
const propName = key.name as string
|
|
49
|
+
const fullPath = `${parentPath}.${propName}`
|
|
50
|
+
const propLoc = prop.loc as { start: { line: number } } | undefined
|
|
51
|
+
const propLine = lineTransformer(propLoc?.start.line ?? 1)
|
|
52
|
+
|
|
53
|
+
const stringValue = getStringValue(value)
|
|
54
|
+
if (stringValue !== null) {
|
|
55
|
+
definitions.push({
|
|
56
|
+
name: propName,
|
|
57
|
+
value: stringValue,
|
|
58
|
+
line: propLine,
|
|
59
|
+
parentName: parentPath,
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Recurse for nested objects
|
|
64
|
+
if (value.type === 'ObjectExpression') {
|
|
65
|
+
extractObjectProperties(value, fullPath, definitions, lineTransformer)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Handle arrays within objects
|
|
69
|
+
if (value.type === 'ArrayExpression') {
|
|
70
|
+
extractArrayElements(value, fullPath, definitions, lineTransformer, propLine)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Extract elements from an array expression
|
|
77
|
+
* @param arrNode - The ArrayExpression node
|
|
78
|
+
* @param parentPath - The full path to this array (e.g., 'items' or 'config.items')
|
|
79
|
+
* @param definitions - Array to collect definitions into
|
|
80
|
+
* @param lineTransformer - Transforms Babel line numbers to file line numbers
|
|
81
|
+
* @param defaultLine - Fallback line if element has no location
|
|
82
|
+
*/
|
|
83
|
+
export function extractArrayElements(
|
|
84
|
+
arrNode: BabelNode,
|
|
85
|
+
parentPath: string,
|
|
86
|
+
definitions: VariableDefinition[],
|
|
87
|
+
lineTransformer: LineTransformer,
|
|
88
|
+
defaultLine: number,
|
|
89
|
+
): void {
|
|
90
|
+
const elements = arrNode.elements as BabelNode[] | undefined
|
|
91
|
+
for (let i = 0; i < (elements?.length ?? 0); i++) {
|
|
92
|
+
const elem = elements![i]
|
|
93
|
+
if (!elem) continue
|
|
94
|
+
|
|
95
|
+
const elemLoc = elem.loc as { start: { line: number } } | undefined
|
|
96
|
+
const elemLine = elemLoc ? lineTransformer(elemLoc.start.line) : defaultLine
|
|
97
|
+
const indexPath = `${parentPath}[${i}]`
|
|
98
|
+
|
|
99
|
+
// Handle string values in array
|
|
100
|
+
const elemValue = getStringValue(elem)
|
|
101
|
+
if (elemValue !== null) {
|
|
102
|
+
definitions.push({
|
|
103
|
+
name: String(i),
|
|
104
|
+
value: elemValue,
|
|
105
|
+
line: elemLine,
|
|
106
|
+
parentName: parentPath,
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Handle array of objects: [{ text: 'Home' }]
|
|
111
|
+
if (elem.type === 'ObjectExpression') {
|
|
112
|
+
const objProperties = elem.properties as BabelNode[] | undefined
|
|
113
|
+
for (const prop of objProperties ?? []) {
|
|
114
|
+
if (prop.type !== 'ObjectProperty') continue
|
|
115
|
+
const key = prop.key as BabelNode | undefined
|
|
116
|
+
const value = prop.value as BabelNode | undefined
|
|
117
|
+
if (!key || key.type !== 'Identifier' || !value) continue
|
|
118
|
+
|
|
119
|
+
const propName = key.name as string
|
|
120
|
+
const propLoc = prop.loc as { start: { line: number } } | undefined
|
|
121
|
+
const propLine = propLoc ? lineTransformer(propLoc.start.line) : elemLine
|
|
122
|
+
|
|
123
|
+
const stringValue = getStringValue(value)
|
|
124
|
+
if (stringValue !== null) {
|
|
125
|
+
definitions.push({
|
|
126
|
+
name: propName,
|
|
127
|
+
value: stringValue,
|
|
128
|
+
line: propLine,
|
|
129
|
+
parentName: indexPath,
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Recurse for nested objects within array elements
|
|
134
|
+
if (value.type === 'ObjectExpression') {
|
|
135
|
+
extractObjectProperties(value, `${indexPath}.${propName}`, definitions, lineTransformer)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ============================================================================
|
|
143
|
+
// Path Building Utilities
|
|
144
|
+
// ============================================================================
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Build the full path for a variable definition.
|
|
148
|
+
* For array indices (numeric names), uses bracket notation: items[0]
|
|
149
|
+
* For object properties, uses dot notation: config.nav.title
|
|
150
|
+
*/
|
|
151
|
+
export function buildDefinitionPath(def: VariableDefinition): string {
|
|
152
|
+
if (!def.parentName) {
|
|
153
|
+
return def.name
|
|
154
|
+
}
|
|
155
|
+
// Check if the name is a numeric index (for arrays)
|
|
156
|
+
if (/^\d+$/.test(def.name)) {
|
|
157
|
+
return `${def.parentName}[${def.name}]`
|
|
158
|
+
}
|
|
159
|
+
return `${def.parentName}.${def.name}`
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Parse an expression path and extract the full path for variable lookup.
|
|
164
|
+
* Handles patterns like: varName, obj.prop, items[0], config.nav.title, links[0].text
|
|
165
|
+
* @returns The full expression path or null if not a simple variable reference
|
|
166
|
+
*/
|
|
167
|
+
export function parseExpressionPath(exprText: string): string | null {
|
|
168
|
+
// Match patterns like: varName, obj.prop, items[0], config.nav.title, links[0].text
|
|
169
|
+
// Pattern breakdown: word characters, dots, and bracket notation with numbers
|
|
170
|
+
const match = exprText.match(/^\s*([\w]+(?:\.[\w]+|\[\d+\])*(?:\.[\w]+)?)\s*$/)
|
|
171
|
+
if (match) {
|
|
172
|
+
return match[1]!
|
|
173
|
+
}
|
|
174
|
+
return null
|
|
175
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { parse as parseAstro } from '@astrojs/compiler'
|
|
2
|
+
import type { Node as AstroNode } from '@astrojs/compiler/types'
|
|
3
|
+
import { parse as parseBabel } from '@babel/parser'
|
|
4
|
+
import fs from 'node:fs/promises'
|
|
5
|
+
|
|
6
|
+
import { getErrorCollector } from '../error-collector'
|
|
7
|
+
import { getParsedFileCache } from './cache'
|
|
8
|
+
import type { BabelFile, CachedParsedFile, ParsedAstroFile } from './types'
|
|
9
|
+
import { extractImports, extractPropAliases, extractVariableDefinitions } from './variable-extraction'
|
|
10
|
+
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Astro File Parsing
|
|
13
|
+
// ============================================================================
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parse an Astro file and return both template AST and frontmatter content
|
|
17
|
+
*/
|
|
18
|
+
export async function parseAstroFile(content: string): Promise<ParsedAstroFile> {
|
|
19
|
+
const result = await parseAstro(content, { position: true })
|
|
20
|
+
|
|
21
|
+
// Find frontmatter node
|
|
22
|
+
let frontmatterContent: string | null = null
|
|
23
|
+
let frontmatterStartLine = 0
|
|
24
|
+
|
|
25
|
+
for (const child of result.ast.children) {
|
|
26
|
+
if (child.type === 'frontmatter') {
|
|
27
|
+
frontmatterContent = child.value
|
|
28
|
+
frontmatterStartLine = child.position?.start.line ?? 1
|
|
29
|
+
break
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
ast: result.ast,
|
|
35
|
+
frontmatterContent,
|
|
36
|
+
frontmatterStartLine,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Parse frontmatter JavaScript/TypeScript with Babel
|
|
42
|
+
* @param content - The frontmatter content to parse
|
|
43
|
+
* @param filePath - Optional file path for error reporting
|
|
44
|
+
*/
|
|
45
|
+
export function parseFrontmatter(content: string, filePath?: string): BabelFile | null {
|
|
46
|
+
try {
|
|
47
|
+
return parseBabel(content, {
|
|
48
|
+
sourceType: 'module',
|
|
49
|
+
plugins: ['typescript'],
|
|
50
|
+
errorRecovery: true,
|
|
51
|
+
}) as unknown as BabelFile
|
|
52
|
+
} catch (error) {
|
|
53
|
+
// Record parse errors for aggregated reporting
|
|
54
|
+
if (filePath) {
|
|
55
|
+
getErrorCollector().addWarning(
|
|
56
|
+
`Frontmatter parse: ${filePath}`,
|
|
57
|
+
error instanceof Error ? error.message : String(error),
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// Cached File Access
|
|
66
|
+
// ============================================================================
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get a cached parsed file, parsing it if not cached
|
|
70
|
+
*/
|
|
71
|
+
export async function getCachedParsedFile(filePath: string): Promise<CachedParsedFile | null> {
|
|
72
|
+
const cache = getParsedFileCache()
|
|
73
|
+
const cached = cache.get(filePath)
|
|
74
|
+
if (cached) return cached
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const content = await fs.readFile(filePath, 'utf-8')
|
|
78
|
+
const lines = content.split('\n')
|
|
79
|
+
|
|
80
|
+
// Only parse .astro files with AST
|
|
81
|
+
if (!filePath.endsWith('.astro')) {
|
|
82
|
+
// For tsx/jsx, just cache content/lines for regex search
|
|
83
|
+
const entry: CachedParsedFile = {
|
|
84
|
+
content,
|
|
85
|
+
lines,
|
|
86
|
+
ast: { type: 'root', children: [] } as unknown as AstroNode,
|
|
87
|
+
frontmatterContent: null,
|
|
88
|
+
frontmatterStartLine: 0,
|
|
89
|
+
variableDefinitions: [],
|
|
90
|
+
propAliases: new Map(),
|
|
91
|
+
imports: [],
|
|
92
|
+
}
|
|
93
|
+
cache.set(filePath, entry)
|
|
94
|
+
return entry
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const { ast, frontmatterContent, frontmatterStartLine } = await parseAstroFile(content)
|
|
98
|
+
|
|
99
|
+
let variableDefinitions: CachedParsedFile['variableDefinitions'] = []
|
|
100
|
+
let propAliases: Map<string, string> = new Map()
|
|
101
|
+
let imports: CachedParsedFile['imports'] = []
|
|
102
|
+
if (frontmatterContent) {
|
|
103
|
+
const frontmatterAst = parseFrontmatter(frontmatterContent, filePath)
|
|
104
|
+
if (frontmatterAst) {
|
|
105
|
+
variableDefinitions = extractVariableDefinitions(frontmatterAst, frontmatterStartLine)
|
|
106
|
+
propAliases = extractPropAliases(frontmatterAst)
|
|
107
|
+
imports = extractImports(frontmatterAst)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const entry: CachedParsedFile = {
|
|
112
|
+
content,
|
|
113
|
+
lines,
|
|
114
|
+
ast,
|
|
115
|
+
frontmatterContent,
|
|
116
|
+
frontmatterStartLine,
|
|
117
|
+
variableDefinitions,
|
|
118
|
+
propAliases,
|
|
119
|
+
imports,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
cache.set(filePath, entry)
|
|
123
|
+
return entry
|
|
124
|
+
} catch {
|
|
125
|
+
return null
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { CachedParsedFile, ImageIndexEntry, SearchIndexEntry } from './types'
|
|
2
|
+
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// File Parsing Cache - Avoid re-parsing the same files
|
|
5
|
+
// ============================================================================
|
|
6
|
+
|
|
7
|
+
/** Cache for parsed Astro files - cleared between builds */
|
|
8
|
+
const parsedFileCache = new Map<string, CachedParsedFile>()
|
|
9
|
+
|
|
10
|
+
/** Cache for directory listings - cleared between builds */
|
|
11
|
+
const directoryCache = new Map<string, string[]>()
|
|
12
|
+
|
|
13
|
+
/** Cache for markdown file contents - cleared between builds */
|
|
14
|
+
const markdownFileCache = new Map<string, { content: string; lines: string[] }>()
|
|
15
|
+
|
|
16
|
+
/** Search indexes built once per build */
|
|
17
|
+
let textSearchIndex: SearchIndexEntry[] = []
|
|
18
|
+
let imageSearchIndex: ImageIndexEntry[] = []
|
|
19
|
+
let searchIndexInitialized = false
|
|
20
|
+
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// Cache Access Functions
|
|
23
|
+
// ============================================================================
|
|
24
|
+
|
|
25
|
+
export function getParsedFileCache(): Map<string, CachedParsedFile> {
|
|
26
|
+
return parsedFileCache
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getDirectoryCache(): Map<string, string[]> {
|
|
30
|
+
return directoryCache
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function getMarkdownFileCache(): Map<string, { content: string; lines: string[] }> {
|
|
34
|
+
return markdownFileCache
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getTextSearchIndex(): SearchIndexEntry[] {
|
|
38
|
+
return textSearchIndex
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getImageSearchIndex(): ImageIndexEntry[] {
|
|
42
|
+
return imageSearchIndex
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function isSearchIndexInitialized(): boolean {
|
|
46
|
+
return searchIndexInitialized
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function setSearchIndexInitialized(value: boolean): void {
|
|
50
|
+
searchIndexInitialized = value
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function addToTextSearchIndex(entry: SearchIndexEntry): void {
|
|
54
|
+
textSearchIndex.push(entry)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function addToImageSearchIndex(entry: ImageIndexEntry): void {
|
|
58
|
+
imageSearchIndex.push(entry)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// Cache Clear Function
|
|
63
|
+
// ============================================================================
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Clear all caches - call at start of each build
|
|
67
|
+
*/
|
|
68
|
+
export function clearSourceFinderCache(): void {
|
|
69
|
+
parsedFileCache.clear()
|
|
70
|
+
directoryCache.clear()
|
|
71
|
+
markdownFileCache.clear()
|
|
72
|
+
textSearchIndex = []
|
|
73
|
+
imageSearchIndex = []
|
|
74
|
+
searchIndexInitialized = false
|
|
75
|
+
}
|