@launch77/cli 1.7.2 → 1.7.3

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 (144) hide show
  1. package/dist/infrastructure/package-resolver.test.js +9 -7
  2. package/dist/infrastructure/package-resolver.test.js.map +1 -1
  3. package/dist/modules/app/commands/create-app.d.ts.map +1 -1
  4. package/dist/modules/app/commands/create-app.js +1 -1
  5. package/dist/modules/app/commands/create-app.js.map +1 -1
  6. package/dist/modules/app/commands/delete-app.d.ts.map +1 -1
  7. package/dist/modules/app/commands/delete-app.js +1 -1
  8. package/dist/modules/app/commands/delete-app.js.map +1 -1
  9. package/dist/modules/app/lib/app-template-resolver.d.ts +1 -1
  10. package/dist/modules/app/lib/app-template-resolver.d.ts.map +1 -1
  11. package/dist/modules/app/lib/app-template-resolver.js +1 -1
  12. package/dist/modules/app/lib/app-template-resolver.js.map +1 -1
  13. package/dist/modules/app/services/app-svc.d.ts +1 -0
  14. package/dist/modules/app/services/app-svc.d.ts.map +1 -1
  15. package/dist/modules/app/services/app-svc.js +4 -4
  16. package/dist/modules/app/services/app-svc.js.map +1 -1
  17. package/dist/modules/app/services/manifest-svc.d.ts +1 -1
  18. package/dist/modules/app/services/manifest-svc.d.ts.map +1 -1
  19. package/dist/modules/catalog/commands/scan.d.ts.map +1 -1
  20. package/dist/modules/catalog/commands/scan.js +1 -1
  21. package/dist/modules/catalog/commands/scan.js.map +1 -1
  22. package/dist/modules/catalog/services/catalog-svc.d.ts.map +1 -1
  23. package/dist/modules/deploy/commands/deploy-init-action.js +1 -1
  24. package/dist/modules/deploy/commands/deploy-init-action.js.map +1 -1
  25. package/dist/modules/deploy/commands/deploy-logs-action.js +1 -1
  26. package/dist/modules/deploy/commands/deploy-logs-action.js.map +1 -1
  27. package/dist/modules/deploy/commands/deploy-status-action.js +1 -1
  28. package/dist/modules/deploy/commands/deploy-status-action.js.map +1 -1
  29. package/dist/modules/git/commands/git-connect.d.ts.map +1 -1
  30. package/dist/modules/git/commands/git-connect.js +3 -3
  31. package/dist/modules/git/commands/git-connect.js.map +1 -1
  32. package/dist/modules/library/commands/create-library.d.ts.map +1 -1
  33. package/dist/modules/library/commands/create-library.js +1 -1
  34. package/dist/modules/library/commands/create-library.js.map +1 -1
  35. package/dist/modules/library/commands/delete-library.d.ts.map +1 -1
  36. package/dist/modules/library/commands/delete-library.js +1 -1
  37. package/dist/modules/library/commands/delete-library.js.map +1 -1
  38. package/dist/modules/library/services/library-create-svc.js +1 -1
  39. package/dist/modules/library/services/library-create-svc.js.map +1 -1
  40. package/dist/modules/library/services/library-svc.d.ts +1 -0
  41. package/dist/modules/library/services/library-svc.d.ts.map +1 -1
  42. package/dist/modules/library/services/library-svc.js +3 -2
  43. package/dist/modules/library/services/library-svc.js.map +1 -1
  44. package/dist/modules/plugin/commands/delete-plugin.d.ts.map +1 -1
  45. package/dist/modules/plugin/commands/delete-plugin.js +1 -2
  46. package/dist/modules/plugin/commands/delete-plugin.js.map +1 -1
  47. package/dist/modules/plugin/commands/plugin-create.d.ts.map +1 -1
  48. package/dist/modules/plugin/commands/plugin-create.js +1 -1
  49. package/dist/modules/plugin/commands/plugin-create.js.map +1 -1
  50. package/dist/modules/plugin/commands/plugin-install.d.ts.map +1 -1
  51. package/dist/modules/plugin/commands/plugin-install.js +1 -2
  52. package/dist/modules/plugin/commands/plugin-install.js.map +1 -1
  53. package/dist/modules/plugin/index.d.ts +3 -3
  54. package/dist/modules/plugin/index.d.ts.map +1 -1
  55. package/dist/modules/plugin/index.js +2 -3
  56. package/dist/modules/plugin/index.js.map +1 -1
  57. package/dist/modules/plugin/lib/plugin-resolver.test.js +10 -6
  58. package/dist/modules/plugin/lib/plugin-resolver.test.js.map +1 -1
  59. package/dist/modules/plugin/services/plugin-create-service.d.ts +1 -0
  60. package/dist/modules/plugin/services/plugin-create-service.d.ts.map +1 -1
  61. package/dist/modules/plugin/services/plugin-create-service.js +4 -3
  62. package/dist/modules/plugin/services/plugin-create-service.js.map +1 -1
  63. package/dist/modules/plugin/services/plugin-svc.test.js +34 -30
  64. package/dist/modules/plugin/services/plugin-svc.test.js.map +1 -1
  65. package/dist/modules/release/commands/release-init.d.ts.map +1 -1
  66. package/dist/modules/release/commands/release-init.js +2 -2
  67. package/dist/modules/release/commands/release-init.js.map +1 -1
  68. package/dist/modules/release/services/release-service.d.ts.map +1 -1
  69. package/dist/modules/release/services/release-service.js +3 -3
  70. package/dist/modules/release/services/release-service.js.map +1 -1
  71. package/dist/modules/workspace/services/workspace-service.d.ts +1 -0
  72. package/dist/modules/workspace/services/workspace-service.d.ts.map +1 -1
  73. package/dist/modules/workspace/services/workspace-service.js +3 -2
  74. package/dist/modules/workspace/services/workspace-service.js.map +1 -1
  75. package/dist/templates/plugin/README.md.hbs +10 -0
  76. package/dist/templates/plugin/package.json.hbs +1 -1
  77. package/dist/templates/plugin/scripts/validate-plugin-json.js +13 -2
  78. package/dist/templates/workspace/.eslintignore +2 -1
  79. package/package.json +3 -3
  80. package/src/infrastructure/package-resolver.test.ts +9 -8
  81. package/src/modules/app/commands/create-app.ts +1 -1
  82. package/src/modules/app/commands/delete-app.ts +1 -1
  83. package/src/modules/app/lib/app-template-resolver.ts +1 -2
  84. package/src/modules/app/services/app-svc.ts +6 -7
  85. package/src/modules/app/services/manifest-svc.ts +1 -1
  86. package/src/modules/catalog/commands/scan.ts +1 -2
  87. package/src/modules/catalog/services/catalog-svc.ts +1 -1
  88. package/src/modules/deploy/commands/deploy-init-action.ts +1 -1
  89. package/src/modules/deploy/commands/deploy-logs-action.ts +1 -1
  90. package/src/modules/deploy/commands/deploy-status-action.ts +1 -1
  91. package/src/modules/git/commands/git-connect.ts +3 -3
  92. package/src/modules/library/commands/create-library.ts +1 -1
  93. package/src/modules/library/commands/delete-library.ts +1 -1
  94. package/src/modules/library/services/library-create-svc.ts +1 -1
  95. package/src/modules/library/services/library-svc.ts +3 -2
  96. package/src/modules/plugin/commands/delete-plugin.ts +1 -3
  97. package/src/modules/plugin/commands/plugin-create.ts +1 -1
  98. package/src/modules/plugin/commands/plugin-install.ts +1 -3
  99. package/src/modules/plugin/index.ts +4 -6
  100. package/src/modules/plugin/lib/plugin-resolver.test.ts +10 -7
  101. package/src/modules/plugin/services/plugin-create-service.ts +4 -3
  102. package/src/modules/plugin/services/plugin-svc.test.ts +52 -32
  103. package/src/modules/release/commands/release-init.ts +2 -2
  104. package/src/modules/release/services/release-service.ts +4 -3
  105. package/src/modules/workspace/services/workspace-service.ts +3 -2
  106. package/templates/plugin/README.md.hbs +10 -0
  107. package/templates/plugin/package.json.hbs +1 -1
  108. package/templates/plugin/scripts/validate-plugin-json.js +13 -2
  109. package/templates/workspace/.eslintignore +2 -1
  110. package/dist/infrastructure/npm-package.d.ts +0 -42
  111. package/dist/infrastructure/npm-package.d.ts.map +0 -1
  112. package/dist/infrastructure/npm-package.js +0 -46
  113. package/dist/infrastructure/npm-package.js.map +0 -1
  114. package/dist/infrastructure/npm.d.ts +0 -9
  115. package/dist/infrastructure/npm.d.ts.map +0 -1
  116. package/dist/infrastructure/npm.js +0 -17
  117. package/dist/infrastructure/npm.js.map +0 -1
  118. package/dist/infrastructure/package-resolver.d.ts +0 -117
  119. package/dist/infrastructure/package-resolver.d.ts.map +0 -1
  120. package/dist/infrastructure/package-resolver.js +0 -170
  121. package/dist/infrastructure/package-resolver.js.map +0 -1
  122. package/dist/modules/plugin/errors/plugin-errors.d.ts +0 -51
  123. package/dist/modules/plugin/errors/plugin-errors.d.ts.map +0 -1
  124. package/dist/modules/plugin/errors/plugin-errors.js +0 -130
  125. package/dist/modules/plugin/errors/plugin-errors.js.map +0 -1
  126. package/dist/modules/plugin/lib/plugin-resolver.d.ts +0 -14
  127. package/dist/modules/plugin/lib/plugin-resolver.d.ts.map +0 -1
  128. package/dist/modules/plugin/lib/plugin-resolver.js +0 -36
  129. package/dist/modules/plugin/lib/plugin-resolver.js.map +0 -1
  130. package/dist/modules/plugin/services/plugin-svc.d.ts +0 -42
  131. package/dist/modules/plugin/services/plugin-svc.d.ts.map +0 -1
  132. package/dist/modules/plugin/services/plugin-svc.js +0 -257
  133. package/dist/modules/plugin/services/plugin-svc.js.map +0 -1
  134. package/dist/modules/plugin/types/plugin-types.d.ts +0 -25
  135. package/dist/modules/plugin/types/plugin-types.d.ts.map +0 -1
  136. package/dist/modules/plugin/types/plugin-types.js +0 -2
  137. package/dist/modules/plugin/types/plugin-types.js.map +0 -1
  138. package/src/infrastructure/npm-package.ts +0 -73
  139. package/src/infrastructure/npm.ts +0 -18
  140. package/src/infrastructure/package-resolver.ts +0 -223
  141. package/src/modules/plugin/errors/plugin-errors.ts +0 -145
  142. package/src/modules/plugin/lib/plugin-resolver.ts +0 -41
  143. package/src/modules/plugin/services/plugin-svc.ts +0 -303
  144. package/src/modules/plugin/types/plugin-types.ts +0 -29
