hale-commenting-system 2.0.0 → 2.0.2

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 CHANGED
@@ -73,7 +73,8 @@ import { BrowserRouter as Router } from 'react-router-dom';
73
73
  import {
74
74
  CommentProvider,
75
75
  CommentOverlay,
76
- CommentDrawer
76
+ CommentDrawer,
77
+ VersionProvider
77
78
  } from 'hale-commenting-system';
78
79
 
79
80
  function App() {
@@ -81,18 +82,20 @@ function App() {
81
82
 
82
83
  return (
83
84
  <Router>
84
- <CommentProvider>
85
- <CommentDrawer
86
- selectedThreadId={selectedThreadId}
87
- onThreadSelect={setSelectedThreadId}
88
- >
89
- <CommentOverlay
85
+ <VersionProvider>
86
+ <CommentProvider>
87
+ <CommentDrawer
90
88
  selectedThreadId={selectedThreadId}
91
89
  onThreadSelect={setSelectedThreadId}
92
- />
93
- {/* Your app content */}
94
- </CommentDrawer>
95
- </CommentProvider>
90
+ >
91
+ <CommentOverlay
92
+ selectedThreadId={selectedThreadId}
93
+ onThreadSelect={setSelectedThreadId}
94
+ />
95
+ {/* Your app content */}
96
+ </CommentDrawer>
97
+ </CommentProvider>
98
+ </VersionProvider>
96
99
  </Router>
97
100
  );
98
101
  }
package/cli/dist/index.js CHANGED
@@ -142,7 +142,9 @@ function injectProviders(content) {
142
142
  const imports = `import {
143
143
  CommentProvider,
144
144
  CommentOverlay,
145
- CommentDrawer
145
+ CommentDrawer,
146
+ useComments,
147
+ VersionProvider
146
148
  } from 'hale-commenting-system';`;
147
149
  const importRegex = /import\s+.*?from\s+['"].*?['"];?/g;
148
150
  const matches = content.match(importRegex);
@@ -154,7 +156,12 @@ function injectProviders(content) {
154
156
  const insertPosition = lastImportIndex + lastImport.length;
155
157
  content = content.slice(0, insertPosition) + "\n\n" + imports + content.slice(insertPosition);
156
158
  }
157
- const returnMatch = content.match(/return\s*\(?[\s\n]*<(\w+)/);
159
+ let returnMatch = content.match(/return\s*\(?[\s\n]*<(\w+)/);
160
+ let isImplicitReturn = false;
161
+ if (!returnMatch) {
162
+ returnMatch = content.match(/=>\s*\(?[\s\n]*<(\w+)/);
163
+ isImplicitReturn = true;
164
+ }
158
165
  if (!returnMatch) {
159
166
  return content;
160
167
  }
@@ -164,6 +171,18 @@ function injectProviders(content) {
164
171
  if (closingIndex === -1) {
165
172
  return content;
166
173
  }
174
+ if (isImplicitReturn) {
175
+ const arrowMatch = content.match(/(const\s+\w+.*?=.*?\(\).*?=>\s*)\(/);
176
+ if (arrowMatch) {
177
+ const beforeParen = arrowMatch[1];
178
+ const arrowEndPos = arrowMatch.index + arrowMatch[0].length - 1;
179
+ const closingParenPos = content.indexOf(");", closingIndex);
180
+ if (closingParenPos !== -1) {
181
+ const jsxContent = content.slice(arrowEndPos + 1, closingParenPos);
182
+ content = content.slice(0, arrowEndPos) + " {\n return" + jsxContent + "\n}" + content.slice(closingParenPos + 2);
183
+ }
184
+ }
185
+ }
167
186
  const stateHook = ` const [selectedThreadId, setSelectedThreadId] = React.useState<string | null>(null);
168
187
 
169
188
  `;
@@ -172,9 +191,9 @@ function injectProviders(content) {
172
191
  const insertPos = functionMatch.index + functionMatch[0].length;
173
192
  content = content.slice(0, insertPos) + "\n" + stateHook + content.slice(insertPos);
174
193
  }
175
- const returnStartMatch = content.match(/return\s*\(/);
194
+ const returnStartMatch = content.match(/return\s*\(?[\s\n]*</);
176
195
  if (returnStartMatch) {
177
- const returnStart = returnStartMatch.index + returnStartMatch[0].length;
196
+ const returnStart = returnStartMatch.index + returnStartMatch[0].length - 1;
178
197
  const returnEnd = content.indexOf(closingTag, returnStart) + closingTag.length;
179
198
  const originalReturn = content.slice(returnStart, returnEnd).trim();
180
199
  const isRouter = originalReturn.match(/^\s*<(Router|BrowserRouter)/);
@@ -186,6 +205,25 @@ function injectProviders(content) {
186
205
  const innerContent = routerMatch[2];
187
206
  wrappedReturn = `
188
207
  <${routerType}>
208
+ <VersionProvider>
209
+ <CommentProvider>
210
+ <CommentDrawer
211
+ selectedThreadId={selectedThreadId}
212
+ onThreadSelect={setSelectedThreadId}
213
+ >
214
+ <CommentOverlay
215
+ selectedThreadId={selectedThreadId}
216
+ onThreadSelect={setSelectedThreadId}
217
+ />
218
+ ${innerContent.trim()}
219
+ </CommentDrawer>
220
+ </CommentProvider>
221
+ </VersionProvider>
222
+ </${routerType}>
223
+ `;
224
+ } else {
225
+ wrappedReturn = `
226
+ <VersionProvider>
189
227
  <CommentProvider>
190
228
  <CommentDrawer
191
229
  selectedThreadId={selectedThreadId}
@@ -195,41 +233,28 @@ function injectProviders(content) {
195
233
  selectedThreadId={selectedThreadId}
196
234
  onThreadSelect={setSelectedThreadId}
197
235
  />
198
- ${innerContent.trim()}
236
+ ${originalReturn}
199
237
  </CommentDrawer>
200
238
  </CommentProvider>
201
- </${routerType}>
202
- `;
203
- } else {
204
- wrappedReturn = `
205
- <CommentProvider>
206
- <CommentDrawer
207
- selectedThreadId={selectedThreadId}
208
- onThreadSelect={setSelectedThreadId}
209
- >
210
- <CommentOverlay
211
- selectedThreadId={selectedThreadId}
212
- onThreadSelect={setSelectedThreadId}
213
- />
214
- ${originalReturn}
215
- </CommentDrawer>
216
- </CommentProvider>
239
+ </VersionProvider>
217
240
  `;
218
241
  }
219
242
  } else {
220
243
  wrappedReturn = `
221
- <CommentProvider>
222
- <CommentDrawer
223
- selectedThreadId={selectedThreadId}
224
- onThreadSelect={setSelectedThreadId}
225
- >
226
- <CommentOverlay
244
+ <VersionProvider>
245
+ <CommentProvider>
246
+ <CommentDrawer
227
247
  selectedThreadId={selectedThreadId}
228
248
  onThreadSelect={setSelectedThreadId}
229
- />
230
- ${originalReturn}
231
- </CommentDrawer>
232
- </CommentProvider>
249
+ >
250
+ <CommentOverlay
251
+ selectedThreadId={selectedThreadId}
252
+ onThreadSelect={setSelectedThreadId}
253
+ />
254
+ ${originalReturn}
255
+ </CommentDrawer>
256
+ </CommentProvider>
257
+ </VersionProvider>
233
258
  `;
234
259
  }
235
260
  content = content.slice(0, returnStart) + wrappedReturn + content.slice(returnEnd);
@@ -297,7 +322,7 @@ async function initCommand(options) {
297
322
  spinner.warn(result.message);
298
323
  console.log(chalk3.yellow("\n\u26A0\uFE0F Could not automatically integrate the commenting system.\n"));
299
324
  console.log(chalk3.white("Please manually add the following to your App component:\n"));
300
- console.log(chalk3.dim(`import { CommentProvider, CommentOverlay, CommentDrawer } from 'hale-commenting-system';
325
+ console.log(chalk3.dim(`import { CommentProvider, CommentOverlay, CommentDrawer, VersionProvider } from 'hale-commenting-system';
301
326
  import { BrowserRouter as Router } from 'react-router-dom';
302
327
  import React from 'react';
303
328
 
@@ -306,18 +331,20 @@ function App() {
306
331
 
307
332
  return (
308
333
  <Router>
309
- <CommentProvider>
310
- <CommentDrawer
311
- selectedThreadId={selectedThreadId}
312
- onThreadSelect={setSelectedThreadId}
313
- >
314
- <CommentOverlay
334
+ <VersionProvider>
335
+ <CommentProvider>
336
+ <CommentDrawer
315
337
  selectedThreadId={selectedThreadId}
316
338
  onThreadSelect={setSelectedThreadId}
317
- />
318
- {/* Your app content */}
319
- </CommentDrawer>
320
- </CommentProvider>
339
+ >
340
+ <CommentOverlay
341
+ selectedThreadId={selectedThreadId}
342
+ onThreadSelect={setSelectedThreadId}
343
+ />
344
+ {/* Your app content */}
345
+ </CommentDrawer>
346
+ </CommentProvider>
347
+ </VersionProvider>
321
348
  </Router>
322
349
  );
323
350
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/utils/detect.ts","../src/utils/logger.ts","../src/generators/code.ts","../src/utils/fs.ts"],"sourcesContent":["import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { initCommand } from './commands/init.js';\n\nconst program = new Command();\n\nprogram\n .name('hale-commenting-system')\n .description('Hale Commenting System CLI - Local setup wizard')\n .version('2.0.0');\n\nprogram\n .command('init')\n .description('Initialize Hale Commenting System in your project')\n .option('-y, --yes', 'Skip prompts and use defaults')\n .action(async (options) => {\n try {\n await initCommand(options);\n } catch (error: any) {\n console.error(chalk.red('\\n✗ Error:'), error.message);\n process.exit(1);\n }\n });\n\n// Show help if no command provided\nif (!process.argv.slice(2).length) {\n program.help();\n}\n\nprogram.parse();\n","import chalk from 'chalk';\nimport ora from 'ora';\nimport inquirer from 'inquirer';\nimport { detectProject } from '../utils/detect.js';\nimport { printWelcome, printWarning } from '../utils/logger.js';\nimport { integrateProviders, showIntegrationDiff } from '../generators/code.js';\n\ninterface InitOptions {\n yes?: boolean;\n}\n\nexport async function initCommand(options: InitOptions) {\n printWelcome();\n\n const spinner = ora('Detecting project...').start();\n\n // Step 1: Detect project type\n let project;\n try {\n project = await detectProject(process.cwd());\n spinner.succeed(`Detected: ${project.framework} with ${project.buildTool}`);\n } catch (error: any) {\n spinner.fail(error.message);\n process.exit(1);\n }\n\n if (!project.isReact) {\n spinner.fail('This package requires a React project');\n console.log(chalk.red('\\n✗ Hale Commenting System requires React.\\n'));\n process.exit(1);\n }\n\n if (!project.hasPatternFly) {\n printWarning('PatternFly not detected. This package is optimized for PatternFly projects.');\n if (!options.yes) {\n const { continueAnyway } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'continueAnyway',\n message: 'Continue anyway?',\n default: false\n }\n ]);\n if (!continueAnyway) {\n console.log(chalk.dim('\\nSetup cancelled.\\n'));\n process.exit(0);\n }\n }\n }\n\n // Step 2: Auto-integrate providers\n console.log(chalk.cyan('\\n📦 Setting up local commenting system...\\n'));\n \n spinner.start('Integrating commenting system into your app...');\n const result = await integrateProviders(project.root);\n \n if (result.success) {\n spinner.succeed('Commenting system integrated!');\n showIntegrationDiff(result.filePath);\n console.log(chalk.green('\\n✓ Setup complete! Your app is ready to use the commenting system.\\n'));\n console.log(chalk.cyan('Next steps:'));\n console.log(chalk.white('1. Review the changes in your App file'));\n console.log(chalk.white('2. Start your dev server (e.g., npm run start:dev)'));\n console.log(chalk.white('3. Open your app in the browser'));\n console.log(chalk.white('4. Click anywhere to add comments (stored in localStorage)\\n'));\n console.log(chalk.dim('💡 Tip: Comments persist across page refreshes and are stored locally in your browser.\\n'));\n } else {\n spinner.warn(result.message);\n console.log(chalk.yellow('\\n⚠️ Could not automatically integrate the commenting system.\\n'));\n console.log(chalk.white('Please manually add the following to your App component:\\n'));\n console.log(chalk.dim(`import { CommentProvider, CommentOverlay, CommentDrawer } from 'hale-commenting-system';\nimport { BrowserRouter as Router } from 'react-router-dom';\nimport React from 'react';\n\nfunction App() {\n const [selectedThreadId, setSelectedThreadId] = React.useState<string | null>(null);\n\n return (\n <Router>\n <CommentProvider>\n <CommentDrawer \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n >\n <CommentOverlay \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n />\n {/* Your app content */}\n </CommentDrawer>\n </CommentProvider>\n </Router>\n );\n}\\n`));\n }\n}\n","import fs from 'fs/promises';\nimport path from 'path';\n\nexport interface ProjectInfo {\n root: string;\n framework: string;\n buildTool: string;\n isReact: boolean;\n hasPatternFly: boolean;\n hasTypeScript: boolean;\n packageJson: any;\n}\n\nexport async function detectProject(cwd: string): Promise<ProjectInfo> {\n const packageJsonPath = path.join(cwd, 'package.json');\n \n let packageJson: any = {};\n try {\n const content = await fs.readFile(packageJsonPath, 'utf-8');\n packageJson = JSON.parse(content);\n } catch (error) {\n throw new Error('No package.json found. Are you in a Node.js project?');\n }\n\n const deps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies\n };\n\n const buildTool = await detectBuildTool(cwd, deps);\n\n return {\n root: cwd,\n framework: detectFramework(deps),\n buildTool,\n isReact: !!deps['react'],\n hasPatternFly: !!deps['@patternfly/react-core'],\n hasTypeScript: !!deps['typescript'],\n packageJson\n };\n}\n\nfunction detectFramework(deps: any): string {\n if (deps['react']) return 'React';\n if (deps['vue']) return 'Vue';\n if (deps['@angular/core']) return 'Angular';\n return 'Unknown';\n}\n\nasync function detectBuildTool(cwd: string, deps: any): Promise<string> {\n if (deps['vite']) return 'Vite';\n if (deps['webpack']) return 'Webpack';\n \n try {\n await fs.access(path.join(cwd, 'next.config.js'));\n return 'Next.js';\n } catch {\n // Next.js config not found\n }\n\n return 'Unknown';\n}\n\nexport async function detectPlatform(cwd: string): Promise<string | null> {\n try {\n await fs.access(path.join(cwd, 'vercel.json'));\n return 'vercel';\n } catch {\n // Not Vercel\n }\n\n try {\n await fs.access(path.join(cwd, 'netlify.toml'));\n return 'netlify';\n } catch {\n // Not Netlify\n }\n\n return null;\n}\n\n","import chalk from 'chalk';\n\nexport function printWelcome() {\n console.log(chalk.bold.cyan('\\n🚀 Hale Commenting System - Local Setup\\n'));\n console.log(chalk.dim('Setting up a localStorage-based commenting system for your app.\\n'));\n}\n\nexport function printWarning(message: string) {\n console.log(chalk.yellow(`⚠️ ${message}`));\n}\n","import path from 'path';\nimport chalk from 'chalk';\nimport { readFile, writeFile, fileExists } from '../utils/fs.js';\n\ninterface IntegrationResult {\n success: boolean;\n filePath: string;\n message: string;\n}\n\nexport async function integrateProviders(projectRoot: string): Promise<IntegrationResult> {\n // Find the App entry point - try common locations\n const possiblePaths = [\n 'src/app/index.tsx',\n 'src/app/App.tsx',\n 'src/App.tsx',\n 'src/index.tsx'\n ];\n\n let appFilePath: string | null = null;\n \n for (const p of possiblePaths) {\n const fullPath = path.join(projectRoot, p);\n if (await fileExists(fullPath)) {\n appFilePath = fullPath;\n break;\n }\n }\n\n if (!appFilePath) {\n return {\n success: false,\n filePath: '',\n message: 'Could not find App entry point. Please integrate manually.'\n };\n }\n\n try {\n const content = await readFile(appFilePath);\n \n // Check if already integrated\n if (content.includes('hale-commenting-system') || content.includes('CommentProvider')) {\n return {\n success: false,\n filePath: appFilePath,\n message: 'Commenting system already integrated.'\n };\n }\n\n const modifiedContent = injectProviders(content);\n \n if (modifiedContent === content) {\n return {\n success: false,\n filePath: appFilePath,\n message: 'Could not automatically integrate. File structure not recognized.'\n };\n }\n\n await writeFile(appFilePath, modifiedContent);\n\n return {\n success: true,\n filePath: appFilePath,\n message: `Successfully integrated providers into ${path.relative(projectRoot, appFilePath)}`\n };\n } catch (error: any) {\n return {\n success: false,\n filePath: appFilePath,\n message: `Error: ${error.message}`\n };\n }\n}\n\nfunction injectProviders(content: string): string {\n // Add imports at the top (after existing imports)\n const imports = `import {\n CommentProvider,\n CommentOverlay,\n CommentDrawer\n} from 'hale-commenting-system';`;\n\n // Find the last import statement\n const importRegex = /import\\s+.*?from\\s+['\"].*?['\"];?/g;\n const matches = content.match(importRegex);\n \n if (!matches || matches.length === 0) {\n // No imports found, add at the beginning\n content = imports + '\\n\\n' + content;\n } else {\n const lastImport = matches[matches.length - 1];\n const lastImportIndex = content.lastIndexOf(lastImport);\n const insertPosition = lastImportIndex + lastImport.length;\n content = content.slice(0, insertPosition) + '\\n\\n' + imports + content.slice(insertPosition);\n }\n\n // Find the return statement with Router/App structure\n // Look for patterns like: return ( <Router> or return <Router>\n const returnMatch = content.match(/return\\s*\\(?[\\s\\n]*<(\\w+)/);\n \n if (!returnMatch) {\n return content; // Can't find return statement\n }\n\n const componentName = returnMatch[1]; // Router, Fragment, etc.\n \n // Find the closing tag\n const closingTag = `</${componentName}>`;\n const closingIndex = content.indexOf(closingTag);\n \n if (closingIndex === -1) {\n return content; // Can't find closing tag\n }\n\n // Add state hook before return\n const stateHook = ` const [selectedThreadId, setSelectedThreadId] = React.useState<string | null>(null);\\n\\n`;\n \n // Find the function body (after function declaration)\n const functionMatch = content.match(/const\\s+\\w+.*?=.*?\\(\\).*?=>\\s*\\{/);\n if (functionMatch) {\n const insertPos = functionMatch.index! + functionMatch[0].length;\n content = content.slice(0, insertPos) + '\\n' + stateHook + content.slice(insertPos);\n }\n\n // Wrap the return content with providers\n const returnStartMatch = content.match(/return\\s*\\(/);\n if (returnStartMatch) {\n const returnStart = returnStartMatch.index! + returnStartMatch[0].length;\n const returnEnd = content.indexOf(closingTag, returnStart) + closingTag.length;\n \n const originalReturn = content.slice(returnStart, returnEnd).trim();\n \n // Check if the original return starts with <Router> or <BrowserRouter>\n const isRouter = originalReturn.match(/^\\s*<(Router|BrowserRouter)/);\n \n let wrappedReturn;\n if (isRouter) {\n // Extract Router content - need to find the inner content\n const routerMatch = originalReturn.match(/<(Router|BrowserRouter)[^>]*>([\\s\\S]*)<\\/\\1>/);\n if (routerMatch) {\n const routerType = routerMatch[1];\n const innerContent = routerMatch[2];\n \n // Put Router on outside, CommentProvider inside\n wrappedReturn = `\n <${routerType}>\n <CommentProvider>\n <CommentDrawer \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n >\n <CommentOverlay \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n />\n ${innerContent.trim()}\n </CommentDrawer>\n </CommentProvider>\n </${routerType}>\n `;\n } else {\n // Fallback to wrapping everything\n wrappedReturn = `\n <CommentProvider>\n <CommentDrawer \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n >\n <CommentOverlay \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n />\n ${originalReturn}\n </CommentDrawer>\n </CommentProvider>\n `;\n }\n } else {\n // No router, wrap everything normally\n wrappedReturn = `\n <CommentProvider>\n <CommentDrawer \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n >\n <CommentOverlay \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n />\n ${originalReturn}\n </CommentDrawer>\n </CommentProvider>\n `;\n }\n \n content = content.slice(0, returnStart) + wrappedReturn + content.slice(returnEnd);\n }\n\n return content;\n}\n\nexport function showIntegrationDiff(filePath: string) {\n console.log(chalk.cyan('\\nChanges made to your App file:'));\n console.log(chalk.white('• Added commenting system imports'));\n console.log(chalk.white('• Added state hook for comment thread selection'));\n console.log(chalk.white('• Wrapped app with CommentProvider'));\n console.log(chalk.white('• Added CommentDrawer and CommentOverlay components\\n'));\n console.log(chalk.dim(`Modified: ${filePath}\\n`));\n}\n","import fs from 'fs/promises';\nimport path from 'path';\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function ensureDir(dirPath: string): Promise<void> {\n await fs.mkdir(dirPath, { recursive: true });\n}\n\nexport async function writeFileIfNotExists(filePath: string, content: string): Promise<boolean> {\n const exists = await fileExists(filePath);\n if (exists) {\n return false;\n }\n \n await fs.writeFile(filePath, content, 'utf-8');\n return true;\n}\n\nexport async function appendToFile(filePath: string, content: string): Promise<void> {\n await fs.appendFile(filePath, content, 'utf-8');\n}\n\nexport async function readFile(filePath: string): Promise<string> {\n return fs.readFile(filePath, 'utf-8');\n}\n\nexport async function writeFile(filePath: string, content: string): Promise<void> {\n await fs.writeFile(filePath, content, 'utf-8');\n}\n\nexport function getRelativePath(from: string, to: string): string {\n return path.relative(from, to);\n}\n\n"],"mappings":"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","names":["chalk","chalk","path","chalk","fs","fs","fs","path","chalk","chalk","chalk"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/utils/detect.ts","../src/utils/logger.ts","../src/generators/code.ts","../src/utils/fs.ts"],"sourcesContent":["import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { initCommand } from './commands/init.js';\n\nconst program = new Command();\n\nprogram\n .name('hale-commenting-system')\n .description('Hale Commenting System CLI - Local setup wizard')\n .version('2.0.0');\n\nprogram\n .command('init')\n .description('Initialize Hale Commenting System in your project')\n .option('-y, --yes', 'Skip prompts and use defaults')\n .action(async (options) => {\n try {\n await initCommand(options);\n } catch (error: any) {\n console.error(chalk.red('\\n✗ Error:'), error.message);\n process.exit(1);\n }\n });\n\n// Show help if no command provided\nif (!process.argv.slice(2).length) {\n program.help();\n}\n\nprogram.parse();\n","import chalk from 'chalk';\nimport ora from 'ora';\nimport inquirer from 'inquirer';\nimport { detectProject } from '../utils/detect.js';\nimport { printWelcome, printWarning } from '../utils/logger.js';\nimport { integrateProviders, showIntegrationDiff } from '../generators/code.js';\n\ninterface InitOptions {\n yes?: boolean;\n}\n\nexport async function initCommand(options: InitOptions) {\n printWelcome();\n\n const spinner = ora('Detecting project...').start();\n\n // Step 1: Detect project type\n let project;\n try {\n project = await detectProject(process.cwd());\n spinner.succeed(`Detected: ${project.framework} with ${project.buildTool}`);\n } catch (error: any) {\n spinner.fail(error.message);\n process.exit(1);\n }\n\n if (!project.isReact) {\n spinner.fail('This package requires a React project');\n console.log(chalk.red('\\n✗ Hale Commenting System requires React.\\n'));\n process.exit(1);\n }\n\n if (!project.hasPatternFly) {\n printWarning('PatternFly not detected. This package is optimized for PatternFly projects.');\n if (!options.yes) {\n const { continueAnyway } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'continueAnyway',\n message: 'Continue anyway?',\n default: false\n }\n ]);\n if (!continueAnyway) {\n console.log(chalk.dim('\\nSetup cancelled.\\n'));\n process.exit(0);\n }\n }\n }\n\n // Step 2: Auto-integrate providers\n console.log(chalk.cyan('\\n📦 Setting up local commenting system...\\n'));\n \n spinner.start('Integrating commenting system into your app...');\n const result = await integrateProviders(project.root);\n \n if (result.success) {\n spinner.succeed('Commenting system integrated!');\n showIntegrationDiff(result.filePath);\n console.log(chalk.green('\\n✓ Setup complete! Your app is ready to use the commenting system.\\n'));\n console.log(chalk.cyan('Next steps:'));\n console.log(chalk.white('1. Review the changes in your App file'));\n console.log(chalk.white('2. Start your dev server (e.g., npm run start:dev)'));\n console.log(chalk.white('3. Open your app in the browser'));\n console.log(chalk.white('4. Click anywhere to add comments (stored in localStorage)\\n'));\n console.log(chalk.dim('💡 Tip: Comments persist across page refreshes and are stored locally in your browser.\\n'));\n } else {\n spinner.warn(result.message);\n console.log(chalk.yellow('\\n⚠️ Could not automatically integrate the commenting system.\\n'));\n console.log(chalk.white('Please manually add the following to your App component:\\n'));\n console.log(chalk.dim(`import { CommentProvider, CommentOverlay, CommentDrawer, VersionProvider } from 'hale-commenting-system';\nimport { BrowserRouter as Router } from 'react-router-dom';\nimport React from 'react';\n\nfunction App() {\n const [selectedThreadId, setSelectedThreadId] = React.useState<string | null>(null);\n\n return (\n <Router>\n <VersionProvider>\n <CommentProvider>\n <CommentDrawer \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n >\n <CommentOverlay \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n />\n {/* Your app content */}\n </CommentDrawer>\n </CommentProvider>\n </VersionProvider>\n </Router>\n );\n}\\n`));\n }\n}\n","import fs from 'fs/promises';\nimport path from 'path';\n\nexport interface ProjectInfo {\n root: string;\n framework: string;\n buildTool: string;\n isReact: boolean;\n hasPatternFly: boolean;\n hasTypeScript: boolean;\n packageJson: any;\n}\n\nexport async function detectProject(cwd: string): Promise<ProjectInfo> {\n const packageJsonPath = path.join(cwd, 'package.json');\n \n let packageJson: any = {};\n try {\n const content = await fs.readFile(packageJsonPath, 'utf-8');\n packageJson = JSON.parse(content);\n } catch (error) {\n throw new Error('No package.json found. Are you in a Node.js project?');\n }\n\n const deps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies\n };\n\n const buildTool = await detectBuildTool(cwd, deps);\n\n return {\n root: cwd,\n framework: detectFramework(deps),\n buildTool,\n isReact: !!deps['react'],\n hasPatternFly: !!deps['@patternfly/react-core'],\n hasTypeScript: !!deps['typescript'],\n packageJson\n };\n}\n\nfunction detectFramework(deps: any): string {\n if (deps['react']) return 'React';\n if (deps['vue']) return 'Vue';\n if (deps['@angular/core']) return 'Angular';\n return 'Unknown';\n}\n\nasync function detectBuildTool(cwd: string, deps: any): Promise<string> {\n if (deps['vite']) return 'Vite';\n if (deps['webpack']) return 'Webpack';\n \n try {\n await fs.access(path.join(cwd, 'next.config.js'));\n return 'Next.js';\n } catch {\n // Next.js config not found\n }\n\n return 'Unknown';\n}\n\nexport async function detectPlatform(cwd: string): Promise<string | null> {\n try {\n await fs.access(path.join(cwd, 'vercel.json'));\n return 'vercel';\n } catch {\n // Not Vercel\n }\n\n try {\n await fs.access(path.join(cwd, 'netlify.toml'));\n return 'netlify';\n } catch {\n // Not Netlify\n }\n\n return null;\n}\n\n","import chalk from 'chalk';\n\nexport function printWelcome() {\n console.log(chalk.bold.cyan('\\n🚀 Hale Commenting System - Local Setup\\n'));\n console.log(chalk.dim('Setting up a localStorage-based commenting system for your app.\\n'));\n}\n\nexport function printWarning(message: string) {\n console.log(chalk.yellow(`⚠️ ${message}`));\n}\n","import path from 'path';\nimport chalk from 'chalk';\nimport { readFile, writeFile, fileExists } from '../utils/fs.js';\n\ninterface IntegrationResult {\n success: boolean;\n filePath: string;\n message: string;\n}\n\nexport async function integrateProviders(projectRoot: string): Promise<IntegrationResult> {\n // Find the App entry point - try common locations\n const possiblePaths = [\n 'src/app/index.tsx',\n 'src/app/App.tsx',\n 'src/App.tsx',\n 'src/index.tsx'\n ];\n\n let appFilePath: string | null = null;\n \n for (const p of possiblePaths) {\n const fullPath = path.join(projectRoot, p);\n if (await fileExists(fullPath)) {\n appFilePath = fullPath;\n break;\n }\n }\n\n if (!appFilePath) {\n return {\n success: false,\n filePath: '',\n message: 'Could not find App entry point. Please integrate manually.'\n };\n }\n\n try {\n const content = await readFile(appFilePath);\n \n // Check if already integrated\n if (content.includes('hale-commenting-system') || content.includes('CommentProvider')) {\n return {\n success: false,\n filePath: appFilePath,\n message: 'Commenting system already integrated.'\n };\n }\n\n const modifiedContent = injectProviders(content);\n \n if (modifiedContent === content) {\n return {\n success: false,\n filePath: appFilePath,\n message: 'Could not automatically integrate. File structure not recognized.'\n };\n }\n\n await writeFile(appFilePath, modifiedContent);\n\n return {\n success: true,\n filePath: appFilePath,\n message: `Successfully integrated providers into ${path.relative(projectRoot, appFilePath)}`\n };\n } catch (error: any) {\n return {\n success: false,\n filePath: appFilePath,\n message: `Error: ${error.message}`\n };\n }\n}\n\nfunction injectProviders(content: string): string {\n // Add imports at the top (after existing imports)\n const imports = `import {\n CommentProvider,\n CommentOverlay,\n CommentDrawer,\n useComments,\n VersionProvider\n} from 'hale-commenting-system';`;\n\n // Find the last import statement\n const importRegex = /import\\s+.*?from\\s+['\"].*?['\"];?/g;\n const matches = content.match(importRegex);\n \n if (!matches || matches.length === 0) {\n // No imports found, add at the beginning\n content = imports + '\\n\\n' + content;\n } else {\n const lastImport = matches[matches.length - 1];\n const lastImportIndex = content.lastIndexOf(lastImport);\n const insertPosition = lastImportIndex + lastImport.length;\n content = content.slice(0, insertPosition) + '\\n\\n' + imports + content.slice(insertPosition);\n }\n\n // Find the JSX in the component - handle both explicit return and implicit arrow return\n // Pattern 1: return ( <Router> or return <Router>\n // Pattern 2: => ( <Router> (implicit return)\n let returnMatch = content.match(/return\\s*\\(?[\\s\\n]*<(\\w+)/);\n let isImplicitReturn = false;\n \n if (!returnMatch) {\n // Try to match implicit arrow function return: => ( <Component>\n returnMatch = content.match(/=>\\s*\\(?[\\s\\n]*<(\\w+)/);\n isImplicitReturn = true;\n }\n \n if (!returnMatch) {\n return content; // Can't find return statement or JSX\n }\n\n const componentName = returnMatch[1]; // Router, Fragment, etc.\n \n // Find the closing tag\n const closingTag = `</${componentName}>`;\n const closingIndex = content.indexOf(closingTag);\n \n if (closingIndex === -1) {\n return content; // Can't find closing tag\n }\n\n // Convert implicit return to explicit return if needed\n if (isImplicitReturn) {\n // Find the arrow function: const App = () => (\n const arrowMatch = content.match(/(const\\s+\\w+.*?=.*?\\(\\).*?=>\\s*)\\(/);\n if (arrowMatch) {\n const beforeParen = arrowMatch[1];\n const arrowEndPos = arrowMatch.index! + arrowMatch[0].length - 1; // Position before the (\n \n // Find the closing paren + semicolon\n const closingParenPos = content.indexOf(');', closingIndex);\n if (closingParenPos !== -1) {\n // Convert: const App = () => (...) to const App = () => { return (...) }\n const jsxContent = content.slice(arrowEndPos + 1, closingParenPos);\n content = content.slice(0, arrowEndPos) + ' {\\n return' + jsxContent + '\\n}' + content.slice(closingParenPos + 2);\n }\n }\n }\n\n // Add state hook before return\n const stateHook = ` const [selectedThreadId, setSelectedThreadId] = React.useState<string | null>(null);\\n\\n`;\n \n // Find the function body (after function declaration) - now guaranteed to have braces\n const functionMatch = content.match(/const\\s+\\w+.*?=.*?\\(\\).*?=>\\s*\\{/);\n if (functionMatch) {\n const insertPos = functionMatch.index! + functionMatch[0].length;\n content = content.slice(0, insertPos) + '\\n' + stateHook + content.slice(insertPos);\n }\n\n // Wrap the return content with providers\n const returnStartMatch = content.match(/return\\s*\\(?[\\s\\n]*</);\n if (returnStartMatch) {\n const returnStart = returnStartMatch.index! + returnStartMatch[0].length - 1; // Position before <\n const returnEnd = content.indexOf(closingTag, returnStart) + closingTag.length;\n \n const originalReturn = content.slice(returnStart, returnEnd).trim();\n \n // Check if the original return starts with <Router> or <BrowserRouter>\n const isRouter = originalReturn.match(/^\\s*<(Router|BrowserRouter)/);\n \n let wrappedReturn;\n if (isRouter) {\n // Extract Router content - need to find the inner content\n const routerMatch = originalReturn.match(/<(Router|BrowserRouter)[^>]*>([\\s\\S]*)<\\/\\1>/);\n if (routerMatch) {\n const routerType = routerMatch[1];\n const innerContent = routerMatch[2];\n \n // Put Router on outside, VersionProvider and CommentProvider inside\n wrappedReturn = `\n <${routerType}>\n <VersionProvider>\n <CommentProvider>\n <CommentDrawer \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n >\n <CommentOverlay \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n />\n ${innerContent.trim()}\n </CommentDrawer>\n </CommentProvider>\n </VersionProvider>\n </${routerType}>\n `;\n } else {\n // Fallback to wrapping everything\n wrappedReturn = `\n <VersionProvider>\n <CommentProvider>\n <CommentDrawer \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n >\n <CommentOverlay \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n />\n ${originalReturn}\n </CommentDrawer>\n </CommentProvider>\n </VersionProvider>\n `;\n }\n } else {\n // No router, wrap everything normally\n wrappedReturn = `\n <VersionProvider>\n <CommentProvider>\n <CommentDrawer \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n >\n <CommentOverlay \n selectedThreadId={selectedThreadId} \n onThreadSelect={setSelectedThreadId}\n />\n ${originalReturn}\n </CommentDrawer>\n </CommentProvider>\n </VersionProvider>\n `;\n }\n \n content = content.slice(0, returnStart) + wrappedReturn + content.slice(returnEnd);\n }\n\n return content;\n}\n\nexport function showIntegrationDiff(filePath: string) {\n console.log(chalk.cyan('\\nChanges made to your App file:'));\n console.log(chalk.white('• Added commenting system imports'));\n console.log(chalk.white('• Added state hook for comment thread selection'));\n console.log(chalk.white('• Wrapped app with CommentProvider'));\n console.log(chalk.white('• Added CommentDrawer and CommentOverlay components\\n'));\n console.log(chalk.dim(`Modified: ${filePath}\\n`));\n}\n","import fs from 'fs/promises';\nimport path from 'path';\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function ensureDir(dirPath: string): Promise<void> {\n await fs.mkdir(dirPath, { recursive: true });\n}\n\nexport async function writeFileIfNotExists(filePath: string, content: string): Promise<boolean> {\n const exists = await fileExists(filePath);\n if (exists) {\n return false;\n }\n \n await fs.writeFile(filePath, content, 'utf-8');\n return true;\n}\n\nexport async function appendToFile(filePath: string, content: string): Promise<void> {\n await fs.appendFile(filePath, content, 'utf-8');\n}\n\nexport async function readFile(filePath: string): Promise<string> {\n return fs.readFile(filePath, 'utf-8');\n}\n\nexport async function writeFile(filePath: string, content: string): Promise<void> {\n await fs.writeFile(filePath, content, 'utf-8');\n}\n\nexport function getRelativePath(from: string, to: string): string {\n return path.relative(from, to);\n}\n\n"],"mappings":"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","names":["chalk","chalk","path","chalk","fs","fs","fs","path","chalk","chalk","chalk"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hale-commenting-system",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Local-first commenting system for React applications with localStorage persistence",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",