@launch77/cli 1.4.3 → 1.4.4

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 (44) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/infrastructure/npm-package.d.ts +42 -0
  3. package/dist/infrastructure/npm-package.d.ts.map +1 -0
  4. package/dist/infrastructure/npm-package.js +46 -0
  5. package/dist/infrastructure/npm-package.js.map +1 -0
  6. package/dist/infrastructure/package-resolver.d.ts +107 -0
  7. package/dist/infrastructure/package-resolver.d.ts.map +1 -0
  8. package/dist/infrastructure/package-resolver.js +143 -0
  9. package/dist/infrastructure/package-resolver.js.map +1 -0
  10. package/dist/infrastructure/package-resolver.test.d.ts +2 -0
  11. package/dist/infrastructure/package-resolver.test.d.ts.map +1 -0
  12. package/dist/infrastructure/package-resolver.test.js +251 -0
  13. package/dist/infrastructure/package-resolver.test.js.map +1 -0
  14. package/dist/modules/app/commands/create-app.d.ts.map +1 -1
  15. package/dist/modules/app/commands/create-app.js +6 -2
  16. package/dist/modules/app/commands/create-app.js.map +1 -1
  17. package/dist/modules/app/lib/app-template-resolver.d.ts +14 -0
  18. package/dist/modules/app/lib/app-template-resolver.d.ts.map +1 -0
  19. package/dist/modules/app/lib/app-template-resolver.js +36 -0
  20. package/dist/modules/app/lib/app-template-resolver.js.map +1 -0
  21. package/dist/modules/app/services/app-svc.d.ts +2 -1
  22. package/dist/modules/app/services/app-svc.d.ts.map +1 -1
  23. package/dist/modules/app/services/app-svc.js +46 -11
  24. package/dist/modules/app/services/app-svc.js.map +1 -1
  25. package/dist/modules/plugin/lib/plugin-resolver.d.ts +10 -72
  26. package/dist/modules/plugin/lib/plugin-resolver.d.ts.map +1 -1
  27. package/dist/modules/plugin/lib/plugin-resolver.js +12 -115
  28. package/dist/modules/plugin/lib/plugin-resolver.js.map +1 -1
  29. package/dist/modules/plugin/lib/plugin-resolver.test.js +43 -39
  30. package/dist/modules/plugin/lib/plugin-resolver.test.js.map +1 -1
  31. package/dist/modules/plugin/services/plugin-svc.d.ts +2 -0
  32. package/dist/modules/plugin/services/plugin-svc.d.ts.map +1 -1
  33. package/dist/modules/plugin/services/plugin-svc.js +14 -17
  34. package/dist/modules/plugin/services/plugin-svc.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/infrastructure/npm-package.ts +73 -0
  37. package/src/infrastructure/package-resolver.test.ts +313 -0
  38. package/src/infrastructure/package-resolver.ts +194 -0
  39. package/src/modules/app/commands/create-app.ts +6 -2
  40. package/src/modules/app/lib/app-template-resolver.ts +40 -0
  41. package/src/modules/app/services/app-svc.ts +49 -12
  42. package/src/modules/plugin/lib/plugin-resolver.test.ts +46 -39
  43. package/src/modules/plugin/lib/plugin-resolver.ts +12 -142
  44. package/src/modules/plugin/services/plugin-svc.ts +15 -15
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @launch77/cli
2
2
 
3
+ ## 1.4.4
4
+
5
+ ### Patch Changes
6
+
7
+ - 1504a6d: Added support for creating apps from tempaltes published in npm
8
+ - Updated dependencies [1504a6d]
9
+ - @launch77/plugin-runtime@0.2.3
10
+
3
11
  ## 1.4.3
4
12
 
