@nuasite/cms 0.1.0
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 +237 -0
- package/dist/src/build-processor.d.ts +20 -0
- package/dist/src/build-processor.d.ts.map +1 -0
- package/dist/src/collection-scanner.d.ts +6 -0
- package/dist/src/collection-scanner.d.ts.map +1 -0
- package/dist/src/component-registry.d.ts +63 -0
- package/dist/src/component-registry.d.ts.map +1 -0
- package/dist/src/config.d.ts +24 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/dev-middleware.d.ts +20 -0
- package/dist/src/dev-middleware.d.ts.map +1 -0
- package/dist/src/editor/ai.d.ts +60 -0
- package/dist/src/editor/ai.d.ts.map +1 -0
- package/dist/src/editor/api.d.ts +140 -0
- package/dist/src/editor/api.d.ts.map +1 -0
- package/dist/src/editor/color-utils.d.ts +106 -0
- package/dist/src/editor/color-utils.d.ts.map +1 -0
- package/dist/src/editor/components/ai-chat.d.ts +11 -0
- package/dist/src/editor/components/ai-chat.d.ts.map +1 -0
- package/dist/src/editor/components/ai-tooltip.d.ts +12 -0
- package/dist/src/editor/components/ai-tooltip.d.ts.map +1 -0
- package/dist/src/editor/components/attribute-editor.d.ts +5 -0
- package/dist/src/editor/components/attribute-editor.d.ts.map +1 -0
- package/dist/src/editor/components/block-editor.d.ts +12 -0
- package/dist/src/editor/components/block-editor.d.ts.map +1 -0
- package/dist/src/editor/components/collections-browser.d.ts +2 -0
- package/dist/src/editor/components/collections-browser.d.ts.map +1 -0
- package/dist/src/editor/components/color-toolbar.d.ts +12 -0
- package/dist/src/editor/components/color-toolbar.d.ts.map +1 -0
- package/dist/src/editor/components/confirm-dialog.d.ts +2 -0
- package/dist/src/editor/components/confirm-dialog.d.ts.map +1 -0
- package/dist/src/editor/components/create-page-modal.d.ts +2 -0
- package/dist/src/editor/components/create-page-modal.d.ts.map +1 -0
- package/dist/src/editor/components/editable-highlights.d.ts +9 -0
- package/dist/src/editor/components/editable-highlights.d.ts.map +1 -0
- package/dist/src/editor/components/error-boundary.d.ts +32 -0
- package/dist/src/editor/components/error-boundary.d.ts.map +1 -0
- package/dist/src/editor/components/fields.d.ts +75 -0
- package/dist/src/editor/components/fields.d.ts.map +1 -0
- package/dist/src/editor/components/frontmatter-fields.d.ts +29 -0
- package/dist/src/editor/components/frontmatter-fields.d.ts.map +1 -0
- package/dist/src/editor/components/highlight-overlay.d.ts +64 -0
- package/dist/src/editor/components/highlight-overlay.d.ts.map +1 -0
- package/dist/src/editor/components/image-overlay.d.ts +12 -0
- package/dist/src/editor/components/image-overlay.d.ts.map +1 -0
- package/dist/src/editor/components/markdown-editor-overlay.d.ts +6 -0
- package/dist/src/editor/components/markdown-editor-overlay.d.ts.map +1 -0
- package/dist/src/editor/components/markdown-inline-editor.d.ts +10 -0
- package/dist/src/editor/components/markdown-inline-editor.d.ts.map +1 -0
- package/dist/src/editor/components/media-library.d.ts +2 -0
- package/dist/src/editor/components/media-library.d.ts.map +1 -0
- package/dist/src/editor/components/outline.d.ts +21 -0
- package/dist/src/editor/components/outline.d.ts.map +1 -0
- package/dist/src/editor/components/redirect-countdown.d.ts +2 -0
- package/dist/src/editor/components/redirect-countdown.d.ts.map +1 -0
- package/dist/src/editor/components/seo-editor.d.ts +2 -0
- package/dist/src/editor/components/seo-editor.d.ts.map +1 -0
- package/dist/src/editor/components/text-style-toolbar.d.ts +8 -0
- package/dist/src/editor/components/text-style-toolbar.d.ts.map +1 -0
- package/dist/src/editor/components/toast/toast-container.d.ts +7 -0
- package/dist/src/editor/components/toast/toast-container.d.ts.map +1 -0
- package/dist/src/editor/components/toast/toast.d.ts +7 -0
- package/dist/src/editor/components/toast/toast.d.ts.map +1 -0
- package/dist/src/editor/components/toast/types.d.ts +7 -0
- package/dist/src/editor/components/toast/types.d.ts.map +1 -0
- package/dist/src/editor/components/toolbar.d.ts +21 -0
- package/dist/src/editor/components/toolbar.d.ts.map +1 -0
- package/dist/src/editor/config.d.ts +4 -0
- package/dist/src/editor/config.d.ts.map +1 -0
- package/dist/src/editor/constants.d.ts +101 -0
- package/dist/src/editor/constants.d.ts.map +1 -0
- package/dist/src/editor/context.d.ts +14 -0
- package/dist/src/editor/context.d.ts.map +1 -0
- package/dist/src/editor/dom.d.ts +77 -0
- package/dist/src/editor/dom.d.ts.map +1 -0
- package/dist/src/editor/editor.d.ts +64 -0
- package/dist/src/editor/editor.d.ts.map +1 -0
- package/dist/src/editor/history.d.ts +20 -0
- package/dist/src/editor/history.d.ts.map +1 -0
- package/dist/src/editor/hooks/index.d.ts +14 -0
- package/dist/src/editor/hooks/index.d.ts.map +1 -0
- package/dist/src/editor/hooks/useAIHandlers.d.ts +22 -0
- package/dist/src/editor/hooks/useAIHandlers.d.ts.map +1 -0
- package/dist/src/editor/hooks/useBlockEditorHandlers.d.ts +18 -0
- package/dist/src/editor/hooks/useBlockEditorHandlers.d.ts.map +1 -0
- package/dist/src/editor/hooks/useElementDetection.d.ts +26 -0
- package/dist/src/editor/hooks/useElementDetection.d.ts.map +1 -0
- package/dist/src/editor/hooks/useImageHoverDetection.d.ts +12 -0
- package/dist/src/editor/hooks/useImageHoverDetection.d.ts.map +1 -0
- package/dist/src/editor/hooks/useTextSelection.d.ts +23 -0
- package/dist/src/editor/hooks/useTextSelection.d.ts.map +1 -0
- package/dist/src/editor/hooks/useTooltipState.d.ts +19 -0
- package/dist/src/editor/hooks/useTooltipState.d.ts.map +1 -0
- package/dist/src/editor/hooks/utils.d.ts +32 -0
- package/dist/src/editor/hooks/utils.d.ts.map +1 -0
- package/dist/src/editor/index.d.ts +12 -0
- package/dist/src/editor/index.d.ts.map +1 -0
- package/dist/src/editor/lib/cn.d.ts +3 -0
- package/dist/src/editor/lib/cn.d.ts.map +1 -0
- package/dist/src/editor/manifest.d.ts +19 -0
- package/dist/src/editor/manifest.d.ts.map +1 -0
- package/dist/src/editor/markdown-api.d.ts +36 -0
- package/dist/src/editor/markdown-api.d.ts.map +1 -0
- package/dist/src/editor/signals.d.ts +242 -0
- package/dist/src/editor/signals.d.ts.map +1 -0
- package/dist/src/editor/storage.d.ts +27 -0
- package/dist/src/editor/storage.d.ts.map +1 -0
- package/dist/src/editor/text-styling.d.ts +350 -0
- package/dist/src/editor/text-styling.d.ts.map +1 -0
- package/dist/src/editor/themes.d.ts +38 -0
- package/dist/src/editor/themes.d.ts.map +1 -0
- package/dist/src/editor/types.d.ts +454 -0
- package/dist/src/editor/types.d.ts.map +1 -0
- package/dist/src/error-collector.d.ts +56 -0
- package/dist/src/error-collector.d.ts.map +1 -0
- package/dist/src/handlers/component-ops.d.ts +34 -0
- package/dist/src/handlers/component-ops.d.ts.map +1 -0
- package/dist/src/handlers/markdown-ops.d.ts +41 -0
- package/dist/src/handlers/markdown-ops.d.ts.map +1 -0
- package/dist/src/handlers/request-utils.d.ts +20 -0
- package/dist/src/handlers/request-utils.d.ts.map +1 -0
- package/dist/src/handlers/source-writer.d.ts +51 -0
- package/dist/src/handlers/source-writer.d.ts.map +1 -0
- package/dist/src/html-processor.d.ts +63 -0
- package/dist/src/html-processor.d.ts.map +1 -0
- package/dist/src/index.d.ts +41 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/manifest-writer.d.ts +111 -0
- package/dist/src/manifest-writer.d.ts.map +1 -0
- package/dist/src/media/contember.d.ts +15 -0
- package/dist/src/media/contember.d.ts.map +1 -0
- package/dist/src/media/local.d.ts +9 -0
- package/dist/src/media/local.d.ts.map +1 -0
- package/dist/src/media/s3.d.ts +12 -0
- package/dist/src/media/s3.d.ts.map +1 -0
- package/dist/src/media/types.d.ts +40 -0
- package/dist/src/media/types.d.ts.map +1 -0
- package/dist/src/preview-generator.d.ts +19 -0
- package/dist/src/preview-generator.d.ts.map +1 -0
- package/dist/src/seo-processor.d.ts +23 -0
- package/dist/src/seo-processor.d.ts.map +1 -0
- package/dist/src/source-finder/ast-extractors.d.ts +35 -0
- package/dist/src/source-finder/ast-extractors.d.ts.map +1 -0
- package/dist/src/source-finder/ast-parser.d.ts +16 -0
- package/dist/src/source-finder/ast-parser.d.ts.map +1 -0
- package/dist/src/source-finder/cache.d.ts +18 -0
- package/dist/src/source-finder/cache.d.ts.map +1 -0
- package/dist/src/source-finder/collection-finder.d.ts +29 -0
- package/dist/src/source-finder/collection-finder.d.ts.map +1 -0
- package/dist/src/source-finder/cross-file-tracker.d.ts +39 -0
- package/dist/src/source-finder/cross-file-tracker.d.ts.map +1 -0
- package/dist/src/source-finder/element-finder.d.ts +42 -0
- package/dist/src/source-finder/element-finder.d.ts.map +1 -0
- package/dist/src/source-finder/image-finder.d.ts +24 -0
- package/dist/src/source-finder/image-finder.d.ts.map +1 -0
- package/dist/src/source-finder/index.d.ts +9 -0
- package/dist/src/source-finder/index.d.ts.map +1 -0
- package/dist/src/source-finder/search-index.d.ts +27 -0
- package/dist/src/source-finder/search-index.d.ts.map +1 -0
- package/dist/src/source-finder/snippet-utils.d.ts +90 -0
- package/dist/src/source-finder/snippet-utils.d.ts.map +1 -0
- package/dist/src/source-finder/source-lookup.d.ts +16 -0
- package/dist/src/source-finder/source-lookup.d.ts.map +1 -0
- package/dist/src/source-finder/types.d.ts +167 -0
- package/dist/src/source-finder/types.d.ts.map +1 -0
- package/dist/src/source-finder/variable-extraction.d.ts +37 -0
- package/dist/src/source-finder/variable-extraction.d.ts.map +1 -0
- package/dist/src/tailwind-colors.d.ts +54 -0
- package/dist/src/tailwind-colors.d.ts.map +1 -0
- package/dist/src/tsconfig.tsbuildinfo +1 -0
- package/dist/src/types.d.ts +367 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/utils.d.ts +61 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/vite-plugin.d.ts +14 -0
- package/dist/src/vite-plugin.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +80 -0
- package/src/build-processor.ts +784 -0
- package/src/collection-scanner.ts +304 -0
- package/src/component-registry.ts +393 -0
- package/src/config.ts +74 -0
- package/src/dev-middleware.ts +525 -0
- package/src/dist/src/tsconfig.tsbuildinfo +1 -0
- package/src/editor/ai.ts +185 -0
- package/src/editor/api.ts +513 -0
- package/src/editor/color-utils.ts +556 -0
- package/src/editor/components/ai-chat.tsx +632 -0
- package/src/editor/components/ai-tooltip.tsx +179 -0
- package/src/editor/components/attribute-editor.tsx +596 -0
- package/src/editor/components/block-editor.tsx +546 -0
- package/src/editor/components/collections-browser.tsx +248 -0
- package/src/editor/components/color-toolbar.tsx +314 -0
- package/src/editor/components/confirm-dialog.tsx +69 -0
- package/src/editor/components/create-page-modal.tsx +163 -0
- package/src/editor/components/editable-highlights.tsx +260 -0
- package/src/editor/components/error-boundary.tsx +87 -0
- package/src/editor/components/fields.tsx +387 -0
- package/src/editor/components/frontmatter-fields.tsx +469 -0
- package/src/editor/components/highlight-overlay.ts +229 -0
- package/src/editor/components/image-overlay.tsx +230 -0
- package/src/editor/components/markdown-editor-overlay.tsx +505 -0
- package/src/editor/components/markdown-inline-editor.tsx +780 -0
- package/src/editor/components/media-library.tsx +297 -0
- package/src/editor/components/outline.tsx +402 -0
- package/src/editor/components/redirect-countdown.tsx +45 -0
- package/src/editor/components/seo-editor.tsx +498 -0
- package/src/editor/components/text-style-toolbar.tsx +362 -0
- package/src/editor/components/toast/toast-container.tsx +15 -0
- package/src/editor/components/toast/toast.tsx +49 -0
- package/src/editor/components/toast/types.ts +7 -0
- package/src/editor/components/toolbar.tsx +366 -0
- package/src/editor/config.ts +12 -0
- package/src/editor/constants.ts +106 -0
- package/src/editor/context.tsx +38 -0
- package/src/editor/dom.ts +357 -0
- package/src/editor/editor.ts +1510 -0
- package/src/editor/env.d.ts +4 -0
- package/src/editor/history.ts +355 -0
- package/src/editor/hooks/index.ts +19 -0
- package/src/editor/hooks/useAIHandlers.ts +345 -0
- package/src/editor/hooks/useBlockEditorHandlers.ts +206 -0
- package/src/editor/hooks/useElementDetection.ts +284 -0
- package/src/editor/hooks/useImageHoverDetection.ts +102 -0
- package/src/editor/hooks/useTextSelection.ts +187 -0
- package/src/editor/hooks/useTooltipState.ts +126 -0
- package/src/editor/hooks/utils.ts +101 -0
- package/src/editor/index.tsx +481 -0
- package/src/editor/lib/cn.ts +4 -0
- package/src/editor/manifest.ts +25 -0
- package/src/editor/markdown-api.ts +209 -0
- package/src/editor/signals.ts +1351 -0
- package/src/editor/storage.ts +266 -0
- package/src/editor/styles.css +465 -0
- package/src/editor/text-styling.ts +773 -0
- package/src/editor/themes.ts +210 -0
- package/src/editor/types.ts +591 -0
- package/src/error-collector.ts +106 -0
- package/src/handlers/component-ops.ts +463 -0
- package/src/handlers/markdown-ops.ts +202 -0
- package/src/handlers/request-utils.ts +151 -0
- package/src/handlers/source-writer.ts +649 -0
- package/src/html-processor.ts +1108 -0
- package/src/index.ts +284 -0
- package/src/manifest-writer.ts +371 -0
- package/src/media/contember.ts +84 -0
- package/src/media/local.ts +114 -0
- package/src/media/s3.ts +133 -0
- package/src/media/types.ts +33 -0
- package/src/preview-generator.ts +293 -0
- package/src/seo-processor.ts +567 -0
- package/src/source-finder/ast-extractors.ts +185 -0
- package/src/source-finder/ast-parser.ts +150 -0
- package/src/source-finder/cache.ts +76 -0
- package/src/source-finder/collection-finder.ts +335 -0
- package/src/source-finder/cross-file-tracker.ts +741 -0
- package/src/source-finder/element-finder.ts +387 -0
- package/src/source-finder/image-finder.ts +283 -0
- package/src/source-finder/index.ts +37 -0
- package/src/source-finder/search-index.ts +525 -0
- package/src/source-finder/snippet-utils.ts +668 -0
- package/src/source-finder/source-lookup.ts +200 -0
- package/src/source-finder/types.ts +210 -0
- package/src/source-finder/variable-extraction.ts +406 -0
- package/src/tailwind-colors.ts +874 -0
- package/src/tsconfig.json +25 -0
- package/src/types.ts +406 -0
- package/src/utils.ts +186 -0
- package/src/vite-plugin.ts +42 -0
|
@@ -0,0 +1,185 @@
|
|
|
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
|
+
* Extract property name from an object key node.
|
|
30
|
+
* Handles both `{ name: value }` (Identifier) and `{ "name": value }` (StringLiteral).
|
|
31
|
+
*/
|
|
32
|
+
function getKeyName(key: BabelNode): string | null {
|
|
33
|
+
if (key.type === 'Identifier') return key.name as string
|
|
34
|
+
if (key.type === 'StringLiteral') return key.value as string
|
|
35
|
+
return null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Recursively extract properties from an object expression
|
|
40
|
+
* @param objNode - The ObjectExpression node
|
|
41
|
+
* @param parentPath - The full path to this object (e.g., 'config' or 'config.nav')
|
|
42
|
+
* @param definitions - Array to collect definitions into
|
|
43
|
+
* @param lineTransformer - Transforms Babel line numbers to file line numbers
|
|
44
|
+
*/
|
|
45
|
+
export function extractObjectProperties(
|
|
46
|
+
objNode: BabelNode,
|
|
47
|
+
parentPath: string,
|
|
48
|
+
definitions: VariableDefinition[],
|
|
49
|
+
lineTransformer: LineTransformer,
|
|
50
|
+
): void {
|
|
51
|
+
const properties = objNode.properties as BabelNode[] | undefined
|
|
52
|
+
for (const prop of properties ?? []) {
|
|
53
|
+
if (prop.type !== 'ObjectProperty') continue
|
|
54
|
+
const key = prop.key as BabelNode | undefined
|
|
55
|
+
const value = prop.value as BabelNode | undefined
|
|
56
|
+
if (!key || !value) continue
|
|
57
|
+
const propName = getKeyName(key)
|
|
58
|
+
if (!propName) continue
|
|
59
|
+
const fullPath = `${parentPath}.${propName}`
|
|
60
|
+
const propLoc = prop.loc as { start: { line: number } } | undefined
|
|
61
|
+
const propLine = lineTransformer(propLoc?.start.line ?? 1)
|
|
62
|
+
|
|
63
|
+
const stringValue = getStringValue(value)
|
|
64
|
+
if (stringValue !== null) {
|
|
65
|
+
definitions.push({
|
|
66
|
+
name: propName,
|
|
67
|
+
value: stringValue,
|
|
68
|
+
line: propLine,
|
|
69
|
+
parentName: parentPath,
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Recurse for nested objects
|
|
74
|
+
if (value.type === 'ObjectExpression') {
|
|
75
|
+
extractObjectProperties(value, fullPath, definitions, lineTransformer)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Handle arrays within objects
|
|
79
|
+
if (value.type === 'ArrayExpression') {
|
|
80
|
+
extractArrayElements(value, fullPath, definitions, lineTransformer, propLine)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Extract elements from an array expression
|
|
87
|
+
* @param arrNode - The ArrayExpression node
|
|
88
|
+
* @param parentPath - The full path to this array (e.g., 'items' or 'config.items')
|
|
89
|
+
* @param definitions - Array to collect definitions into
|
|
90
|
+
* @param lineTransformer - Transforms Babel line numbers to file line numbers
|
|
91
|
+
* @param defaultLine - Fallback line if element has no location
|
|
92
|
+
*/
|
|
93
|
+
export function extractArrayElements(
|
|
94
|
+
arrNode: BabelNode,
|
|
95
|
+
parentPath: string,
|
|
96
|
+
definitions: VariableDefinition[],
|
|
97
|
+
lineTransformer: LineTransformer,
|
|
98
|
+
defaultLine: number,
|
|
99
|
+
): void {
|
|
100
|
+
const elements = arrNode.elements as BabelNode[] | undefined
|
|
101
|
+
for (let i = 0; i < (elements?.length ?? 0); i++) {
|
|
102
|
+
const elem = elements![i]
|
|
103
|
+
if (!elem) continue
|
|
104
|
+
|
|
105
|
+
const elemLoc = elem.loc as { start: { line: number } } | undefined
|
|
106
|
+
const elemLine = elemLoc ? lineTransformer(elemLoc.start.line) : defaultLine
|
|
107
|
+
const indexPath = `${parentPath}[${i}]`
|
|
108
|
+
|
|
109
|
+
// Handle string values in array
|
|
110
|
+
const elemValue = getStringValue(elem)
|
|
111
|
+
if (elemValue !== null) {
|
|
112
|
+
definitions.push({
|
|
113
|
+
name: String(i),
|
|
114
|
+
value: elemValue,
|
|
115
|
+
line: elemLine,
|
|
116
|
+
parentName: parentPath,
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Handle array of objects: [{ text: 'Home' }] or [{ "text": 'Home' }]
|
|
121
|
+
if (elem.type === 'ObjectExpression') {
|
|
122
|
+
const objProperties = elem.properties as BabelNode[] | undefined
|
|
123
|
+
for (const prop of objProperties ?? []) {
|
|
124
|
+
if (prop.type !== 'ObjectProperty') continue
|
|
125
|
+
const key = prop.key as BabelNode | undefined
|
|
126
|
+
const value = prop.value as BabelNode | undefined
|
|
127
|
+
if (!key || !value) continue
|
|
128
|
+
const propName = getKeyName(key)
|
|
129
|
+
if (!propName) continue
|
|
130
|
+
const propLoc = prop.loc as { start: { line: number } } | undefined
|
|
131
|
+
const propLine = propLoc ? lineTransformer(propLoc.start.line) : elemLine
|
|
132
|
+
|
|
133
|
+
const stringValue = getStringValue(value)
|
|
134
|
+
if (stringValue !== null) {
|
|
135
|
+
definitions.push({
|
|
136
|
+
name: propName,
|
|
137
|
+
value: stringValue,
|
|
138
|
+
line: propLine,
|
|
139
|
+
parentName: indexPath,
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Recurse for nested objects within array elements
|
|
144
|
+
if (value.type === 'ObjectExpression') {
|
|
145
|
+
extractObjectProperties(value, `${indexPath}.${propName}`, definitions, lineTransformer)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ============================================================================
|
|
153
|
+
// Path Building Utilities
|
|
154
|
+
// ============================================================================
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Build the full path for a variable definition.
|
|
158
|
+
* For array indices (numeric names), uses bracket notation: items[0]
|
|
159
|
+
* For object properties, uses dot notation: config.nav.title
|
|
160
|
+
*/
|
|
161
|
+
export function buildDefinitionPath(def: VariableDefinition): string {
|
|
162
|
+
if (!def.parentName) {
|
|
163
|
+
return def.name
|
|
164
|
+
}
|
|
165
|
+
// Check if the name is a numeric index (for arrays)
|
|
166
|
+
if (/^\d+$/.test(def.name)) {
|
|
167
|
+
return `${def.parentName}[${def.name}]`
|
|
168
|
+
}
|
|
169
|
+
return `${def.parentName}.${def.name}`
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Parse an expression path and extract the full path for variable lookup.
|
|
174
|
+
* Handles patterns like: varName, obj.prop, items[0], config.nav.title, links[0].text
|
|
175
|
+
* @returns The full expression path or null if not a simple variable reference
|
|
176
|
+
*/
|
|
177
|
+
export function parseExpressionPath(exprText: string): string | null {
|
|
178
|
+
// Match patterns like: varName, obj.prop, items[0], config.nav.title, links[0].text
|
|
179
|
+
// Pattern breakdown: word characters, dots, and bracket notation with numbers
|
|
180
|
+
const match = exprText.match(/^\s*([\w]+(?:\.[\w]+|\[\d+\])*(?:\.[\w]+)?)\s*$/)
|
|
181
|
+
if (match) {
|
|
182
|
+
return match[1]!
|
|
183
|
+
}
|
|
184
|
+
return null
|
|
185
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
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
|
+
/** Deduplicates concurrent parsing requests for the same file */
|
|
69
|
+
const inFlightParsing = new Map<string, Promise<CachedParsedFile | null>>()
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get a cached parsed file, parsing it if not cached.
|
|
73
|
+
* Concurrent requests for the same file are deduplicated to avoid
|
|
74
|
+
* redundant parsing and potential race conditions.
|
|
75
|
+
*/
|
|
76
|
+
export async function getCachedParsedFile(filePath: string): Promise<CachedParsedFile | null> {
|
|
77
|
+
const cache = getParsedFileCache()
|
|
78
|
+
const cached = cache.get(filePath)
|
|
79
|
+
if (cached) return cached
|
|
80
|
+
|
|
81
|
+
// Deduplicate concurrent requests for the same file
|
|
82
|
+
const inFlight = inFlightParsing.get(filePath)
|
|
83
|
+
if (inFlight) return inFlight
|
|
84
|
+
|
|
85
|
+
const promise = parseAndCacheFile(filePath, cache)
|
|
86
|
+
inFlightParsing.set(filePath, promise)
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
return await promise
|
|
90
|
+
} finally {
|
|
91
|
+
inFlightParsing.delete(filePath)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function parseAndCacheFile(
|
|
96
|
+
filePath: string,
|
|
97
|
+
cache: Map<string, CachedParsedFile>,
|
|
98
|
+
): Promise<CachedParsedFile | null> {
|
|
99
|
+
try {
|
|
100
|
+
const content = await fs.readFile(filePath, 'utf-8')
|
|
101
|
+
const lines = content.split('\n')
|
|
102
|
+
|
|
103
|
+
// Only parse .astro files with AST
|
|
104
|
+
if (!filePath.endsWith('.astro')) {
|
|
105
|
+
// For tsx/jsx, just cache content/lines for regex search
|
|
106
|
+
const entry: CachedParsedFile = {
|
|
107
|
+
content,
|
|
108
|
+
lines,
|
|
109
|
+
ast: { type: 'root', children: [] } as unknown as AstroNode,
|
|
110
|
+
frontmatterContent: null,
|
|
111
|
+
frontmatterStartLine: 0,
|
|
112
|
+
variableDefinitions: [],
|
|
113
|
+
propAliases: new Map(),
|
|
114
|
+
imports: [],
|
|
115
|
+
}
|
|
116
|
+
cache.set(filePath, entry)
|
|
117
|
+
return entry
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const { ast, frontmatterContent, frontmatterStartLine } = await parseAstroFile(content)
|
|
121
|
+
|
|
122
|
+
let variableDefinitions: CachedParsedFile['variableDefinitions'] = []
|
|
123
|
+
let propAliases: Map<string, string> = new Map()
|
|
124
|
+
let imports: CachedParsedFile['imports'] = []
|
|
125
|
+
if (frontmatterContent) {
|
|
126
|
+
const frontmatterAst = parseFrontmatter(frontmatterContent, filePath)
|
|
127
|
+
if (frontmatterAst) {
|
|
128
|
+
variableDefinitions = extractVariableDefinitions(frontmatterAst, frontmatterStartLine)
|
|
129
|
+
propAliases = extractPropAliases(frontmatterAst)
|
|
130
|
+
imports = extractImports(frontmatterAst)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const entry: CachedParsedFile = {
|
|
135
|
+
content,
|
|
136
|
+
lines,
|
|
137
|
+
ast,
|
|
138
|
+
frontmatterContent,
|
|
139
|
+
frontmatterStartLine,
|
|
140
|
+
variableDefinitions,
|
|
141
|
+
propAliases,
|
|
142
|
+
imports,
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
cache.set(filePath, entry)
|
|
146
|
+
return entry
|
|
147
|
+
} catch {
|
|
148
|
+
return null
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
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 — use the same array instance and clear with length=0 to avoid stale references */
|
|
17
|
+
const textSearchIndex: SearchIndexEntry[] = []
|
|
18
|
+
const 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
|
+
// Clear arrays in-place to avoid stale references from consumers
|
|
73
|
+
textSearchIndex.length = 0
|
|
74
|
+
imageSearchIndex.length = 0
|
|
75
|
+
searchIndexInitialized = false
|
|
76
|
+
}
|