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 +14 -11
- package/cli/dist/index.js +69 -42
- package/cli/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
<
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
onThreadSelect={setSelectedThreadId}
|
|
88
|
-
>
|
|
89
|
-
<CommentOverlay
|
|
85
|
+
<VersionProvider>
|
|
86
|
+
<CommentProvider>
|
|
87
|
+
<CommentDrawer
|
|
90
88
|
selectedThreadId={selectedThreadId}
|
|
91
89
|
onThreadSelect={setSelectedThreadId}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
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
|
-
${
|
|
236
|
+
${originalReturn}
|
|
199
237
|
</CommentDrawer>
|
|
200
238
|
</CommentProvider>
|
|
201
|
-
|
|
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
|
-
<
|
|
222
|
-
<
|
|
223
|
-
|
|
224
|
-
onThreadSelect={setSelectedThreadId}
|
|
225
|
-
>
|
|
226
|
-
<CommentOverlay
|
|
244
|
+
<VersionProvider>
|
|
245
|
+
<CommentProvider>
|
|
246
|
+
<CommentDrawer
|
|
227
247
|
selectedThreadId={selectedThreadId}
|
|
228
248
|
onThreadSelect={setSelectedThreadId}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
-
<
|
|
310
|
-
<
|
|
311
|
-
|
|
312
|
-
onThreadSelect={setSelectedThreadId}
|
|
313
|
-
>
|
|
314
|
-
<CommentOverlay
|
|
334
|
+
<VersionProvider>
|
|
335
|
+
<CommentProvider>
|
|
336
|
+
<CommentDrawer
|
|
315
337
|
selectedThreadId={selectedThreadId}
|
|
316
338
|
onThreadSelect={setSelectedThreadId}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
}
|
package/cli/dist/index.js.map
CHANGED
|
@@ -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":";;;AAAA,SAAS,eAAe;AACxB,OAAOA,YAAW;;;ACDlB,OAAOC,YAAW;AAClB,OAAO,SAAS;AAChB,OAAO,cAAc;;;ACFrB,OAAO,QAAQ;AACf,OAAO,UAAU;AAYjB,eAAsB,cAAc,KAAmC;AACrE,QAAM,kBAAkB,KAAK,KAAK,KAAK,cAAc;AAErD,MAAI,cAAmB,CAAC;AACxB,MAAI;AACF,UAAM,UAAU,MAAM,GAAG,SAAS,iBAAiB,OAAO;AAC1D,kBAAc,KAAK,MAAM,OAAO;AAAA,EAClC,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AAEA,QAAM,OAAO;AAAA,IACX,GAAG,YAAY;AAAA,IACf,GAAG,YAAY;AAAA,EACjB;AAEA,QAAM,YAAY,MAAM,gBAAgB,KAAK,IAAI;AAEjD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,WAAW,gBAAgB,IAAI;AAAA,IAC/B;AAAA,IACA,SAAS,CAAC,CAAC,KAAK,OAAO;AAAA,IACvB,eAAe,CAAC,CAAC,KAAK,wBAAwB;AAAA,IAC9C,eAAe,CAAC,CAAC,KAAK,YAAY;AAAA,IAClC;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,MAAmB;AAC1C,MAAI,KAAK,OAAO,EAAG,QAAO;AAC1B,MAAI,KAAK,KAAK,EAAG,QAAO;AACxB,MAAI,KAAK,eAAe,EAAG,QAAO;AAClC,SAAO;AACT;AAEA,eAAe,gBAAgB,KAAa,MAA4B;AACtE,MAAI,KAAK,MAAM,EAAG,QAAO;AACzB,MAAI,KAAK,SAAS,EAAG,QAAO;AAE5B,MAAI;AACF,UAAM,GAAG,OAAO,KAAK,KAAK,KAAK,gBAAgB,CAAC;AAChD,WAAO;AAAA,EACT,QAAQ;AAAA,EAER;AAEA,SAAO;AACT;;;AC7DA,OAAO,WAAW;AAEX,SAAS,eAAe;AAC7B,UAAQ,IAAI,MAAM,KAAK,KAAK,oDAA6C,CAAC;AAC1E,UAAQ,IAAI,MAAM,IAAI,mEAAmE,CAAC;AAC5F;AAEO,SAAS,aAAa,SAAiB;AAC5C,UAAQ,IAAI,MAAM,OAAO,iBAAO,OAAO,EAAE,CAAC;AAC5C;;;ACTA,OAAOC,WAAU;AACjB,OAAOC,YAAW;;;ACDlB,OAAOC,SAAQ;AAGf,eAAsB,WAAW,UAAoC;AACnE,MAAI;AACF,UAAMC,IAAG,OAAO,QAAQ;AACxB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAoBA,eAAsB,SAAS,UAAmC;AAChE,SAAOC,IAAG,SAAS,UAAU,OAAO;AACtC;AAEA,eAAsB,UAAU,UAAkB,SAAgC;AAChF,QAAMA,IAAG,UAAU,UAAU,SAAS,OAAO;AAC/C;;;AD1BA,eAAsB,mBAAmB,aAAiD;AAExF,QAAM,gBAAgB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,cAA6B;AAEjC,aAAW,KAAK,eAAe;AAC7B,UAAM,WAAWC,MAAK,KAAK,aAAa,CAAC;AACzC,QAAI,MAAM,WAAW,QAAQ,GAAG;AAC9B,oBAAc;AACd;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AAAA,EACF;AAEA,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,WAAW;AAG1C,QAAI,QAAQ,SAAS,wBAAwB,KAAK,QAAQ,SAAS,iBAAiB,GAAG;AACrF,aAAO;AAAA,QACL,SAAS;AAAA,QACT,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,IACF;AAEA,UAAM,kBAAkB,gBAAgB,OAAO;AAE/C,QAAI,oBAAoB,SAAS;AAC/B,aAAO;AAAA,QACL,SAAS;AAAA,QACT,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,IACF;AAEA,UAAM,UAAU,aAAa,eAAe;AAE5C,WAAO;AAAA,MACL,SAAS;AAAA,MACT,UAAU;AAAA,MACV,SAAS,0CAA0CA,MAAK,SAAS,aAAa,WAAW,CAAC;AAAA,IAC5F;AAAA,EACF,SAAS,OAAY;AACnB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,UAAU;AAAA,MACV,SAAS,UAAU,MAAM,OAAO;AAAA,IAClC;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,SAAyB;AAEhD,QAAM,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAShB,QAAM,cAAc;AACpB,QAAM,UAAU,QAAQ,MAAM,WAAW;AAEzC,MAAI,CAAC,WAAW,QAAQ,WAAW,GAAG;AAEpC,cAAU,UAAU,SAAS;AAAA,EAC/B,OAAO;AACL,UAAM,aAAa,QAAQ,QAAQ,SAAS,CAAC;AAC7C,UAAM,kBAAkB,QAAQ,YAAY,UAAU;AACtD,UAAM,iBAAiB,kBAAkB,WAAW;AACpD,cAAU,QAAQ,MAAM,GAAG,cAAc,IAAI,SAAS,UAAU,QAAQ,MAAM,cAAc;AAAA,EAC9F;AAKA,MAAI,cAAc,QAAQ,MAAM,2BAA2B;AAC3D,MAAI,mBAAmB;AAEvB,MAAI,CAAC,aAAa;AAEhB,kBAAc,QAAQ,MAAM,uBAAuB;AACnD,uBAAmB;AAAA,EACrB;AAEA,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,YAAY,CAAC;AAGnC,QAAM,aAAa,KAAK,aAAa;AACrC,QAAM,eAAe,QAAQ,QAAQ,UAAU;AAE/C,MAAI,iBAAiB,IAAI;AACvB,WAAO;AAAA,EACT;AAGA,MAAI,kBAAkB;AAEpB,UAAM,aAAa,QAAQ,MAAM,oCAAoC;AACrE,QAAI,YAAY;AACd,YAAM,cAAc,WAAW,CAAC;AAChC,YAAM,cAAc,WAAW,QAAS,WAAW,CAAC,EAAE,SAAS;AAG/D,YAAM,kBAAkB,QAAQ,QAAQ,MAAM,YAAY;AAC1D,UAAI,oBAAoB,IAAI;AAE1B,cAAM,aAAa,QAAQ,MAAM,cAAc,GAAG,eAAe;AACjE,kBAAU,QAAQ,MAAM,GAAG,WAAW,IAAI,iBAAiB,aAAa,QAAQ,QAAQ,MAAM,kBAAkB,CAAC;AAAA,MACnH;AAAA,IACF;AAAA,EACF;AAGA,QAAM,YAAY;AAAA;AAAA;AAGlB,QAAM,gBAAgB,QAAQ,MAAM,kCAAkC;AACtE,MAAI,eAAe;AACjB,UAAM,YAAY,cAAc,QAAS,cAAc,CAAC,EAAE;AAC1D,cAAU,QAAQ,MAAM,GAAG,SAAS,IAAI,OAAO,YAAY,QAAQ,MAAM,SAAS;AAAA,EACpF;AAGA,QAAM,mBAAmB,QAAQ,MAAM,sBAAsB;AAC7D,MAAI,kBAAkB;AACpB,UAAM,cAAc,iBAAiB,QAAS,iBAAiB,CAAC,EAAE,SAAS;AAC3E,UAAM,YAAY,QAAQ,QAAQ,YAAY,WAAW,IAAI,WAAW;AAExE,UAAM,iBAAiB,QAAQ,MAAM,aAAa,SAAS,EAAE,KAAK;AAGlE,UAAM,WAAW,eAAe,MAAM,6BAA6B;AAEnE,QAAI;AACJ,QAAI,UAAU;AAEZ,YAAM,cAAc,eAAe,MAAM,8CAA8C;AACvF,UAAI,aAAa;AACf,cAAM,aAAa,YAAY,CAAC;AAChC,cAAM,eAAe,YAAY,CAAC;AAGlC,wBAAgB;AAAA,OACjB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAWH,aAAa,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA,QAIzB,UAAU;AAAA;AAAA,MAEZ,OAAO;AAEL,wBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAWZ,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA,MAKpB;AAAA,IACF,OAAO;AAEL,sBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAWV,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA,IAKtB;AAEA,cAAU,QAAQ,MAAM,GAAG,WAAW,IAAI,gBAAgB,QAAQ,MAAM,SAAS;AAAA,EACnF;AAEA,SAAO;AACT;AAEO,SAAS,oBAAoB,UAAkB;AACpD,UAAQ,IAAIC,OAAM,KAAK,kCAAkC,CAAC;AAC1D,UAAQ,IAAIA,OAAM,MAAM,wCAAmC,CAAC;AAC5D,UAAQ,IAAIA,OAAM,MAAM,sDAAiD,CAAC;AAC1E,UAAQ,IAAIA,OAAM,MAAM,yCAAoC,CAAC;AAC7D,UAAQ,IAAIA,OAAM,MAAM,4DAAuD,CAAC;AAChF,UAAQ,IAAIA,OAAM,IAAI,aAAa,QAAQ;AAAA,CAAI,CAAC;AAClD;;;AHxOA,eAAsB,YAAY,SAAsB;AACtD,eAAa;AAEb,QAAM,UAAU,IAAI,sBAAsB,EAAE,MAAM;AAGlD,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,cAAc,QAAQ,IAAI,CAAC;AAC3C,YAAQ,QAAQ,aAAa,QAAQ,SAAS,SAAS,QAAQ,SAAS,EAAE;AAAA,EAC5E,SAAS,OAAY;AACnB,YAAQ,KAAK,MAAM,OAAO;AAC1B,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,CAAC,QAAQ,SAAS;AACpB,YAAQ,KAAK,uCAAuC;AACpD,YAAQ,IAAIC,OAAM,IAAI,mDAA8C,CAAC;AACrE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,CAAC,QAAQ,eAAe;AAC1B,iBAAa,6EAA6E;AAC1F,QAAI,CAAC,QAAQ,KAAK;AAChB,YAAM,EAAE,eAAe,IAAI,MAAM,SAAS,OAAO;AAAA,QAC/C;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS;AAAA,QACX;AAAA,MACF,CAAC;AACD,UAAI,CAAC,gBAAgB;AACnB,gBAAQ,IAAIA,OAAM,IAAI,sBAAsB,CAAC;AAC7C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAGA,UAAQ,IAAIA,OAAM,KAAK,qDAA8C,CAAC;AAEtE,UAAQ,MAAM,gDAAgD;AAC9D,QAAM,SAAS,MAAM,mBAAmB,QAAQ,IAAI;AAEpD,MAAI,OAAO,SAAS;AAClB,YAAQ,QAAQ,+BAA+B;AAC/C,wBAAoB,OAAO,QAAQ;AACnC,YAAQ,IAAIA,OAAM,MAAM,4EAAuE,CAAC;AAChG,YAAQ,IAAIA,OAAM,KAAK,aAAa,CAAC;AACrC,YAAQ,IAAIA,OAAM,MAAM,wCAAwC,CAAC;AACjE,YAAQ,IAAIA,OAAM,MAAM,oDAAoD,CAAC;AAC7E,YAAQ,IAAIA,OAAM,MAAM,iCAAiC,CAAC;AAC1D,YAAQ,IAAIA,OAAM,MAAM,8DAA8D,CAAC;AACvF,YAAQ,IAAIA,OAAM,IAAI,iGAA0F,CAAC;AAAA,EACnH,OAAO;AACL,YAAQ,KAAK,OAAO,OAAO;AAC3B,YAAQ,IAAIA,OAAM,OAAO,4EAAkE,CAAC;AAC5F,YAAQ,IAAIA,OAAM,MAAM,4DAA4D,CAAC;AACrF,YAAQ,IAAIA,OAAM,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAyBtB,CAAC;AAAA,EACH;AACF;;;AD7FA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,wBAAwB,EAC7B,YAAY,iDAAiD,EAC7D,QAAQ,OAAO;AAElB,QACG,QAAQ,MAAM,EACd,YAAY,mDAAmD,EAC/D,OAAO,aAAa,+BAA+B,EACnD,OAAO,OAAO,YAAY;AACzB,MAAI;AACF,UAAM,YAAY,OAAO;AAAA,EAC3B,SAAS,OAAY;AACnB,YAAQ,MAAMC,OAAM,IAAI,iBAAY,GAAG,MAAM,OAAO;AACpD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAGH,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE,QAAQ;AACjC,UAAQ,KAAK;AACf;AAEA,QAAQ,MAAM;","names":["chalk","chalk","path","chalk","fs","fs","fs","path","chalk","chalk","chalk"]}
|
package/package.json
CHANGED