@imjp/writenex-astro 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.
Files changed (141) hide show
  1. package/README.md +539 -0
  2. package/dist/chunk-5PM6EQE5.js +151 -0
  3. package/dist/chunk-5PM6EQE5.js.map +1 -0
  4. package/dist/chunk-7XU5X6CW.js +1331 -0
  5. package/dist/chunk-7XU5X6CW.js.map +1 -0
  6. package/dist/chunk-AAOQHQPU.js +574 -0
  7. package/dist/chunk-AAOQHQPU.js.map +1 -0
  8. package/dist/chunk-CF2XXJFF.js +1410 -0
  9. package/dist/chunk-CF2XXJFF.js.map +1 -0
  10. package/dist/chunk-CRPZUUDU.js +52 -0
  11. package/dist/chunk-CRPZUUDU.js.map +1 -0
  12. package/dist/chunk-CYLDJ3HZ.js +310 -0
  13. package/dist/chunk-CYLDJ3HZ.js.map +1 -0
  14. package/dist/chunk-KIKIPIFA.js +1 -0
  15. package/dist/chunk-KIKIPIFA.js.map +1 -0
  16. package/dist/chunk-XNTQTTJU.js +145 -0
  17. package/dist/chunk-XNTQTTJU.js.map +1 -0
  18. package/dist/client/index.css +2 -0
  19. package/dist/client/index.css.map +1 -0
  20. package/dist/client/index.js +375 -0
  21. package/dist/client/index.js.map +1 -0
  22. package/dist/client/styles.css +584 -0
  23. package/dist/client/variables.css +304 -0
  24. package/dist/config/index.d.ts +54 -0
  25. package/dist/config/index.js +38 -0
  26. package/dist/config/index.js.map +1 -0
  27. package/dist/config-BmEdBDo_.d.ts +220 -0
  28. package/dist/content-BWR52vD-.d.ts +64 -0
  29. package/dist/discovery/index.d.ts +310 -0
  30. package/dist/discovery/index.js +38 -0
  31. package/dist/discovery/index.js.map +1 -0
  32. package/dist/errors-C0iYiDTv.d.ts +107 -0
  33. package/dist/filesystem/index.d.ts +1292 -0
  34. package/dist/filesystem/index.js +203 -0
  35. package/dist/filesystem/index.js.map +1 -0
  36. package/dist/image-FP7w5ZIs.d.ts +47 -0
  37. package/dist/index.d.ts +64 -0
  38. package/dist/index.js +151 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/loader-55LWCXHA.js +12 -0
  41. package/dist/loader-55LWCXHA.js.map +1 -0
  42. package/dist/loader-CrdnaAWR.d.ts +327 -0
  43. package/dist/server/index.d.ts +357 -0
  44. package/dist/server/index.js +37 -0
  45. package/dist/server/index.js.map +1 -0
  46. package/package.json +94 -0
  47. package/src/client/App.tsx +900 -0
  48. package/src/client/components/ConfigPanel/ConfigPanel.css +553 -0
  49. package/src/client/components/ConfigPanel/ConfigPanel.tsx +396 -0
  50. package/src/client/components/ConfigPanel/index.ts +6 -0
  51. package/src/client/components/CreateContentModal/CreateContentModal.css +327 -0
  52. package/src/client/components/CreateContentModal/CreateContentModal.tsx +216 -0
  53. package/src/client/components/CreateContentModal/index.ts +7 -0
  54. package/src/client/components/Editor/Editor.css +885 -0
  55. package/src/client/components/Editor/Editor.tsx +484 -0
  56. package/src/client/components/Editor/ImageDialog.css +344 -0
  57. package/src/client/components/Editor/ImageDialog.tsx +367 -0
  58. package/src/client/components/Editor/LinkDialog.css +326 -0
  59. package/src/client/components/Editor/LinkDialog.tsx +332 -0
  60. package/src/client/components/Editor/index.ts +6 -0
  61. package/src/client/components/FrontmatterForm/FrontmatterForm.css +468 -0
  62. package/src/client/components/FrontmatterForm/FrontmatterForm.tsx +914 -0
  63. package/src/client/components/FrontmatterForm/index.ts +7 -0
  64. package/src/client/components/Header/Header.css +300 -0
  65. package/src/client/components/Header/Header.tsx +300 -0
  66. package/src/client/components/Header/index.ts +7 -0
  67. package/src/client/components/KeyboardShortcuts/KeyboardShortcuts.css +239 -0
  68. package/src/client/components/KeyboardShortcuts/KeyboardShortcuts.tsx +151 -0
  69. package/src/client/components/KeyboardShortcuts/index.ts +6 -0
  70. package/src/client/components/LazyEditor.tsx +75 -0
  71. package/src/client/components/LiveRegion/LiveRegion.css +19 -0
  72. package/src/client/components/LiveRegion/LiveRegion.tsx +60 -0
  73. package/src/client/components/LiveRegion/index.ts +7 -0
  74. package/src/client/components/SearchReplace/SearchReplacePanel.css +300 -0
  75. package/src/client/components/SearchReplace/SearchReplacePanel.tsx +332 -0
  76. package/src/client/components/SearchReplace/index.ts +7 -0
  77. package/src/client/components/SelectCollectionModal/SelectCollectionModal.css +308 -0
  78. package/src/client/components/SelectCollectionModal/SelectCollectionModal.tsx +223 -0
  79. package/src/client/components/SelectCollectionModal/index.ts +7 -0
  80. package/src/client/components/Sidebar/Sidebar.css +570 -0
  81. package/src/client/components/Sidebar/Sidebar.tsx +617 -0
  82. package/src/client/components/Sidebar/index.ts +7 -0
  83. package/src/client/components/SkipLink/SkipLink.css +51 -0
  84. package/src/client/components/SkipLink/SkipLink.tsx +67 -0
  85. package/src/client/components/SkipLink/index.ts +7 -0
  86. package/src/client/components/UnsavedChangesModal/UnsavedChangesModal.css +233 -0
  87. package/src/client/components/UnsavedChangesModal/UnsavedChangesModal.tsx +160 -0
  88. package/src/client/components/UnsavedChangesModal/index.ts +1 -0
  89. package/src/client/components/VersionHistory/DiffViewer.css +430 -0
  90. package/src/client/components/VersionHistory/DiffViewer.tsx +383 -0
  91. package/src/client/components/VersionHistory/VersionActions.css +318 -0
  92. package/src/client/components/VersionHistory/VersionActions.tsx +277 -0
  93. package/src/client/components/VersionHistory/VersionHistoryPanel.css +369 -0
  94. package/src/client/components/VersionHistory/VersionHistoryPanel.tsx +469 -0
  95. package/src/client/components/VersionHistory/index.ts +9 -0
  96. package/src/client/context/ApiContext.tsx +154 -0
  97. package/src/client/context/ThemeContext.tsx +172 -0
  98. package/src/client/hooks/useAnnounce.ts +201 -0
  99. package/src/client/hooks/useApi.ts +374 -0
  100. package/src/client/hooks/useArrowNavigation.ts +286 -0
  101. package/src/client/hooks/useAutosave.ts +241 -0
  102. package/src/client/hooks/useFocusTrap.ts +178 -0
  103. package/src/client/hooks/useKeyboardShortcuts.ts +203 -0
  104. package/src/client/hooks/useSearch.ts +206 -0
  105. package/src/client/hooks/useVersionHistory.ts +451 -0
  106. package/src/client/index.tsx +70 -0
  107. package/src/client/styles.css +584 -0
  108. package/src/client/utils/focus.ts +57 -0
  109. package/src/client/utils/openInEditor.ts +130 -0
  110. package/src/client/variables.css +304 -0
  111. package/src/config/defaults.ts +109 -0
  112. package/src/config/index.ts +32 -0
  113. package/src/config/loader.ts +174 -0
  114. package/src/config/schema.ts +161 -0
  115. package/src/core/constants.ts +39 -0
  116. package/src/core/errors.ts +739 -0
  117. package/src/core/index.ts +11 -0
  118. package/src/discovery/collections.ts +216 -0
  119. package/src/discovery/index.ts +33 -0
  120. package/src/discovery/patterns.ts +702 -0
  121. package/src/discovery/schema.ts +453 -0
  122. package/src/filesystem/images.ts +798 -0
  123. package/src/filesystem/index.ts +107 -0
  124. package/src/filesystem/reader.ts +452 -0
  125. package/src/filesystem/version-config.ts +390 -0
  126. package/src/filesystem/versions.ts +1339 -0
  127. package/src/filesystem/watcher.ts +226 -0
  128. package/src/filesystem/writer.ts +540 -0
  129. package/src/index.ts +61 -0
  130. package/src/integration.ts +228 -0
  131. package/src/server/assets.ts +254 -0
  132. package/src/server/cache.ts +355 -0
  133. package/src/server/index.ts +33 -0
  134. package/src/server/middleware.ts +209 -0
  135. package/src/server/routes.ts +1428 -0
  136. package/src/types/api.ts +61 -0
  137. package/src/types/config.ts +134 -0
  138. package/src/types/content.ts +64 -0
  139. package/src/types/image.ts +48 -0
  140. package/src/types/index.ts +58 -0
  141. package/src/types/version.ts +117 -0
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @fileoverview Core utilities barrel file for @writenex/astro
3
+ *
4
+ * This module re-exports shared utilities including error classes,
5
+ * error codes, and constants used across the integration.
6
+ *
7
+ * @module @writenex/astro/core
8
+ */
9
+
10
+ export * from "./errors";
11
+ export * from "./constants";
@@ -0,0 +1,216 @@
1
+ /**
2
+ * @fileoverview Collection discovery for Astro content collections
3
+ *
4
+ * This module provides functions to auto-discover content collections
5
+ * from an Astro project's src/content directory.
6
+ *
7
+ * ## Discovery Process:
8
+ * 1. Scan src/content/ for subdirectories
9
+ * 2. Each subdirectory is treated as a collection
10
+ * 3. Count content files in each collection
11
+ * 4. Detect file patterns from existing files
12
+ * 5. Auto-detect frontmatter schema from sample files
13
+ *
14
+ * @module @writenex/astro/discovery/collections
15
+ */
16
+
17
+ import { readdir, stat } from "node:fs/promises";
18
+ import { existsSync } from "node:fs";
19
+ import { join } from "node:path";
20
+ import type { DiscoveredCollection, CollectionConfig } from "@/types";
21
+ import { getCollectionCount } from "@/filesystem/reader";
22
+ import { DEFAULT_FILE_PATTERN } from "@/config/defaults";
23
+ import { detectFilePattern as detectPattern } from "./patterns";
24
+ import { detectSchema } from "./schema";
25
+
26
+ /**
27
+ * Default content directory path relative to project root
28
+ */
29
+ const DEFAULT_CONTENT_DIR = "src/content";
30
+
31
+ /**
32
+ * Directories to ignore during discovery
33
+ */
34
+ const IGNORED_DIRECTORIES = new Set(["node_modules", ".git", "_", "."]);
35
+
36
+ /**
37
+ * Check if a directory should be ignored
38
+ *
39
+ * @param name - Directory name
40
+ * @returns True if should be ignored
41
+ */
42
+ function shouldIgnore(name: string): boolean {
43
+ return (
44
+ IGNORED_DIRECTORIES.has(name) ||
45
+ name.startsWith("_") ||
46
+ name.startsWith(".")
47
+ );
48
+ }
49
+
50
+ /**
51
+ * Discover all content collections in a project
52
+ *
53
+ * Scans the src/content directory for subdirectories and treats
54
+ * each as a content collection.
55
+ *
56
+ * @param projectRoot - Absolute path to the project root
57
+ * @param contentDir - Relative path to content directory (default: src/content)
58
+ * @returns Array of discovered collections
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * const collections = await discoverCollections('/path/to/project');
63
+ * // Returns: [
64
+ * // { name: 'blog', path: 'src/content/blog', count: 10, ... },
65
+ * // { name: 'docs', path: 'src/content/docs', count: 5, ... },
66
+ * // ]
67
+ * ```
68
+ */
69
+ export async function discoverCollections(
70
+ projectRoot: string,
71
+ contentDir: string = DEFAULT_CONTENT_DIR
72
+ ): Promise<DiscoveredCollection[]> {
73
+ const contentPath = join(projectRoot, contentDir);
74
+
75
+ // Check if content directory exists
76
+ if (!existsSync(contentPath)) {
77
+ return [];
78
+ }
79
+
80
+ const collections: DiscoveredCollection[] = [];
81
+
82
+ try {
83
+ const entries = await readdir(contentPath, { withFileTypes: true });
84
+
85
+ for (const entry of entries) {
86
+ // Skip non-directories and ignored directories
87
+ if (!entry.isDirectory() || shouldIgnore(entry.name)) {
88
+ continue;
89
+ }
90
+
91
+ const collectionPath = join(contentPath, entry.name);
92
+ const relativePath = join(contentDir, entry.name);
93
+
94
+ // Count content files in this collection
95
+ const count = await getCollectionCount(collectionPath);
96
+
97
+ // Detect file pattern using pattern detection module
98
+ const patternResult = await detectPattern(collectionPath);
99
+ const filePattern = patternResult.pattern;
100
+
101
+ // Auto-detect schema from sample files
102
+ const schemaResult = await detectSchema(collectionPath);
103
+ const schema =
104
+ Object.keys(schemaResult.schema).length > 0
105
+ ? schemaResult.schema
106
+ : undefined;
107
+
108
+ // Generate default preview URL pattern
109
+ const previewUrl = `/${entry.name}/{slug}`;
110
+
111
+ collections.push({
112
+ name: entry.name,
113
+ path: relativePath,
114
+ filePattern,
115
+ count,
116
+ schema,
117
+ previewUrl,
118
+ });
119
+ }
120
+ } catch (error) {
121
+ console.error(`[writenex] Failed to discover collections: ${error}`);
122
+ }
123
+
124
+ return collections;
125
+ }
126
+
127
+ /**
128
+ * Merge discovered collections with configured collections
129
+ *
130
+ * Configured collections take precedence over discovered ones.
131
+ * This allows users to override auto-discovered settings.
132
+ *
133
+ * @param discovered - Auto-discovered collections
134
+ * @param configured - User-configured collections
135
+ * @returns Merged collection list
136
+ */
137
+ export function mergeCollections(
138
+ discovered: DiscoveredCollection[],
139
+ configured: CollectionConfig[]
140
+ ): DiscoveredCollection[] {
141
+ const configuredNames = new Set(configured.map((c) => c.name));
142
+ const result: DiscoveredCollection[] = [];
143
+
144
+ // Add configured collections first (they take precedence)
145
+ for (const config of configured) {
146
+ const discoveredMatch = discovered.find((d) => d.name === config.name);
147
+
148
+ result.push({
149
+ name: config.name,
150
+ path: config.path,
151
+ filePattern:
152
+ config.filePattern ??
153
+ discoveredMatch?.filePattern ??
154
+ DEFAULT_FILE_PATTERN,
155
+ count: discoveredMatch?.count ?? 0,
156
+ schema: config.schema ?? discoveredMatch?.schema,
157
+ previewUrl:
158
+ config.previewUrl ??
159
+ discoveredMatch?.previewUrl ??
160
+ `/${config.name}/{slug}`,
161
+ });
162
+ }
163
+
164
+ // Add discovered collections that weren't configured
165
+ for (const disc of discovered) {
166
+ if (!configuredNames.has(disc.name)) {
167
+ result.push(disc);
168
+ }
169
+ }
170
+
171
+ return result;
172
+ }
173
+
174
+ /**
175
+ * Get a single collection by name
176
+ *
177
+ * @param projectRoot - Absolute path to the project root
178
+ * @param collectionName - Name of the collection
179
+ * @param contentDir - Relative path to content directory
180
+ * @returns The collection if found, undefined otherwise
181
+ */
182
+ export async function getCollection(
183
+ projectRoot: string,
184
+ collectionName: string,
185
+ contentDir: string = DEFAULT_CONTENT_DIR
186
+ ): Promise<DiscoveredCollection | undefined> {
187
+ const collections = await discoverCollections(projectRoot, contentDir);
188
+ return collections.find((c) => c.name === collectionName);
189
+ }
190
+
191
+ /**
192
+ * Check if a collection exists
193
+ *
194
+ * @param projectRoot - Absolute path to the project root
195
+ * @param collectionName - Name of the collection
196
+ * @param contentDir - Relative path to content directory
197
+ * @returns True if the collection exists
198
+ */
199
+ export async function collectionExists(
200
+ projectRoot: string,
201
+ collectionName: string,
202
+ contentDir: string = DEFAULT_CONTENT_DIR
203
+ ): Promise<boolean> {
204
+ const collectionPath = join(projectRoot, contentDir, collectionName);
205
+
206
+ if (!existsSync(collectionPath)) {
207
+ return false;
208
+ }
209
+
210
+ try {
211
+ const stats = await stat(collectionPath);
212
+ return stats.isDirectory();
213
+ } catch {
214
+ return false;
215
+ }
216
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @fileoverview Discovery module exports for @writenex/astro
3
+ *
4
+ * This module provides the public API for collection discovery,
5
+ * file pattern detection, and schema auto-detection.
6
+ *
7
+ * @module @writenex/astro/discovery
8
+ */
9
+
10
+ // Collection discovery
11
+ export {
12
+ discoverCollections,
13
+ mergeCollections,
14
+ getCollection,
15
+ collectionExists,
16
+ } from "./collections";
17
+
18
+ // Pattern detection
19
+ export {
20
+ detectFilePattern,
21
+ generatePathFromPattern,
22
+ parsePatternTokens,
23
+ validatePattern,
24
+ getPatternExtension,
25
+ resolvePatternTokens,
26
+ isValidPattern,
27
+ getSupportedTokens,
28
+ } from "./patterns";
29
+ export type { PatternDetectionResult, ResolveTokensOptions } from "./patterns";
30
+
31
+ // Schema detection
32
+ export { detectSchema, mergeSchema, describeSchema } from "./schema";
33
+ export type { SchemaDetectionResult } from "./schema";