|
4 | 4 | * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 |
5 | 5 | */ |
6 | 6 |
|
| 7 | +import fs from 'node:fs'; |
| 8 | +import path from 'node:path'; |
7 | 9 | import {findCartridges} from '../operations/code/cartridges.js'; |
8 | 10 | import type {B2CInstance} from '../instance/index.js'; |
9 | 11 | import type {OcapiComponents} from '../clients/index.js'; |
10 | | -import type {ScaffoldChoice, DynamicParameterSource, SourceResult} from './types.js'; |
| 12 | +import type {ScaffoldChoice, ScaffoldParameter, DynamicParameterSource, SourceResult} from './types.js'; |
11 | 13 |
|
12 | 14 | /** |
13 | 15 | * Common B2C Commerce hook extension points. |
@@ -129,3 +131,73 @@ export function validateAgainstSource( |
129 | 131 | // For hook-points and other sources, no validation (allow any value) |
130 | 132 | return {valid: true}; |
131 | 133 | } |
| 134 | + |
| 135 | +/** |
| 136 | + * Path to use for scaffold destination so files are generated under outputDir (e.g. working directory). |
| 137 | + * Returns a path relative to projectRoot when the cartridge is under projectRoot, so the executor |
| 138 | + * joins with outputDir instead of ignoring it. Otherwise returns the absolute path. |
| 139 | + */ |
| 140 | +export function cartridgePathForDestination(absolutePath: string, projectRoot: string): string { |
| 141 | + const normalizedRoot = path.resolve(projectRoot); |
| 142 | + const normalizedPath = path.resolve(absolutePath); |
| 143 | + const relative = path.relative(normalizedRoot, normalizedPath); |
| 144 | + // Use relative path only when cartridge is under projectRoot (no leading '..') |
| 145 | + if (relative && !relative.startsWith('..') && !path.isAbsolute(relative)) { |
| 146 | + return relative; |
| 147 | + } |
| 148 | + return absolutePath; |
| 149 | +} |
| 150 | + |
| 151 | +/** |
| 152 | + * Result of detecting a source parameter value from a filesystem path. |
| 153 | + */ |
| 154 | +export interface SourceDetectionResult { |
| 155 | + /** The resolved parameter value (e.g., cartridge name) */ |
| 156 | + value: string; |
| 157 | + /** Companion variables to set (e.g., { cartridgeNamePath: "cartridges/app_custom" }) */ |
| 158 | + companionVariables: Record<string, string>; |
| 159 | +} |
| 160 | + |
| 161 | +/** |
| 162 | + * Detect a parameter's source value from a filesystem context path. |
| 163 | + * |
| 164 | + * For `cartridges` source: walks up from `contextPath` looking for a `.project` file |
| 165 | + * (cartridge marker), stopping at projectRoot. On match returns the cartridge name and |
| 166 | + * companion path variable. |
| 167 | + * |
| 168 | + * @param param - The scaffold parameter with a `source` field |
| 169 | + * @param contextPath - Filesystem path providing context (e.g., right-clicked folder) |
| 170 | + * @param projectRoot - Project root directory |
| 171 | + * @returns Detection result, or undefined if the source could not be detected |
| 172 | + */ |
| 173 | +export function detectSourceFromPath( |
| 174 | + param: ScaffoldParameter, |
| 175 | + contextPath: string, |
| 176 | + projectRoot: string, |
| 177 | +): SourceDetectionResult | undefined { |
| 178 | + if (param.source !== 'cartridges') { |
| 179 | + return undefined; |
| 180 | + } |
| 181 | + |
| 182 | + const normalizedRoot = path.resolve(projectRoot); |
| 183 | + let current = path.resolve(contextPath); |
| 184 | + |
| 185 | + // Walk up from contextPath, checking for .project at each level |
| 186 | + while (current.length >= normalizedRoot.length) { |
| 187 | + const projectFile = path.join(current, '.project'); |
| 188 | + if (fs.existsSync(projectFile)) { |
| 189 | + const cartridgeName = path.basename(current); |
| 190 | + const destPath = cartridgePathForDestination(current, projectRoot); |
| 191 | + return { |
| 192 | + value: cartridgeName, |
| 193 | + companionVariables: {[`${param.name}Path`]: destPath}, |
| 194 | + }; |
| 195 | + } |
| 196 | + |
| 197 | + const parent = path.dirname(current); |
| 198 | + if (parent === current) break; // filesystem root |
| 199 | + current = parent; |
| 200 | + } |
| 201 | + |
| 202 | + return undefined; |
| 203 | +} |
0 commit comments