@sap-ux/adp-tooling 1.0.43 → 1.0.44

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.
@@ -32,6 +32,7 @@ export default class RoutesHandler {
32
32
  * Whether this is running in build path mode (CF ADP using build output).
33
33
  */
34
34
  private readonly isBuildPathMode;
35
+ private readonly isWin32;
35
36
  /**
36
37
  * Constructor taking project as input.
37
38
  *
@@ -89,6 +90,15 @@ export default class RoutesHandler {
89
90
  * @param next Next Function
90
91
  */
91
92
  handleGetControllerExtensionData: (req: Request, res: Response, next: NextFunction) => Promise<void>;
93
+ /**
94
+ * Resolves base and instance-specific controller extensions from the workspace's codeExt change files.
95
+ *
96
+ * @param codeExtFiles codeExt change files read from the workspace
97
+ * @param controllerName Controller name matched to each change's selector
98
+ * @param viewId Optional view ID used to detect an instance-specific extension for the current view
99
+ * @returns Existence flags and paths for base or instance controllers, plus any stale change reference
100
+ */
101
+ private resolveControllerExtensions;
92
102
  /**
93
103
  * Handler for writing a controller extension file to the workspace.
94
104
  *
@@ -126,6 +136,7 @@ export default class RoutesHandler {
126
136
  * @returns Promise<ManifestService>
127
137
  */
128
138
  private getManifestService;
139
+ private toResponsePath;
129
140
  }
130
141
  export {};
131
142
  //# sourceMappingURL=routes-handler.d.ts.map
