@nuasite/cms-marker 0.0.52 → 0.0.54

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.
Files changed (39) hide show
  1. package/README.md +0 -4
  2. package/dist/types/astro-transform.d.ts +21 -0
  3. package/dist/types/astro-transform.d.ts.map +1 -0
  4. package/dist/types/build-processor.d.ts +10 -0
  5. package/dist/types/build-processor.d.ts.map +1 -0
  6. package/dist/types/component-registry.d.ts +63 -0
  7. package/dist/types/component-registry.d.ts.map +1 -0
  8. package/dist/types/dev-middleware.d.ts +7 -0
  9. package/dist/types/dev-middleware.d.ts.map +1 -0
  10. package/dist/types/html-processor.d.ts +51 -0
  11. package/dist/types/html-processor.d.ts.map +1 -0
  12. package/dist/types/index.d.ts +7 -0
  13. package/dist/types/index.d.ts.map +1 -0
  14. package/dist/types/manifest-writer.d.ts +75 -0
  15. package/dist/types/manifest-writer.d.ts.map +1 -0
  16. package/dist/types/source-finder.d.ts +97 -0
  17. package/dist/types/source-finder.d.ts.map +1 -0
  18. package/dist/types/tailwind-colors.d.ts +66 -0
  19. package/dist/types/tailwind-colors.d.ts.map +1 -0
  20. package/dist/types/tsconfig.tsbuildinfo +1 -0
  21. package/dist/types/types.d.ts +195 -0
  22. package/dist/types/types.d.ts.map +1 -0
  23. package/dist/types/utils.d.ts +38 -0
  24. package/dist/types/utils.d.ts.map +1 -0
  25. package/dist/types/vite-plugin.d.ts +14 -0
  26. package/dist/types/vite-plugin.d.ts.map +1 -0
  27. package/package.json +1 -1
  28. package/src/astro-transform.ts +4 -4
  29. package/src/build-processor.ts +1 -1
  30. package/src/component-registry.ts +2 -2
  31. package/src/dev-middleware.ts +6 -6
  32. package/src/html-processor.ts +180 -6
  33. package/src/index.ts +0 -1
  34. package/src/manifest-writer.ts +47 -1
  35. package/src/source-finder.ts +142 -9
  36. package/src/tailwind-colors.ts +338 -0
  37. package/src/tsconfig.json +1 -1
  38. package/src/types.ts +123 -1
  39. package/src/utils.ts +99 -0
package/src/types.ts CHANGED
@@ -27,14 +27,95 @@ export interface ComponentDefinition {
27
27
  slots?: string[]
28
28
  }
29
29
 