@@ -1,257 +0,0 @@
1
- import * as path from 'path';
2
- import * as fs from 'fs/promises';
3
- import chalk from 'chalk';
4
- import { execa } from 'execa';
5
- import fsExtra from 'fs-extra';
6
- import { readPluginMetadata } from '@launch77/plugin-runtime';
7
- import { downloadNpmPackage } from '../../../infrastructure/npm-package.js';
8
- import * as npm from '../../../infrastructure/npm.js';
9
- import { validateWorkspaceContext } from '../../../utils/launch77-validation.js';
10
- import { validateAppName } from '../../../utils/validation.js';
11
- import { PluginInstallationError, InvalidPluginContextError, createInvalidContextError, MissingPluginTargetsError, createInvalidTargetError, PluginResolutionError, PluginDirectoryNotFoundError, InvalidPluginNameError } from '../errors/plugin-errors.js';
12
- import { PluginResolver } from '../lib/plugin-resolver.js';
13
- /**
14
- * Map location type to target string
15
- */
16
- function locationTypeToTarget(locationType) {
17
- switch (locationType) {
18
- case 'workspace-app':
19
- return 'app';
20
- case 'workspace-library':
21
- return 'library';
22
- case 'workspace-plugin':
23
- return 'plugin';
24
- case 'workspace-app-template':
25
- return 'app-template';
26
- default:
27
- return null;
28
- }
29
- }
30
- export class PluginService {
31
- pluginResolver;
32
- constructor() {
33
- this.pluginResolver = new PluginResolver();
34
- }
35
- /**
36
- * Validate that we're in a valid package directory and return the target type
37
- */
38
- validateContext(context) {
39
- const currentTarget = locationTypeToTarget(context.locationType);
40
- if (!currentTarget)
41
- throw createInvalidContextError(context.locationType);
42
- if (!context.appName)
43
- throw new InvalidPluginContextError('Could not determine package name. This is a bug. Please report it.');
44
- return currentTarget;
45
- }
46
- /**
47
- * Validate plugin name, resolve its location, and download if needed
48
- */
49
- async validateAndResolvePlugin(pluginName, workspaceRoot, logger) {
50
- logger(chalk.blue(`\n🔍 Resolving plugin "${pluginName}"...`));
51
- logger(` ├─ Validating plugin name...`);
52
- const validation = this.pluginResolver.validateInput(pluginName);
53
- if (!validation.isValid) {
54
- throw new PluginResolutionError(pluginName, validation.error || 'Invalid plugin name');
55
- }
56
- logger(` │ └─ ${chalk.green('✓')} Valid plugin name`);
57
- logger(` ├─ Checking local workspace: ${chalk.dim(`plugins/${pluginName}`)}`);
58
- const resolution = await this.pluginResolver.resolveLocation(pluginName, workspaceRoot);
59
- let pluginPath;
60
- let version;
61
- if (resolution.source === 'local') {
62
- logger(` │ └─ ${chalk.green('✓')} Found local plugin`);
63
- pluginPath = resolution.localPath;
64
- version = resolution.version; // Local plugins always have version after verification
65
- }
66
- else {
67
- logger(` │ └─ ${chalk.dim('Not found locally')}`);
68
- logger(` ├─ Resolving to npm package: ${chalk.cyan(resolution.npmPackage)}`);
69
- pluginPath = await this.downloadNpmPlugin(resolution.npmPackage, workspaceRoot, logger);
70
- // Read version from downloaded package
71
- const packageJsonPath = path.join(pluginPath, 'package.json');
72
- const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
73
- const packageJson = JSON.parse(packageJsonContent);
74
- version = packageJson.version;
75
- }
76
- logger(` └─ ${chalk.green('✓')} Plugin resolved\n`);
77
- return {
78
- pluginPath,
79
- source: resolution.source,
80
- npmPackage: resolution.npmPackage,
81
- version,
82
- };
83
- }
84
- /**
85
- * Read plugin metadata and validate it supports the current target
86
- */
87
- async validatePluginTargets(pluginPath, pluginName, currentTarget) {
88
- const metadata = await readPluginMetadata(pluginPath);
89
- if (!metadata.targets || metadata.targets.length === 0) {
90
- throw new MissingPluginTargetsError(pluginName);
91
- }
92
- if (!metadata.targets.includes(currentTarget)) {
93
- throw createInvalidTargetError(pluginName, currentTarget, metadata.targets);
94
- }
95
- return metadata;
96
- }
97
- /**
98
- * Check if plugin is already installed and return early-exit result if so
99
- */
100
- async checkExistingInstallation(pluginName, packagePath, logger) {
101
- const existingInstallation = await this.isPluginInstalled(pluginName, packagePath);
102
- if (existingInstallation) {
103
- logger(chalk.yellow(`\nℹ️ Plugin '${pluginName}' is already installed in this package.\n`));
104
- logger(`Package: ${chalk.cyan(existingInstallation.package)} (${existingInstallation.source})`);
105
- logger(`Version: ${existingInstallation.version}`);
106
- logger(`Installed: ${existingInstallation.installedAt}\n`);
107
- logger(chalk.gray('To reinstall: Remove from package.json launch77.installedPlugins'));
108
- logger(chalk.gray('(plugin:remove command coming soon)\n'));
109
- return {
110
- pluginName,
111
- filesInstalled: false,
112
- packageJsonUpdated: false,
113
- dependenciesInstalled: false,
114
- };
115
- }
116
- return null;
117
- }
118
- /**
119
- * Install a plugin to the current package
120
- */
121
- async installPlugin(request, context, logger = console.log) {
122
- const { pluginName } = request;
123
- const currentTarget = this.validateContext(context);
124
- const { pluginPath, source, npmPackage, version } = await this.validateAndResolvePlugin(pluginName, context.workspaceRoot, logger);
125
- const metadata = await this.validatePluginTargets(pluginPath, pluginName, currentTarget);
126
- const packagePath = this.getPackagePath(context);
127
- const earlyExit = await this.checkExistingInstallation(pluginName, packagePath, logger);
128
- if (earlyExit)
129
- return earlyExit;
130
- await this.runGenerator(pluginPath, packagePath, context);
131
- const packageName = source === 'npm' ? npmPackage : pluginName;
132
- await this.writePluginManifest(packagePath, {
133
- pluginName,
134
- packageName,
135
- version,
136
- source,
137
- });
138
- return {
139
- pluginName,
140
- filesInstalled: true,
141
- packageJsonUpdated: true,
142
- dependenciesInstalled: true,
143
- };
144
- }
145
- /**
146
- * Download and install an npm plugin package
147
- */
148
- async downloadNpmPlugin(npmPackage, workspaceRoot, logger) {
149
- logger(` └─ Installing from npm: ${chalk.cyan(npmPackage)}...`);
150
- const result = await downloadNpmPackage({
151
- packageName: npmPackage,
152
- workspaceRoot,
153
- });
154
- return result.packagePath;
155
- }
156
- getPackagePath(context) {
157
- // Determine the base directory based on location type
158
- switch (context.locationType) {
159
- case 'workspace-app':
160
- return path.join(context.appsDir, context.appName);
161
- case 'workspace-library':
162
- return path.join(context.workspaceRoot, 'libraries', context.appName);
163
- case 'workspace-plugin':
164
- return path.join(context.workspaceRoot, 'plugins', context.appName);
165
- case 'workspace-app-template':
166
- return path.join(context.workspaceRoot, 'app-templates', context.appName);
167
- default:
168
- throw new InvalidPluginContextError(`Cannot install plugin from ${context.locationType}`);
169
- }
170
- }
171
- async runGenerator(pluginPath, appPath, context) {
172
- try {
173
- const generatorPath = path.join(pluginPath, 'dist/generator.js');
174
- const args = [generatorPath, `--appPath=${appPath}`, `--appName=${context.appName}`, `--workspaceName=${context.workspaceName}`, `--pluginPath=${pluginPath}`];
175
- await execa('node', args, {
176
- cwd: pluginPath,
177
- stdio: 'inherit',
178
- });
179
- }
180
- catch (error) {
181
- throw new PluginInstallationError(`Generator failed: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
182
- }
183
- }
184
- async isPluginInstalled(pluginName, packagePath) {
185
- try {
186
- const packageJsonPath = path.join(packagePath, 'package.json');
187
- const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
188
- const packageJson = JSON.parse(packageJsonContent);
189
- const manifest = packageJson.launch77;
190
- if (manifest?.installedPlugins?.[pluginName]) {
191
- return manifest.installedPlugins[pluginName];
192
- }
193
- return null;
194
- }
195
- catch (error) {
196
- // If package.json doesn't exist or can't be read, assume not installed
197
- return null;
198
- }
199
- }
200
- /**
201
- * Write plugin installation metadata to the target package's package.json
202
- */
203
- async writePluginManifest(packagePath, installationInfo) {
204
- try {
205
- const packageJsonPath = path.join(packagePath, 'package.json');
206
- const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
207
- const packageJson = JSON.parse(packageJsonContent);
208
- if (!packageJson.launch77) {
209
- packageJson.launch77 = {};
210
- }
211
- if (!packageJson.launch77.installedPlugins) {
212
- packageJson.launch77.installedPlugins = {};
213
- }
214
- const manifest = packageJson.launch77;
215
- manifest.installedPlugins[installationInfo.pluginName] = {
216
- package: installationInfo.packageName,
217
- version: installationInfo.version,
218
- installedAt: new Date().toISOString(),
219
- source: installationInfo.source,
220
- };
221
- await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf-8');
222
- }
223
- catch (error) {
224
- throw new PluginInstallationError(`Failed to write plugin manifest: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
225
- }
226
- }
227
- /**
228
- * Delete a plugin from the workspace
229
- */
230
- async deletePlugin(request, context) {
231
- const { pluginName } = request;
232
- // 1. Validate plugin name (reusing app name validation since format is the same)
233
- const nameValidation = validateAppName(pluginName);
234
- if (!nameValidation.valid) {
235
- throw new InvalidPluginNameError(nameValidation.errorMessage || 'Invalid plugin name');
236
- }
237
- // 2. Validate workspace context
238
- const contextValidation = validateWorkspaceContext(context);
239
- if (!contextValidation.valid) {
240
- throw new Error(contextValidation.errorMessage || 'Invalid workspace context');
241
- }
242
- // 3. Determine plugin path
243
- const pluginPath = path.join(context.workspaceRoot, 'plugins', pluginName);
244
- // 4. Check if plugin exists
245
- if (!(await fsExtra.pathExists(pluginPath))) {
246
- throw new PluginDirectoryNotFoundError(pluginName, pluginPath);
247
- }
248
- // 5. Delete the plugin directory
249
- await fsExtra.remove(pluginPath);
250
- // 6. Update dependencies
251
- await npm.install(context.workspaceRoot);
252
- return {
253
- pluginName,
254
- };
255
- }
256
- }
257
- //# sourceMappingURL=plugin-svc.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin-svc.js","sourceRoot":"","sources":["../../../../src/modules/plugin/services/plugin-svc.ts"],"names":[],"mappings":"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"}
@@ -1,25 +0,0 @@
1
- export interface InstallPluginRequest {
2
- pluginName: string;
3
- }
4
- export interface InstallPluginResult {
5
- pluginName: string;
6
- filesInstalled: boolean;
7
- packageJsonUpdated: boolean;
8
- dependenciesInstalled: boolean;
9
- }
10
- export interface PluginMetadata {
11
- dependencies?: Record<string, string>;
12
- devDependencies?: Record<string, string>;
13
- scripts?: Record<string, string>;
14
- }
15
- export interface HookResult {
16
- templateVariables?: Record<string, string>;
17
- hookContext?: Record<string, string>;
18
- }
19
- export interface DeletePluginRequest {
20
- pluginName: string;
21
- }
22
- export interface DeletePluginResult {
23
- pluginName: string;
24
- }
25
- //# sourceMappingURL=plugin-types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin-types.d.ts","sourceRoot":"","sources":["../../../../src/modules/plugin/types/plugin-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,OAAO,CAAA;IACvB,kBAAkB,EAAE,OAAO,CAAA;IAC3B,qBAAqB,EAAE,OAAO,CAAA;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACrC;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAA;CACnB"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=plugin-types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin-types.js","sourceRoot":"","sources":["../../../../src/modules/plugin/types/plugin-types.ts"],"names":[],"mappings":""}
@@ -1,73 +0,0 @@
1
- import * as path from 'path'
2
-
3
- import { execa } from 'execa'
4
-
5
- import { NpmInstallationError } from '../modules/plugin/errors/plugin-errors.js'
6
-
7
- /**
8
- * Options for downloading an npm package
9
- */
10
- export interface DownloadNpmPackageOptions {
11
- /** The npm package name to download */
12
- packageName: string
13
- /** The workspace root directory where node_modules will be */
14
- workspaceRoot: string
15
- /** Optional logger function for status messages */
16
- logger?: (message: string) => void
17
- }
18
-
19
- /**
20
- * Result of downloading an npm package
21
- */
22
- export interface DownloadNpmPackageResult {
23
- /** Full path to the downloaded package in node_modules */
24
- packagePath: string
25
- /** The package name that was downloaded */
26
- packageName: string
27
- }
28
-
29
- /**
30
- * Download and install an npm package to workspace node_modules
31
- *
32
- * This function:
33
- * - Runs `npm install {packageName} --save-dev` in the workspace root
34
- * - Adds the package to workspace package.json devDependencies
35
- * - Returns the path to the installed package in node_modules
36
- *
37
- * @param options - Download options
38
- * @returns The path to the installed package
39
- * @throws NpmInstallationError if the download fails
40
- *
41
- * @example
42
- * const result = await downloadNpmPackage({
43
- * packageName: '@launch77-shared/plugin-release',
44
- * workspaceRoot: '/path/to/workspace',
45
- * logger: (msg) => console.log(msg)
46
- * })
47
- * // result.packagePath: '/path/to/workspace/node_modules/@launch77-shared/plugin-release'
48
- */
49
- export async function downloadNpmPackage(options: DownloadNpmPackageOptions): Promise<DownloadNpmPackageResult> {
50
- const { packageName, workspaceRoot, logger } = options
51
-
52
- if (logger) {
53
- logger(`Installing from npm: ${packageName}...`)
54
- }
55
-
56
- try {
57
- // Install the npm package to the workspace
58
- await execa('npm', ['install', packageName, '--save-dev'], {
59
- cwd: workspaceRoot,
60
- stdio: 'pipe', // Capture output for clean logging
61
- })
62
-
63
- // Return path to installed package in node_modules
64
- const packagePath = path.join(workspaceRoot, 'node_modules', packageName)
65
-
66
- return {
67
- packagePath,
68
- packageName,
69
- }
70
- } catch (error) {
71
- throw new NpmInstallationError(packageName, error instanceof Error ? error : undefined)
72
- }
73
- }
@@ -1,18 +0,0 @@
1
- import { execa } from 'execa'
2
-
3
- /**
4
- * Run npm install in a directory
5
- */
6
- export async function runNpmInstall(cwd: string): Promise<void> {
7
- await execa('npm', ['install'], {
8
- cwd,
9
- stdio: 'pipe',
10
- })
11
- }
12
-
13
- /**
14
- * Alias for runNpmInstall
15
- */
16
- export async function install(cwd: string): Promise<void> {
17
- await runNpmInstall(cwd)
18
- }
@@ -1,223 +0,0 @@
1
- import * as path from 'path'
2
-
3
- import { parsePluginName, isValidNpmPackageName } from '@launch77/plugin-runtime'
4
- import fs from 'fs-extra'
5
-
6
- import type { ValidationResult } from '@launch77/plugin-runtime'
7
-
8
- /**
9
- * Base interface for package resolution results
10
- */
11
- export interface PackageResolution {
12
- /** The source of the package */
13
- source: 'local' | 'npm'
14
- /** The resolved name/package to use */
15
- resolvedName: string
16
- /** The local path if source is 'local' */
17
- localPath?: string
18
- /** The npm package name if source is 'npm' */
19
- npmPackage?: string
20
- /** The version from package.json (required for local packages, undefined for npm until installed) */
21
- version?: string
22
- }
23
-
24
- /**
25
- * Abstract base class for resolving Launch77 packages
26
- *
27
- * Provides generic resolution logic for finding packages in:
28
- * 1. Local workspace directory (e.g., plugins/, app-templates/)
29
- * 2. npm packages with configured prefix (e.g., @launch77-shared/plugin-*, @launch77-shared/app-template-*)
30
- *
31
- * Concrete implementations must provide:
32
- * - Folder name for local resolution
33
- * - Package prefix for npm resolution
34
- * - Verification logic to validate local packages
35
- */
36
- export abstract class PackageResolver {
37
- /**
38
- * Get the local folder name where packages of this type are stored
39
- * @example 'plugins' or 'app-templates'
40
- */
41
- protected abstract getFolderName(): string
42
-
43
- /**
44
- * Get the npm package prefix for unscoped packages
45
- * @example '@launch77-shared/plugin-' or '@launch77-shared/app-template-'
46
- */
47
- protected abstract getPackagePrefix(): string
48
-
49
- /**
50
- * Verify that a local package is valid and complete
51
- * @param localPath - The local directory path to verify
52
- * @returns true if the package is valid, false otherwise
53
- */
54
- protected abstract verify(localPath: string): Promise<boolean>
55
-
56
- /**
57
- * Validate package input name
58
- *
59
- * Accepts:
60
- * - Unscoped names (e.g., "release", "my-package")
61
- * - Scoped npm packages (e.g., "@ibm/package-name")
62
- *
63
- * Rejects:
64
- * - Invalid formats
65
- * - Empty strings
66
- * - Names with invalid characters
67
- *
68
- * @param name - The package name to validate
69
- * @returns ValidationResult with isValid and optional error message
70
- *
71
- * @example
72
- * validateInput('release') // { isValid: true }
73
- * validateInput('@ibm/analytics') // { isValid: true }
74
- * validateInput('@invalid') // { isValid: false, error: '...' }
75
- */
76
- validateInput(name: string): ValidationResult {
77
- if (!name || name.trim().length === 0) {
78
- return {
79
- isValid: false,
80
- error: 'Package name cannot be empty',
81
- }
82
- }
83
-
84
- const trimmedName = name.trim()
85
-
86
- // Parse the name to determine type and validate
87
- //TODO: move/rename parsePluginName() to parsePackageName()
88
- const parsed = parsePluginName(trimmedName)
89
-
90
- if (!parsed.isValid) {
91
- return {
92
- isValid: false,
93
- error: parsed.error,
94
- }
95
- }
96
-
97
- // If it's scoped, it must be a valid npm package name
98
- if (parsed.type === 'scoped') {
99
- return isValidNpmPackageName(trimmedName)
100
- }
101
-
102
- // Unscoped names are valid for both local and npm
103
- return { isValid: true }
104
- }
105
-
106
- /**
107
- * Convert an unscoped package name to an npm package name
108
- *
109
- * Rules:
110
- * - Unscoped names: prefix with configured package prefix
111
- * - Scoped names: use as-is
112
- *
113
- * @param name - The package name (must be validated first)
114
- * @returns The npm package name
115
- *
116
- * @example
117
- * toNpmPackageName('release') // '@launch77-shared/plugin-release' (for PluginResolver)
118
- * toNpmPackageName('@ibm/analytics') // '@ibm/analytics'
119
- */
120
- toNpmPackageName(name: string): string {
121
- const trimmedName = name.trim()
122
-
123
- // If already scoped, use as-is
124
- if (trimmedName.startsWith('@')) {
125
- return trimmedName
126
- }
127
-
128
- // Otherwise, convert using configured prefix
129
- return `${this.getPackagePrefix()}${trimmedName}`
130
- }
131
-
132
- /**
133
- * Read version from package.json
134
- * @param packagePath - The path to the package directory
135
- * @returns The version string from package.json
136
- * @throws If package.json doesn't exist, can't be read, or is missing the version field
137
- */
138
- private async readVersion(packagePath: string): Promise<string> {
139
- const packageJsonPath = path.join(packagePath, 'package.json')
140
- try {
141
- const packageJson = await fs.readJson(packageJsonPath)
142
- if (!packageJson.version) {
143
- throw new Error(`Invalid package structure: package.json at ${packagePath} is missing required version field. ` + `All Launch77 packages must include a valid package.json with a version field.`)
144
- }
145
- return packageJson.version
146
- } catch (error) {
147
- // Re-throw our own error messages
148
- if (error instanceof Error && error.message.includes('Invalid package structure')) {
149
- throw error
150
- }
151
- // File not found or invalid JSON
152
- throw new Error(`Invalid package structure: package.json not found or invalid at ${packagePath}. ` + `All Launch77 packages must include a valid package.json with a version field.`)
153
- }
154
- }
155
-
156
- /**
157
- * Resolve package location from name
158
- *
159
- * Resolution order:
160
- * 1. Check local workspace directory (configured by getFolderName())
161
- * 2. Verify local package is valid (using verify())
162
- * 3. Fall back to npm package name (with configured prefix)
163
- * 4. Read version from package.json (if available)
164
- *
165
- * @param name - The package name to resolve
166
- * @param workspaceRoot - The workspace root directory
167
- * @returns PackageResolution with source, resolved location, and version
168
- *
169
- * @example
170
- * // Local package found
171
- * await resolveLocation('my-package', '/workspace')
172
- * // { source: 'local', resolvedName: 'my-package', localPath: '/workspace/plugins/my-package', version: '1.0.0' }
173
- *
174
- * // Not found locally, resolve to npm
175
- * await resolveLocation('release', '/workspace')
176
- * // { source: 'npm', resolvedName: 'release', npmPackage: '@launch77-shared/plugin-release' }
177
- *
178
- * // Scoped package always resolves to npm
179
- * await resolveLocation('@ibm/analytics', '/workspace')
180
- * // { source: 'npm', resolvedName: '@ibm/analytics', npmPackage: '@ibm/analytics' }
181
- */
182
- async resolveLocation(name: string, workspaceRoot: string): Promise<PackageResolution> {
183
- const trimmedName = name.trim()
184
- const parsed = parsePluginName(trimmedName)
185
-
186
- // If scoped, always use npm (local packages are never scoped)
187
- if (parsed.type === 'scoped') {
188
- return {
189
- source: 'npm',
190
- resolvedName: trimmedName,
191
- npmPackage: trimmedName,
192
- }
193
- }
194
-
195
- // Check local workspace directory
196
- const localPath = path.join(workspaceRoot, this.getFolderName(), trimmedName)
197
- const localExists = await fs.pathExists(localPath)
198
-
199
- if (localExists) {
200
- // Verify it's a valid package
201
- const isValid = await this.verify(localPath)
202
-
203
- if (isValid) {
204
- const version = await this.readVersion(localPath)
205
- return {
206
- source: 'local',
207
- resolvedName: trimmedName,
208
- localPath,
209
- version,
210
- }
211
- }
212
- }
213
-
214
- // Not found locally or invalid, resolve to npm package
215
- const npmPackage = this.toNpmPackageName(trimmedName)
216
-
217
- return {
218
- source: 'npm',
219
- resolvedName: trimmedName,
220
- npmPackage,
221
- }
222
- }
223
- }