@@ -21,6 +21,7 @@ export default class RoutesHandler {
21
21
  * Whether this is running in build path mode (CF ADP using build output).
22
22
  */
23
23
  isBuildPathMode;
24
+ isWin32 = os.platform() === 'win32';
24
25
  /**
25
26
  * Constructor taking project as input.
26
27
  *
@@ -128,52 +129,92 @@ export default class RoutesHandler {
128
129
  try {
129
130
  const query = req.query;
130
131
  const controllerName = query.name;
132
+ const viewId = query.viewId;
131
133
  const codeExtFiles = await this.readAllFilesByGlob('/**/changes/*_codeExt.change');
132
- let controllerPathFromRoot = '';
133
- let controllerExists = false;
134
- let controllerPath = '';
135
- let changeFilePath = '';
136
- const project = this.util.getProject();
137
- const sourcePath = project.getSourcePath();
138
- const rootPath = this.util.getProject().getRootPath();
139
- const projectName = project.getName();
140
- const isTsSupported = isTypescriptSupported(rootPath);
141
- const getPath = (projectPath, fileName, folder = DirName.Coding) => path.join(projectPath, DirName.Changes, folder, fileName).split(path.sep).join(path.posix.sep);
142
- for (const file of codeExtFiles) {
143
- const fileStr = await file.getString();
144
- const change = JSON.parse(fileStr);
145
- if (change.selector.controllerName === controllerName) {
146
- const baseFileName = change.content.codeRef.replace('coding/', '');
147
- const fileName = isTsSupported ? baseFileName.replace('.js', '.ts') : baseFileName;
148
- controllerPath = getPath(sourcePath, fileName);
149
- controllerPathFromRoot = getPath(projectName, fileName);
150
- changeFilePath = getPath(projectName, file.getName(), '');
151
- controllerExists = true;
152
- break;
153
- }
154
- }
155
- if (controllerExists && !fs.existsSync(controllerPath)) {
156
- const errorMsg = `Please delete the change file at "${changeFilePath}" and retry creating the controller extension.`;
134
+ const lookup = await this.resolveControllerExtensions(codeExtFiles, controllerName, viewId);
135
+ const { baseControllerExists, baseControllerPath, baseControllerPathFromRoot, instanceControllerExists, instanceControllerPath, instanceControllerPathFromRoot, missingChangeFilePaths, isTsSupported } = lookup;
136
+ if (!baseControllerExists && !instanceControllerExists && missingChangeFilePaths.length > 0) {
137
+ const errorMsg = `Please delete the change file(s) at "${missingChangeFilePaths.join('", "')}" and retry creating the controller extension.`;
157
138
  this.logger.debug(errorMsg);
158
139
  res.status(HttpStatusCodes.NOT_FOUND).send({ message: errorMsg });
159
140
  return;
160
141
  }
161
142
  const isRunningInBAS = isAppStudio();
162
143
  this.sendFilesResponse(res, {
163
- controllerExists,
164
- controllerPath: os.platform() === 'win32' ? `/${controllerPath}` : controllerPath,
165
- controllerPathFromRoot,
144
+ baseControllerExists,
145
+ baseControllerPath: this.toResponsePath(baseControllerPath),
146
+ baseControllerPathFromRoot,
147
+ instanceControllerExists,
148
+ instanceControllerPath: this.toResponsePath(instanceControllerPath),
149
+ instanceControllerPathFromRoot,
166
150
  isRunningInBAS,
167
151
  isTsSupported
168
152
  });
169
- this.logger.debug(controllerExists
170
- ? `Controller exists at '${controllerPath}'`
171
- : `Controller with controllerName '${controllerName}' does not exist`);
153
+ this.logger.debug(`Controller '${controllerName}' existence — base: ${baseControllerExists}, instance (viewId '${viewId ?? ''}'): ${instanceControllerExists}`);
172
154
  }
173
155
  catch (e) {
174
156
  this.handleErrorMessage(res, next, e);
175
157
  }
176
158
  };
159
+ /**
160
+ * Resolves base and instance-specific controller extensions from the workspace's codeExt change files.
161
+ *
162
+ * @param codeExtFiles codeExt change files read from the workspace
163
+ * @param controllerName Controller name matched to each change's selector
164
+ * @param viewId Optional view ID used to detect an instance-specific extension for the current view
165
+ * @returns Existence flags and paths for base or instance controllers, plus any stale change reference
166
+ */
167
+ async resolveControllerExtensions(codeExtFiles, controllerName, viewId) {
168
+ const project = this.util.getProject();
169
+ const sourcePath = project.getSourcePath();
170
+ const projectName = project.getName();
171
+ const isTsSupported = isTypescriptSupported(project.getRootPath());
172
+ const getPath = (projectPath, fileName, folder = DirName.Coding) => path.join(projectPath, DirName.Changes, folder, fileName).split(path.sep).join(path.posix.sep);
173
+ const lookup = {
174
+ baseControllerExists: false,
175
+ baseControllerPath: '',
176
+ baseControllerPathFromRoot: '',
177
+ instanceControllerExists: false,
178
+ instanceControllerPath: '',
179
+ instanceControllerPathFromRoot: '',
180
+ missingChangeFilePaths: [],
181
+ isTsSupported
182
+ };
183
+ for (const file of codeExtFiles) {
184
+ const change = JSON.parse(await file.getString());
185
+ const changeViewId = change.content.viewId;
186
+ const isBase = !changeViewId;
187
+ const isInstanceForView = !!viewId && changeViewId === viewId;
188
+ if (change.selector.controllerName !== controllerName || (!isBase && !isInstanceForView)) {
189
+ continue;
190
+ }
191
+ const baseFileName = change.content.codeRef.replace('coding/', '');
192
+ const fileName = isTsSupported ? baseFileName.replace('.js', '.ts') : baseFileName;
193
+ const controllerPath = getPath(sourcePath, fileName);
194
+ const controllerPathFromRoot = getPath(projectName, fileName);
195
+ const changeFilePath = getPath(projectName, file.getName(), '');
196
+ if (!fs.existsSync(controllerPath)) {
197
+ lookup.missingChangeFilePaths.push(changeFilePath);
198
+ this.logger.debug(`Change file at "${changeFilePath}" references a missing controller at "${controllerPath}".`);
199
+ continue;
200
+ }
201
+ if (isBase) {
202
+ lookup.baseControllerExists = true;
203
+ lookup.baseControllerPath = controllerPath;
204
+ lookup.baseControllerPathFromRoot = controllerPathFromRoot;
205
+ }
206
+ else {
207
+ lookup.instanceControllerExists = true;
208
+ lookup.instanceControllerPath = controllerPath;
209
+ lookup.instanceControllerPathFromRoot = controllerPathFromRoot;
210
+ }
211
+ }
212
+ // A stale change file (missing controller on disk) is only fatal when no valid controller
213
+ // was found at all. If a valid base or instance controller exists alongside the stale entry,
214
+ // the 200 response reflects what is actually present and the debug log above provides
215
+ // server-side visibility of the dangling change file.
216
+ return lookup;
217
+ }
177
218
  /**
178
219
  * Handler for writing a controller extension file to the workspace.
179
220
  *
@@ -297,7 +338,7 @@ export default class RoutesHandler {
297
338
  const annotationExists = fs.existsSync(annotationPath);
298
339
  apiResponse[dataSourceId].annotationDetails = {
299
340
  fileName: path.parse(localAnnotationUri).base,
300
- annotationPath: os.platform() === 'win32' ? `/${annotationPath}` : annotationPath,
341
+ annotationPath: this.toResponsePath(annotationPath),
301
342
  annotationPathFromRoot,
302
343
  annotationExistsInWS: annotationExists
303
344
  };
@@ -319,6 +360,9 @@ export default class RoutesHandler {
319
360
  const variant = await getVariant(basePath);
320
361
  return await ManifestService.initMergedManifest(this.provider, basePath, variant, this.logger);
321
362
  }
363
+ toResponsePath(p) {
364
+ return p && this.isWin32 ? `/${p}` : p;
365
+ }
322
366
  }
323
367
  /**
324
368
  * Generates a controller file for the Adaptation Project based on the project's TypeScript support.
package/dist/types.d.ts CHANGED
@@ -335,6 +335,7 @@ export interface CodeExtChange extends CommonChangeProperties {
335
335
  changeType: 'codeExt';
336
336
  content: {
337
337
  codeRef: string;
338
+ viewId?: string;
338
339
  };
339
340
  selector: {
340
341
  controllerName: string;
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "bugs": {
11
11
  "url": "https://github.com/SAP/open-ux-tools/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Aadp-tooling"
12
12
  },
13
- "version": "1.0.43",
13
+ "version": "1.0.44",
14
14
  "license": "Apache-2.0",
15
15
  "author": "@SAP/ux-tools-team",
16
16
  "main": "dist/index.js",