30
+ /** Context around an element for resilient matching when exact match fails */
31
+ export interface SourceContext {
32
+ /** Text content of the preceding sibling element */
33
+ precedingText?: string
34
+ /** Text content of the following sibling element */
35
+ followingText?: string
36
+ /** Parent element's tag name */
37
+ parentTag?: string
38
+ /** Position among siblings (0-indexed) */
39
+ siblingIndex?: number
40
+ /** Parent element's class attribute */
41
+ parentClasses?: string
42
+ }
43
+
44
+ /** Image metadata for better tracking and integrity */
45
+ export interface ImageMetadata {
46
+ /** Image source URL */
47
+ src: string
48
+ /** Alt text */
49
+ alt: string
50
+ /** SHA256 hash of image content (for integrity checking) */
51
+ hash?: string
52
+ /** Image dimensions */
53
+ dimensions?: { width: number; height: number }
54
+ /** Responsive image srcset */
55
+ srcSet?: string
56
+ /** Image sizes attribute */
57
+ sizes?: string
58
+ }
59
+
60
+ /** Content constraints for validation */
61
+ export interface ContentConstraints {
62
+ /** Maximum content length */
63
+ maxLength?: number
64
+ /** Minimum content length */
65
+ minLength?: number
66
+ /** Regex pattern for validation */
67
+ pattern?: string
68
+ /** Allowed HTML tags for rich text content */
69
+ allowedTags?: string[]
70
+ }
71
+
72
+ /** Represents a single Tailwind color with its shades */
73
+ export interface TailwindColor {
74
+ /** Color name (e.g., 'red', 'blue', 'primary') */
75
+ name: string
76
+ /** Available shades (e.g., ['50', '100', '200', ..., '900', '950']) */
77
+ shades: string[]
78
+ /** Whether this is a custom/theme color vs default Tailwind */
79
+ isCustom?: boolean
80
+ }
81
+
82
+ /** Color classes currently applied to an element */
83
+ export interface ColorClasses {
84
+ /** Background color class (e.g., 'bg-blue-500') */
85
+ bg?: string
86
+ /** Text color class (e.g., 'text-white') */
87
+ text?: string
88
+ /** Border color class (e.g., 'border-blue-600') */
89
+ border?: string
90
+ /** Hover background color class (e.g., 'hover:bg-blue-600') */
91
+ hoverBg?: string
92
+ /** Hover text color class (e.g., 'hover:text-gray-100') */
93
+ hoverText?: string
94
+ /** All color-related classes as found in the element */
95
+ allColorClasses?: string[]
96
+ }
97
+
98
+ /** Available colors palette from Tailwind config */
99
+ export interface AvailableColors {
100
+ /** All available colors with their shades */
101
+ colors: TailwindColor[]
102
+ /** Default Tailwind color names */
103
+ defaultColors: string[]
104
+ /** Custom/theme color names */
105
+ customColors: string[]
106
+ }
107
+
30
108
  export interface ManifestEntry {
31
109
  id: string
32
110
  tag: string
111
+ /** Plain text content (for display/search) */
33
112
  text: string
113
+ /** HTML content when element contains inline styling (strong, em, etc.) */
114
+ html?: string
34
115
  sourcePath?: string
35
116
  sourceLine?: number
36
117
  sourceSnippet?: string
37
- sourceType?: 'static' | 'variable' | 'prop' | 'computed' | 'collection'
118
+ sourceType?: 'static' | 'variable' | 'prop' | 'computed' | 'collection' | 'image'
38
119
  variableName?: string
39
120
  childCmsIds?: string[]
40
121
  parentComponentId?: string
@@ -42,6 +123,27 @@ export interface ManifestEntry {
42
123
  collectionName?: string
43
124
  /** Entry slug for collection entries (e.g., '3d-tisk') */
44
125
  collectionSlug?: string
126
+ /** Path to the markdown content file (e.g., 'src/content/blog/my-post.md') */
127
+ contentPath?: string
128
+ /** Image source URL (for image entries) - deprecated, use imageMetadata */
129
+ imageSrc?: string
130
+ /** Image alt text (for image entries) - deprecated, use imageMetadata */
131
+ imageAlt?: string
132
+
133
+ // === Robustness fields ===
134
+
135
+ /** Stable ID derived from content + context hash, survives rebuilds */
136
+ stableId?: string
137
+ /** SHA256 hash of sourceSnippet at generation time for conflict detection */
138
+ sourceHash?: string
139
+ /** Context around the element for resilient matching */
140
+ sourceContext?: SourceContext
141
+ /** Image metadata for img elements (replaces imageSrc/imageAlt) */
142
+ imageMetadata?: ImageMetadata
143
+ /** Content validation constraints */
144
+ constraints?: ContentConstraints
145
+ /** Color classes applied to this element (for buttons, etc.) */
146
+ colorClasses?: ColorClasses
45
147
  }
46
148
 
47
149
  export interface ComponentInstance {
@@ -73,10 +175,30 @@ export interface CollectionEntry {
73
175
  wrapperId?: string
74
176
  }
75
177
 
178
+ /** Manifest metadata for versioning and conflict detection */
179
+ export interface ManifestMetadata {
180
+ /** Manifest schema version */
181
+ version: string
182
+ /** ISO timestamp when manifest was generated */
183
+ generatedAt: string
184
+ /** Build system that generated the manifest (e.g., 'astro', 'vite') */
185
+ generatedBy?: string
186
+ /** Build ID for correlation */
187
+ buildId?: string
188
+ /** SHA256 hash of all entry content for quick drift detection */
189
+ contentHash?: string
190
+ /** Per-source-file hashes for granular conflict detection */
191
+ sourceFileHashes?: Record<string, string>
192
+ }
193
+
76
194
  export interface CmsManifest {
195
+ /** Manifest metadata for versioning and conflict detection */
196
+ metadata?: ManifestMetadata
77
197
  entries: Record<string, ManifestEntry>
78
198
  components: Record<string, ComponentInstance>
79
199
  componentDefinitions: Record<string, ComponentDefinition>
80
200
  /** Content collection entries indexed by "collectionName/slug" */
81
201
  collections?: Record<string, CollectionEntry>
202
+ /** Available Tailwind colors from the project's config */
203
+ availableColors?: AvailableColors
82
204
  }
package/src/utils.ts ADDED
@@ -0,0 +1,99 @@
1
+ import { createHash } from 'node:crypto'
2
+ import type { ManifestEntry, SourceContext } from './types'
3
+
4
+ /**
5
+ * Generate a SHA256 hash of the given content
6
+ */
7
+ export function sha256(content: string): string {
8
+ return createHash('sha256').update(content, 'utf8').digest('hex')
9
+ }
10
+
11
+ /**
12
+ * Generate a short hash (first 12 characters of SHA256)
13
+ * Used for stableId to keep it reasonably short but still unique
14
+ */
15
+ export function shortHash(content: string): string {
16
+ return sha256(content).substring(0, 12)
17
+ }
18
+
19
+ /**
20
+ * Generate a stable ID for an element based on its content and context.
21
+ * This ID survives rebuilds as long as the content and structure remain similar.
22
+ *
23
+ * Components:
24
+ * - tag name
25
+ * - first 50 chars of text content
26
+ * - source path (if available)
27
+ * - parent tag
28
+ * - sibling index
29
+ */
30
+ export function generateStableId(
31
+ tag: string,
32
+ text: string,
33
+ sourcePath?: string,
34
+ context?: SourceContext,
35
+ ): string {
36
+ const components = [
37
+ tag,
38
+ text.substring(0, 50).trim(),
39
+ sourcePath || '',
40
+ context?.parentTag || '',
41
+ context?.siblingIndex?.toString() || '',
42
+ ]
43
+
44
+ return shortHash(components.join('|'))
45
+ }
46
+
47
+ /**
48
+ * Generate a hash of the source snippet for conflict detection.
49
+ * If the source file changes, this hash will differ from what's stored in manifest.
50
+ */
51
+ export function generateSourceHash(sourceSnippet: string): string {
52
+ return sha256(sourceSnippet)
53
+ }
54
+
55
+ /**
56
+ * Generate a content hash for the entire manifest (all entries).
57
+ * Used for quick drift detection without comparing individual entries.
58
+ */
59
+ export function generateManifestContentHash(entries: Record<string, ManifestEntry>): string {
60
+ // Sort keys for deterministic hashing
61
+ const sortedKeys = Object.keys(entries).sort()
62
+ const content = sortedKeys.map(key => {
63
+ const entry = entries[key]!
64
+ // Hash only content-relevant fields, not generated IDs
65
+ return `${entry.tag}|${entry.text}|${entry.html || ''}|${entry.sourcePath || ''}`
66
+ }).join('\n')
67
+
68
+ return sha256(content)
69
+ }
70
+
71
+ /**
72
+ * Generate per-source-file hashes for granular conflict detection.
73
+ * Maps source file path -> hash of all entries from that file.
74
+ */
75
+ export function generateSourceFileHashes(entries: Record<string, ManifestEntry>): Record<string, string> {
76
+ // Group entries by source file
77
+ const entriesByFile: Record<string, ManifestEntry[]> = {}
78
+
79
+ for (const entry of Object.values(entries)) {
80
+ const sourcePath = entry.sourcePath
81
+ if (sourcePath) {
82
+ if (!entriesByFile[sourcePath]) {
83
+ entriesByFile[sourcePath] = []
84
+ }
85
+ entriesByFile[sourcePath].push(entry)
86
+ }
87
+ }
88
+
89
+ // Generate hash for each file
90
+ const hashes: Record<string, string> = {}
91
+ for (const [filePath, fileEntries] of Object.entries(entriesByFile)) {
92
+ // Sort entries by line number for determinism
93
+ const sorted = fileEntries.sort((a, b) => (a.sourceLine || 0) - (b.sourceLine || 0))
94
+ const content = sorted.map(e => `${e.sourceLine || 0}|${e.text}|${e.sourceSnippet || ''}`).join('\n')
95
+ hashes[filePath] = sha256(content)
96
+ }
97
+
98
+ return hashes
99
+ }