5
13
  ### Patch Changes
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Options for downloading an npm package
3
+ */
4
+ export interface DownloadNpmPackageOptions {
5
+ /** The npm package name to download */
6
+ packageName: string;
7
+ /** The workspace root directory where node_modules will be */
8
+ workspaceRoot: string;
9
+ /** Optional logger function for status messages */
10
+ logger?: (message: string) => void;
11
+ }
12
+ /**
13
+ * Result of downloading an npm package
14
+ */
15
+ export interface DownloadNpmPackageResult {
16
+ /** Full path to the downloaded package in node_modules */
17
+ packagePath: string;
18
+ /** The package name that was downloaded */
19
+ packageName: string;
20
+ }
21
+ /**
22
+ * Download and install an npm package to workspace node_modules
23
+ *
24
+ * This function:
25
+ * - Runs `npm install {packageName} --save-dev` in the workspace root
26
+ * - Adds the package to workspace package.json devDependencies
27
+ * - Returns the path to the installed package in node_modules
28
+ *
29
+ * @param options - Download options
30
+ * @returns The path to the installed package
31
+ * @throws NpmInstallationError if the download fails
32
+ *
33
+ * @example
34
+ * const result = await downloadNpmPackage({
35
+ * packageName: '@launch77-shared/plugin-release',
36
+ * workspaceRoot: '/path/to/workspace',
37
+ * logger: (msg) => console.log(msg)
38
+ * })
39
+ * // result.packagePath: '/path/to/workspace/node_modules/@launch77-shared/plugin-release'
40
+ */
41
+ export declare function downloadNpmPackage(options: DownloadNpmPackageOptions): Promise<DownloadNpmPackageResult>;
42
+ //# sourceMappingURL=npm-package.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"npm-package.d.ts","sourceRoot":"","sources":["../../src/infrastructure/npm-package.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAA;IACnB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAA;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAA;IACnB,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAwB9G"}
@@ -0,0 +1,46 @@
1
+ import * as path from 'path';
2
+ import { execa } from 'execa';
3
+ import { NpmInstallationError } from '../modules/plugin/errors/plugin-errors.js';
4
+ /**
5
+ * Download and install an npm package to workspace node_modules
6
+ *
7
+ * This function:
8
+ * - Runs `npm install {packageName} --save-dev` in the workspace root
9
+ * - Adds the package to workspace package.json devDependencies
10
+ * - Returns the path to the installed package in node_modules
11
+ *
12
+ * @param options - Download options
13
+ * @returns The path to the installed package
14
+ * @throws NpmInstallationError if the download fails
15
+ *
16
+ * @example
17
+ * const result = await downloadNpmPackage({
18
+ * packageName: '@launch77-shared/plugin-release',
19
+ * workspaceRoot: '/path/to/workspace',
20
+ * logger: (msg) => console.log(msg)
21
+ * })
22
+ * // result.packagePath: '/path/to/workspace/node_modules/@launch77-shared/plugin-release'
23
+ */
24
+ export async function downloadNpmPackage(options) {
25
+ const { packageName, workspaceRoot, logger } = options;
26
+ if (logger) {
27
+ logger(`Installing from npm: ${packageName}...`);
28
+ }
29
+ try {
30
+ // Install the npm package to the workspace
31
+ await execa('npm', ['install', packageName, '--save-dev'], {
32
+ cwd: workspaceRoot,
33
+ stdio: 'pipe', // Capture output for clean logging
34
+ });
35
+ // Return path to installed package in node_modules
36
+ const packagePath = path.join(workspaceRoot, 'node_modules', packageName);
37
+ return {
38
+ packagePath,
39
+ packageName,
40
+ };
41
+ }
42
+ catch (error) {
43
+ throw new NpmInstallationError(packageName, error instanceof Error ? error : undefined);
44
+ }
45
+ }
46
+ //# sourceMappingURL=npm-package.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"npm-package.js","sourceRoot":"","sources":["../../src/infrastructure/npm-package.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAE5B,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAE7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAwBhF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAkC;IACzE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IAEtD,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,CAAC,wBAAwB,WAAW,KAAK,CAAC,CAAA;IAClD,CAAC;IAED,IAAI,CAAC;QACH,2CAA2C;QAC3C,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE;YACzD,GAAG,EAAE,aAAa;YAClB,KAAK,EAAE,MAAM,EAAE,mCAAmC;SACnD,CAAC,CAAA;QAEF,mDAAmD;QACnD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,cAAc,EAAE,WAAW,CAAC,CAAA;QAEzE,OAAO;YACL,WAAW;YACX,WAAW;SACZ,CAAA;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,oBAAoB,CAAC,WAAW,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IACzF,CAAC;AACH,CAAC"}
@@ -0,0 +1,107 @@
1
+ import type { ValidationResult } from '@launch77/plugin-runtime';
2
+ /**
3
+ * Base interface for package resolution results
4
+ */
5
+ export interface PackageResolution {
6
+ /** The source of the package */
7
+ source: 'local' | 'npm';
8
+ /** The resolved name/package to use */
9
+ resolvedName: string;
10
+ /** The local path if source is 'local' */
11
+ localPath?: string;
12
+ /** The npm package name if source is 'npm' */
13
+ npmPackage?: string;
14
+ }
15
+ /**
16
+ * Abstract base class for resolving Launch77 packages
17
+ *
18
+ * Provides generic resolution logic for finding packages in:
19
+ * 1. Local workspace directory (e.g., plugins/, app-templates/)
20
+ * 2. npm packages with configured prefix (e.g., @launch77-shared/plugin-*, @launch77-shared/app-template-*)
21
+ *
22
+ * Concrete implementations must provide:
23
+ * - Folder name for local resolution
24
+ * - Package prefix for npm resolution
25
+ * - Verification logic to validate local packages
26
+ */
27
+ export declare abstract class PackageResolver {
28
+ /**
29
+ * Get the local folder name where packages of this type are stored
30
+ * @example 'plugins' or 'app-templates'
31
+ */
32
+ protected abstract getFolderName(): string;
33
+ /**
34
+ * Get the npm package prefix for unscoped packages
35
+ * @example '@launch77-shared/plugin-' or '@launch77-shared/app-template-'
36
+ */
37
+ protected abstract getPackagePrefix(): string;
38
+ /**
39
+ * Verify that a local package is valid and complete
40
+ * @param localPath - The local directory path to verify
41
+ * @returns true if the package is valid, false otherwise
42
+ */
43
+ protected abstract verify(localPath: string): Promise<boolean>;
44
+ /**
45
+ * Validate package input name
46
+ *
47
+ * Accepts:
48
+ * - Unscoped names (e.g., "release", "my-package")
49
+ * - Scoped npm packages (e.g., "@ibm/package-name")
50
+ *
51
+ * Rejects:
52
+ * - Invalid formats
53
+ * - Empty strings
54
+ * - Names with invalid characters
55
+ *
56
+ * @param name - The package name to validate
57
+ * @returns ValidationResult with isValid and optional error message
58
+ *
59
+ * @example
60
+ * validateInput('release') // { isValid: true }
61
+ * validateInput('@ibm/analytics') // { isValid: true }
62
+ * validateInput('@invalid') // { isValid: false, error: '...' }
63
+ */
64
+ validateInput(name: string): ValidationResult;
65
+ /**
66
+ * Convert an unscoped package name to an npm package name
67
+ *
68
+ * Rules:
69
+ * - Unscoped names: prefix with configured package prefix
70
+ * - Scoped names: use as-is
71
+ *
72
+ * @param name - The package name (must be validated first)
73
+ * @returns The npm package name
74
+ *
75
+ * @example
76
+ * toNpmPackageName('release') // '@launch77-shared/plugin-release' (for PluginResolver)
77
+ * toNpmPackageName('@ibm/analytics') // '@ibm/analytics'
78
+ */
79
+ toNpmPackageName(name: string): string;
80
+ /**
81
+ * Resolve package location from name
82
+ *
83
+ * Resolution order:
84
+ * 1. Check local workspace directory (configured by getFolderName())
85
+ * 2. Verify local package is valid (using verify())
86
+ * 3. Fall back to npm package name (with configured prefix)
87
+ *
88
+ * @param name - The package name to resolve
89
+ * @param workspaceRoot - The workspace root directory
90
+ * @returns PackageResolution with source and resolved location
91
+ *
92
+ * @example
93
+ * // Local package found
94
+ * await resolveLocation('my-package', '/workspace')
95
+ * // { source: 'local', resolvedName: 'my-package', localPath: '/workspace/plugins/my-package' }
96
+ *
97
+ * // Not found locally, resolve to npm
98
+ * await resolveLocation('release', '/workspace')
99
+ * // { source: 'npm', resolvedName: 'release', npmPackage: '@launch77-shared/plugin-release' }
100
+ *
101
+ * // Scoped package always resolves to npm
102
+ * await resolveLocation('@ibm/analytics', '/workspace')
103
+ * // { source: 'npm', resolvedName: '@ibm/analytics', npmPackage: '@ibm/analytics' }
104
+ */
105
+ resolveLocation(name: string, workspaceRoot: string): Promise<PackageResolution>;
106
+ }
107
+ //# sourceMappingURL=package-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-resolver.d.ts","sourceRoot":"","sources":["../../src/infrastructure/package-resolver.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAEhE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,gCAAgC;IAChC,MAAM,EAAE,OAAO,GAAG,KAAK,CAAA;IACvB,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAA;IACpB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;;;;;;GAWG;AACH,8BAAsB,eAAe;IACnC;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa,IAAI,MAAM;IAE1C;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,gBAAgB,IAAI,MAAM;IAE7C;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAE9D;;;;;;;;;;;;;;;;;;;OAmBG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB;IA8B7C;;;;;;;;;;;;;OAaG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAYtC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACG,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAuCvF"}
@@ -0,0 +1,143 @@
1
+ import * as path from 'path';
2
+ import { parsePluginName, isValidNpmPackageName } from '@launch77/plugin-runtime';
3
+ import fs from 'fs-extra';
4
+ /**
5
+ * Abstract base class for resolving Launch77 packages
6
+ *
7
+ * Provides generic resolution logic for finding packages in:
8
+ * 1. Local workspace directory (e.g., plugins/, app-templates/)
9
+ * 2. npm packages with configured prefix (e.g., @launch77-shared/plugin-*, @launch77-shared/app-template-*)
10
+ *
11
+ * Concrete implementations must provide:
12
+ * - Folder name for local resolution
13
+ * - Package prefix for npm resolution
14
+ * - Verification logic to validate local packages
15
+ */
16
+ export class PackageResolver {
17
+ /**
18
+ * Validate package input name
19
+ *
20
+ * Accepts:
21
+ * - Unscoped names (e.g., "release", "my-package")
22
+ * - Scoped npm packages (e.g., "@ibm/package-name")
23
+ *
24
+ * Rejects:
25
+ * - Invalid formats
26
+ * - Empty strings
27
+ * - Names with invalid characters
28
+ *
29
+ * @param name - The package name to validate
30
+ * @returns ValidationResult with isValid and optional error message
31
+ *
32
+ * @example
33
+ * validateInput('release') // { isValid: true }
34
+ * validateInput('@ibm/analytics') // { isValid: true }
35
+ * validateInput('@invalid') // { isValid: false, error: '...' }
36
+ */
37
+ validateInput(name) {
38
+ if (!name || name.trim().length === 0) {
39
+ return {
40
+ isValid: false,
41
+ error: 'Package name cannot be empty',
42
+ };
43
+ }
44
+ const trimmedName = name.trim();
45
+ // Parse the name to determine type and validate
46
+ //TODO: move/rename parsePluginName() to parsePackageName()
47
+ const parsed = parsePluginName(trimmedName);
48
+ if (!parsed.isValid) {
49
+ return {
50
+ isValid: false,
51
+ error: parsed.error,
52
+ };
53
+ }
54
+ // If it's scoped, it must be a valid npm package name
55
+ if (parsed.type === 'scoped') {
56
+ return isValidNpmPackageName(trimmedName);
57
+ }
58
+ // Unscoped names are valid for both local and npm
59
+ return { isValid: true };
60
+ }
61
+ /**
62
+ * Convert an unscoped package name to an npm package name
63
+ *
64
+ * Rules:
65
+ * - Unscoped names: prefix with configured package prefix
66
+ * - Scoped names: use as-is
67
+ *
68
+ * @param name - The package name (must be validated first)
69
+ * @returns The npm package name
70
+ *
71
+ * @example
72
+ * toNpmPackageName('release') // '@launch77-shared/plugin-release' (for PluginResolver)
73
+ * toNpmPackageName('@ibm/analytics') // '@ibm/analytics'
74
+ */
75
+ toNpmPackageName(name) {
76
+ const trimmedName = name.trim();
77
+ // If already scoped, use as-is
78
+ if (trimmedName.startsWith('@')) {
79
+ return trimmedName;
80
+ }
81
+ // Otherwise, convert using configured prefix
82
+ return `${this.getPackagePrefix()}${trimmedName}`;
83
+ }
84
+ /**
85
+ * Resolve package location from name
86
+ *
87
+ * Resolution order:
88
+ * 1. Check local workspace directory (configured by getFolderName())
89
+ * 2. Verify local package is valid (using verify())
90
+ * 3. Fall back to npm package name (with configured prefix)
91
+ *
92
+ * @param name - The package name to resolve
93
+ * @param workspaceRoot - The workspace root directory
94
+ * @returns PackageResolution with source and resolved location
95
+ *
96
+ * @example
97
+ * // Local package found
98
+ * await resolveLocation('my-package', '/workspace')
99
+ * // { source: 'local', resolvedName: 'my-package', localPath: '/workspace/plugins/my-package' }
100
+ *
101
+ * // Not found locally, resolve to npm
102
+ * await resolveLocation('release', '/workspace')
103
+ * // { source: 'npm', resolvedName: 'release', npmPackage: '@launch77-shared/plugin-release' }
104
+ *
105
+ * // Scoped package always resolves to npm
106
+ * await resolveLocation('@ibm/analytics', '/workspace')
107
+ * // { source: 'npm', resolvedName: '@ibm/analytics', npmPackage: '@ibm/analytics' }
108
+ */
109
+ async resolveLocation(name, workspaceRoot) {
110
+ const trimmedName = name.trim();
111
+ const parsed = parsePluginName(trimmedName);
112
+ // If scoped, always use npm (local packages are never scoped)
113
+ if (parsed.type === 'scoped') {
114
+ return {
115
+ source: 'npm',
116
+ resolvedName: trimmedName,
117
+ npmPackage: trimmedName,
118
+ };
119
+ }
120
+ // Check local workspace directory
121
+ const localPath = path.join(workspaceRoot, this.getFolderName(), trimmedName);
122
+ const localExists = await fs.pathExists(localPath);
123
+ if (localExists) {
124
+ // Verify it's a valid package
125
+ const isValid = await this.verify(localPath);
126
+ if (isValid) {
127
+ return {
128
+ source: 'local',
129
+ resolvedName: trimmedName,
130
+ localPath,
131
+ };
132
+ }
133
+ }
134
+ // Not found locally or invalid, resolve to npm package
135
+ const npmPackage = this.toNpmPackageName(trimmedName);
136
+ return {
137
+ source: 'npm',
138
+ resolvedName: trimmedName,
139
+ npmPackage,
140
+ };
141
+ }
142
+ }
143
+ //# sourceMappingURL=package-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-resolver.js","sourceRoot":"","sources":["../../src/infrastructure/package-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAE5B,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAA;AACjF,OAAO,EAAE,MAAM,UAAU,CAAA;AAkBzB;;;;;;;;;;;GAWG;AACH,MAAM,OAAgB,eAAe;IAoBnC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,aAAa,CAAC,IAAY;QACxB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtC,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,8BAA8B;aACtC,CAAA;QACH,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAE/B,gDAAgD;QAChD,2DAA2D;QAC3D,MAAM,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC,CAAA;QAE3C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,MAAM,CAAC,KAAK;aACpB,CAAA;QACH,CAAC;QAED,sDAAsD;QACtD,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,OAAO,qBAAqB,CAAC,WAAW,CAAC,CAAA;QAC3C,CAAC;QAED,kDAAkD;QAClD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IAC1B,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,gBAAgB,CAAC,IAAY;QAC3B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAE/B,+BAA+B;QAC/B,IAAI,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAChC,OAAO,WAAW,CAAA;QACpB,CAAC;QAED,6CAA6C;QAC7C,OAAO,GAAG,IAAI,CAAC,gBAAgB,EAAE,GAAG,WAAW,EAAE,CAAA;IACnD,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,KAAK,CAAC,eAAe,CAAC,IAAY,EAAE,aAAqB;QACvD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAC/B,MAAM,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC,CAAA;QAE3C,8DAA8D;QAC9D,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,OAAO;gBACL,MAAM,EAAE,KAAK;gBACb,YAAY,EAAE,WAAW;gBACzB,UAAU,EAAE,WAAW;aACxB,CAAA;QACH,CAAC;QAED,kCAAkC;QAClC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,EAAE,WAAW,CAAC,CAAA;QAC7E,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;QAElD,IAAI,WAAW,EAAE,CAAC;YAChB,8BAA8B;YAC9B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YAE5C,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO;oBACL,MAAM,EAAE,OAAO;oBACf,YAAY,EAAE,WAAW;oBACzB,SAAS;iBACV,CAAA;YACH,CAAC;QACH,CAAC;QAED,uDAAuD;QACvD,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAA;QAErD,OAAO;YACL,MAAM,EAAE,KAAK;YACb,YAAY,EAAE,WAAW;YACzB,UAAU;SACX,CAAA;IACH,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=package-resolver.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-resolver.test.d.ts","sourceRoot":"","sources":["../../src/infrastructure/package-resolver.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,251 @@
1
+ import * as os from 'os';
2
+ import * as path from 'path';
3
+ import fs from 'fs-extra';
4
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
5
+ import { PackageResolver } from './package-resolver.js';
6
+ /**
7
+ * Test implementation of PackageResolver for unit testing
8
+ */
9
+ class TestPackageResolver extends PackageResolver {
10
+ getFolderName() {
11
+ return 'test-packages';
12
+ }
13
+ getPackagePrefix() {
14
+ return '@test-org/test-';
15
+ }
16
+ async verify(localPath) {
17
+ // Verify by checking for package.json
18
+ const packageJsonPath = path.join(localPath, 'package.json');
19
+ return await fs.pathExists(packageJsonPath);
20
+ }
21
+ }
22
+ describe('PackageResolver', () => {
23
+ let resolver;
24
+ let tempDir;
25
+ beforeEach(async () => {
26
+ resolver = new TestPackageResolver();
27
+ tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'package-resolver-test-'));
28
+ });
29
+ afterEach(async () => {
30
+ await fs.remove(tempDir);
31
+ });
32
+ describe('validateInput', () => {
33
+ describe('valid inputs', () => {
34
+ it('should accept valid unscoped package names', () => {
35
+ const result = resolver.validateInput('release');
36
+ expect(result.isValid).toBe(true);
37
+ expect(result.error).toBeUndefined();
38
+ });
39
+ it('should accept unscoped names with hyphens', () => {
40
+ const result = resolver.validateInput('my-package');
41
+ expect(result.isValid).toBe(true);
42
+ });
43
+ it('should accept unscoped names with numbers', () => {
44
+ const result = resolver.validateInput('package-123');
45
+ expect(result.isValid).toBe(true);
46
+ });
47
+ it('should accept valid scoped packages', () => {
48
+ const result = resolver.validateInput('@ibm/analytics');
49
+ expect(result.isValid).toBe(true);
50
+ expect(result.error).toBeUndefined();
51
+ });
52
+ it('should accept scoped packages with hyphens', () => {
53
+ const result = resolver.validateInput('@launch77-shared/plugin-release');
54
+ expect(result.isValid).toBe(true);
55
+ });
56
+ it('should trim whitespace from valid names', () => {
57
+ const result = resolver.validateInput(' release ');
58
+ expect(result.isValid).toBe(true);
59
+ });
60
+ it('should trim whitespace from scoped names', () => {
61
+ const result = resolver.validateInput(' @ibm/analytics ');
62
+ expect(result.isValid).toBe(true);
63
+ });
64
+ });
65
+ describe('invalid inputs', () => {
66
+ it('should reject empty string', () => {
67
+ const result = resolver.validateInput('');
68
+ expect(result.isValid).toBe(false);
69
+ expect(result.error).toBe('Package name cannot be empty');
70
+ });
71
+ it('should reject whitespace-only string', () => {
72
+ const result = resolver.validateInput(' ');
73
+ expect(result.isValid).toBe(false);
74
+ expect(result.error).toBe('Package name cannot be empty');
75
+ });
76
+ it('should reject invalid scoped package without name', () => {
77
+ const result = resolver.validateInput('@invalid');
78
+ expect(result.isValid).toBe(false);
79
+ expect(result.error).toContain('Scoped package must be in format @org/package');
80
+ });
81
+ it('should reject invalid scoped package without scope', () => {
82
+ const result = resolver.validateInput('@/package');
83
+ expect(result.isValid).toBe(false);
84
+ expect(result.error).toBeDefined();
85
+ });
86
+ it('should reject invalid scoped package with missing name after slash', () => {
87
+ const result = resolver.validateInput('@org/');
88
+ expect(result.isValid).toBe(false);
89
+ expect(result.error).toContain('Scoped package must be in format @org/package');
90
+ });
91
+ it('should reject names with uppercase letters', () => {
92
+ const result = resolver.validateInput('MyPackage');
93
+ expect(result.isValid).toBe(false);
94
+ expect(result.error).toBeDefined();
95
+ });
96
+ it('should reject names starting with numbers', () => {
97
+ const result = resolver.validateInput('123package');
98
+ expect(result.isValid).toBe(false);
99
+ expect(result.error).toBeDefined();
100
+ });
101
+ it('should reject names with underscores', () => {
102
+ const result = resolver.validateInput('my_package');
103
+ expect(result.isValid).toBe(false);
104
+ expect(result.error).toBeDefined();
105
+ });
106
+ it('should reject names with spaces', () => {
107
+ const result = resolver.validateInput('my package');
108
+ expect(result.isValid).toBe(false);
109
+ expect(result.error).toBeDefined();
110
+ });
111
+ });
112
+ });
113
+ describe('toNpmPackageName', () => {
114
+ describe('unscoped names', () => {
115
+ it('should prefix unscoped package names', () => {
116
+ const result = resolver.toNpmPackageName('release');
117
+ expect(result).toBe('@test-org/test-release');
118
+ });
119
+ it('should prefix unscoped names with hyphens', () => {
120
+ const result = resolver.toNpmPackageName('my-package');
121
+ expect(result).toBe('@test-org/test-my-package');
122
+ });
123
+ it('should trim whitespace from unscoped names', () => {
124
+ const result = resolver.toNpmPackageName(' release ');
125
+ expect(result).toBe('@test-org/test-release');
126
+ });
127
+ });
128
+ describe('scoped names', () => {
129
+ it('should return scoped packages as-is', () => {
130
+ const result = resolver.toNpmPackageName('@ibm/analytics');
131
+ expect(result).toBe('@ibm/analytics');
132
+ });
133
+ it('should return scoped packages with hyphens as-is', () => {
134
+ const result = resolver.toNpmPackageName('@launch77-shared/plugin-release');
135
+ expect(result).toBe('@launch77-shared/plugin-release');
136
+ });
137
+ it('should trim whitespace from scoped names', () => {
138
+ const result = resolver.toNpmPackageName(' @ibm/analytics ');
139
+ expect(result).toBe('@ibm/analytics');
140
+ });
141
+ });
142
+ });
143
+ describe('resolveLocation', () => {
144
+ describe('local resolution (unscoped names)', () => {
145
+ it('should resolve to local when valid package exists', async () => {
146
+ const packageName = 'my-local-package';
147
+ const localPath = path.join(tempDir, 'test-packages', packageName);
148
+ await fs.ensureDir(localPath);
149
+ await fs.writeJSON(path.join(localPath, 'package.json'), { name: packageName });
150
+ const result = await resolver.resolveLocation(packageName, tempDir);
151
+ expect(result.source).toBe('local');
152
+ expect(result.resolvedName).toBe(packageName);
153
+ expect(result.localPath).toBe(localPath);
154
+ expect(result.npmPackage).toBeUndefined();
155
+ });
156
+ it('should fall back to npm when local directory exists but is invalid', async () => {
157
+ const packageName = 'invalid-local-package';
158
+ const localPath = path.join(tempDir, 'test-packages', packageName);
159
+ await fs.ensureDir(localPath);
160
+ // Don't create package.json, making it invalid
161
+ const result = await resolver.resolveLocation(packageName, tempDir);
162
+ expect(result.source).toBe('npm');
163
+ expect(result.resolvedName).toBe(packageName);
164
+ expect(result.npmPackage).toBe('@test-org/test-invalid-local-package');
165
+ expect(result.localPath).toBeUndefined();
166
+ });
167
+ it('should fall back to npm when local directory does not exist', async () => {
168
+ const packageName = 'nonexistent-package';
169
+ const result = await resolver.resolveLocation(packageName, tempDir);
170
+ expect(result.source).toBe('npm');
171
+ expect(result.resolvedName).toBe(packageName);
172
+ expect(result.npmPackage).toBe('@test-org/test-nonexistent-package');
173
+ expect(result.localPath).toBeUndefined();
174
+ });
175
+ it('should trim whitespace from package names', async () => {
176
+ const packageName = 'my-package';
177
+ const localPath = path.join(tempDir, 'test-packages', packageName);
178
+ await fs.ensureDir(localPath);
179
+ await fs.writeJSON(path.join(localPath, 'package.json'), { name: packageName });
180
+ const result = await resolver.resolveLocation(' my-package ', tempDir);
181
+ expect(result.source).toBe('local');
182
+ expect(result.resolvedName).toBe(packageName);
183
+ expect(result.localPath).toBe(localPath);
184
+ });
185
+ });
186
+ describe('npm resolution (scoped names)', () => {
187
+ it('should always resolve scoped packages to npm', async () => {
188
+ const packageName = '@ibm/analytics';
189
+ const result = await resolver.resolveLocation(packageName, tempDir);
190
+ expect(result.source).toBe('npm');
191
+ expect(result.resolvedName).toBe(packageName);
192
+ expect(result.npmPackage).toBe(packageName);
193
+ expect(result.localPath).toBeUndefined();
194
+ });
195
+ it('should resolve scoped packages to npm even if local directory exists', async () => {
196
+ const packageName = '@ibm/analytics';
197
+ // Create a local directory with the scoped package name (edge case)
198
+ const localPath = path.join(tempDir, 'test-packages', '@ibm/analytics');
199
+ await fs.ensureDir(localPath);
200
+ await fs.writeJSON(path.join(localPath, 'package.json'), { name: packageName });
201
+ const result = await resolver.resolveLocation(packageName, tempDir);
202
+ expect(result.source).toBe('npm');
203
+ expect(result.resolvedName).toBe(packageName);
204
+ expect(result.npmPackage).toBe(packageName);
205
+ expect(result.localPath).toBeUndefined();
206
+ });
207
+ it('should handle scoped packages with hyphens', async () => {
208
+ const packageName = '@launch77-shared/plugin-release';
209
+ const result = await resolver.resolveLocation(packageName, tempDir);
210
+ expect(result.source).toBe('npm');
211
+ expect(result.resolvedName).toBe(packageName);
212
+ expect(result.npmPackage).toBe(packageName);
213
+ });
214
+ it('should trim whitespace from scoped package names', async () => {
215
+ const packageName = '@ibm/analytics';
216
+ const result = await resolver.resolveLocation(' @ibm/analytics ', tempDir);
217
+ expect(result.source).toBe('npm');
218
+ expect(result.resolvedName).toBe(packageName);
219
+ expect(result.npmPackage).toBe(packageName);
220
+ });
221
+ });
222
+ describe('edge cases', () => {
223
+ it('should handle empty workspace test-packages directory', async () => {
224
+ // Ensure the directory exists but is empty
225
+ await fs.ensureDir(path.join(tempDir, 'test-packages'));
226
+ const result = await resolver.resolveLocation('some-package', tempDir);
227
+ expect(result.source).toBe('npm');
228
+ expect(result.resolvedName).toBe('some-package');
229
+ expect(result.npmPackage).toBe('@test-org/test-some-package');
230
+ });
231
+ it('should handle missing workspace test-packages directory', async () => {
232
+ // Don't create the test-packages directory at all
233
+ const result = await resolver.resolveLocation('some-package', tempDir);
234
+ expect(result.source).toBe('npm');
235
+ expect(result.resolvedName).toBe('some-package');
236
+ expect(result.npmPackage).toBe('@test-org/test-some-package');
237
+ });
238
+ it('should handle different workspace root paths', async () => {
239
+ const customRoot = path.join(tempDir, 'custom', 'workspace');
240
+ const packageName = 'my-package';
241
+ const localPath = path.join(customRoot, 'test-packages', packageName);
242
+ await fs.ensureDir(localPath);
243
+ await fs.writeJSON(path.join(localPath, 'package.json'), { name: packageName });
244
+ const result = await resolver.resolveLocation(packageName, customRoot);
245
+ expect(result.source).toBe('local');
246
+ expect(result.localPath).toBe(localPath);
247
+ });
248
+ });
249
+ });
250
+ });
251
+ //# sourceMappingURL=package-resolver.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-resolver.test.js","sourceRoot":"","sources":["../../src/infrastructure/package-resolver.test.ts"],"names":[],"mappings":"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"}