@sap-ux/fe-fpm-writer 0.14.3 → 0.15.0

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.
@@ -0,0 +1,14 @@
1
+ import type { Editor } from 'mem-fs-editor';
2
+ import type { ControllerExtension } from './types';
3
+ export declare const UI5_CONTROLLER_EXTENSION_LIST_REPORT = "sap.fe.templates.ListReport.ListReportController";
4
+ export declare const UI5_CONTROLLER_EXTENSION_OBJECT_PAGE = "sap.fe.templates.ObjectPage.ObjectPageController";
5
+ /**
6
+ * Add a controller extension to an existing UI5 application.
7
+ *
8
+ * @param {string} basePath - the base path
9
+ * @param {ControllerExtension} controllerConfig - the controller extension configuration
10
+ * @param {Editor} [fs] - the memfs editor instance
11
+ * @returns {Editor} the updated memfs editor instance
12
+ */
13
+ export declare function generateControllerExtension(basePath: string, controllerConfig: ControllerExtension, fs?: Editor): Editor;
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateControllerExtension = exports.UI5_CONTROLLER_EXTENSION_OBJECT_PAGE = exports.UI5_CONTROLLER_EXTENSION_LIST_REPORT = void 0;
4
+ const mem_fs_1 = require("mem-fs");
5
+ const mem_fs_editor_1 = require("mem-fs-editor");
6
+ const path_1 = require("path");
7
+ const ejs_1 = require("ejs");
8
+ const types_1 = require("./types");
9
+ const validate_1 = require("../common/validate");
10
+ const defaults_1 = require("../common/defaults");
11
+ const templates_1 = require("../templates");
12
+ exports.UI5_CONTROLLER_EXTENSION_LIST_REPORT = 'sap.fe.templates.ListReport.ListReportController';
13
+ exports.UI5_CONTROLLER_EXTENSION_OBJECT_PAGE = 'sap.fe.templates.ObjectPage.ObjectPageController';
14
+ const UI5_CONTROLLER_EXTENSIONS = 'sap.ui.controllerExtensions';
15
+ const EXTENSION_PAGE_TYPE_MAP = new Map([
16
+ [types_1.ControllerExtensionPageType.ListReport, exports.UI5_CONTROLLER_EXTENSION_LIST_REPORT],
17
+ [types_1.ControllerExtensionPageType.ObjectPage, exports.UI5_CONTROLLER_EXTENSION_OBJECT_PAGE]
18
+ ]);
19
+ /**
20
+ * A function appends passed array of values with new value if value does not exist in array.
21
+ *
22
+ * @param values - array of values
23
+ * @param value - value to append
24
+ * @returns Array of values
25
+ */
26
+ function appendUniqueEntryToArray(values, value) {
27
+ if (!values.includes(value)) {
28
+ values.push(value);
29
+ }
30
+ return values;
31
+ }
32
+ /**
33
+ * A function returns existing controller extension from manifest for passed extension id.
34
+ *
35
+ * @param {Manifest} manifest - manifest
36
+ * @param {string} extensionId - extension id
37
+ * @returns {ManifestControllerExtension | undefined} Existing controller extension
38
+ */
39
+ function getExistingControllerExtension(manifest, extensionId) {
40
+ var _a, _b, _c;
41
+ const extensions = (_c = (_b = (_a = manifest['sap.ui5']) === null || _a === void 0 ? void 0 : _a.extends) === null || _b === void 0 ? void 0 : _b.extensions) === null || _c === void 0 ? void 0 : _c[UI5_CONTROLLER_EXTENSIONS];
42
+ if (extensions === null || extensions === void 0 ? void 0 : extensions.hasOwnProperty(extensionId)) {
43
+ return extensions[extensionId];
44
+ }
45
+ return undefined;
46
+ }
47
+ /**
48
+ * Method enhances the provided controller extension by handling existing controller extension entry from manifest.
49
+ * Logic applies following:
50
+ * 1. Handles public property "overwrite" - if we should append or overwrite existing controller names.
51
+ * 2. Detects transition from "controllerName" to "controllerNames" when new controller is appended to exiusting entry with property "controllerNames".
52
+ * 3. Adds new controller entry to "controllerNames" array.
53
+ *
54
+ * @param {ManifestControllerExtension} manifestExtension - controller extension from manifest
55
+ * @param {InternalControllerExtension} config - internal controller extension configuration
56
+ * @param {string} controllerName - full name of new controller to add or replace/overwrite
57
+ */
58
+ function handleExistingManifestExtension(manifestExtension, config, controllerName) {
59
+ if (config.overwrite) {
60
+ if (manifestExtension.controllerNames) {
61
+ // Delete "controllerNames" from manifest because it will be overwritten by single controllerName
62
+ config.deleteProperty = 'controllerNames';
63
+ }
64
+ // Do not need append new controller with existing - exit further handling
65
+ return;
66
+ }
67
+ // Append new controller extension with existing controllers
68
+ if (manifestExtension.controllerName && manifestExtension.controllerName !== config.controllerName) {
69
+ // Manifest has single controller - transfer it into array
70
+ config.controllerNames = manifestExtension.controllerNames ? [...manifestExtension.controllerNames] : [];
71
+ // Check before append
72
+ appendUniqueEntryToArray(config.controllerNames, manifestExtension.controllerName);
73
+ appendUniqueEntryToArray(config.controllerNames, controllerName);
74
+ // Delete "controllerName" from manifest
75
+ config.deleteProperty = 'controllerName';
76
+ }
77
+ else if (manifestExtension.controllerNames && !manifestExtension.controllerNames.includes(controllerName)) {
78
+ // Manifest has array of controllers - append new entry
79
+ config.controllerNames = appendUniqueEntryToArray([...manifestExtension.controllerNames], controllerName);
80
+ }
81
+ }
82
+ /**
83
+ * Method enhances the provided controller extension configuration with default and additional data.
84
+ *
85
+ * @param {string} extensionName - a controller extension configuration object
86
+ * @returns {ControllerExtensionPageTarget | undefined} Page configuration object if extension name is assigned to supported page type.
87
+ */
88
+ function resolvePageDataFromExtension(extensionName) {
89
+ for (const [key, value] of EXTENSION_PAGE_TYPE_MAP) {
90
+ if (extensionName.startsWith(value)) {
91
+ return {
92
+ pageType: key
93
+ };
94
+ }
95
+ }
96
+ return undefined;
97
+ }
98
+ /**
99
+ * Method enhances the provided controller extension configuration with default and additional data.
100
+ *
101
+ * @param {ControllerExtension} data - a controller extension configuration object
102
+ * @param {string} manifestPath - path to the project's manifest.json
103
+ * @param {Manifest} manifest - the application manifest
104
+ * @returns enhanced configuration
105
+ */
106
+ function enhanceConfig(data, manifestPath, manifest) {
107
+ // clone input
108
+ const config = Object.assign({}, data);
109
+ // Apply default data
110
+ defaults_1.setCommonDefaults(config, manifestPath, manifest);
111
+ // Create `controllerName` with full path/namespace
112
+ config.controllerName = `${config.ns}.${config.name}`;
113
+ // Resolve controller extension id/key
114
+ let extensionId;
115
+ if (typeof config.extension === 'object') {
116
+ // Use default as List Report
117
+ config.extension.pageType = config.extension.pageType || types_1.ControllerExtensionPageType.ListReport;
118
+ const { pageType, pageId } = config.extension;
119
+ extensionId = EXTENSION_PAGE_TYPE_MAP.get(pageType) || exports.UI5_CONTROLLER_EXTENSION_LIST_REPORT;
120
+ if (pageId) {
121
+ // Prepend project id
122
+ extensionId = `${extensionId}#${manifest['sap.app'].id}::${pageId}`;
123
+ }
124
+ }
125
+ else {
126
+ // Try to resolve page type from manual extension
127
+ extensionId = config.extension;
128
+ config.extension = resolvePageDataFromExtension(config.extension) || config.extension;
129
+ }
130
+ config.extensionId = extensionId;
131
+ // Get existing controller extension entry from manifest
132
+ const manifestExtension = getExistingControllerExtension(manifest, extensionId);
133
+ // If controller extension already exists in manifest - append new controller
134
+ if (manifestExtension) {
135
+ handleExistingManifestExtension(manifestExtension, config, config.controllerName);
136
+ }
137
+ return config;
138
+ }
139
+ /**
140
+ * A function that transforms JSON object during JSON.stringify call.
141
+ * Method is used to remove 'controllerName' or 'controllerNames' properties from manifest in case when we have transition from 'controllerName' to 'controllerNames'.
142
+ *
143
+ * @param {InternalControllerExtension} config - a controller extension configuration object
144
+ * @returns Json replacer method
145
+ */
146
+ function getManifestReplacer(config) {
147
+ let isRoot = true;
148
+ const { deleteProperty } = config;
149
+ if (!deleteProperty) {
150
+ // No request to delete any property
151
+ return undefined;
152
+ }
153
+ return (key, value) => {
154
+ // Handle only root - more stable solution instead of checking 'key'
155
+ if (key === '' && isRoot) {
156
+ isRoot = false;
157
+ const extension = getExistingControllerExtension(value, config.extensionId);
158
+ if (extension) {
159
+ delete extension[deleteProperty];
160
+ }
161
+ }
162
+ return value;
163
+ };
164
+ }
165
+ /**
166
+ * Add a controller extension to an existing UI5 application.
167
+ *
168
+ * @param {string} basePath - the base path
169
+ * @param {ControllerExtension} controllerConfig - the controller extension configuration
170
+ * @param {Editor} [fs] - the memfs editor instance
171
+ * @returns {Editor} the updated memfs editor instance
172
+ */
173
+ function generateControllerExtension(basePath, controllerConfig, fs) {
174
+ // Validate the base and view paths
175
+ if (!fs) {
176
+ fs = mem_fs_editor_1.create(mem_fs_1.create());
177
+ }
178
+ validate_1.validateBasePath(basePath, fs);
179
+ const manifestPath = path_1.join(basePath, 'webapp/manifest.json');
180
+ const manifest = fs.readJSON(manifestPath);
181
+ // merge with defaults
182
+ const internalConfig = enhanceConfig(controllerConfig, manifestPath, manifest);
183
+ // enhance manifest with view definition
184
+ const filledTemplate = ejs_1.render(fs.read(templates_1.getTemplatePath('controller-extension/manifest.json')), internalConfig, {});
185
+ fs.extendJSON(manifestPath, JSON.parse(filledTemplate), getManifestReplacer(internalConfig));
186
+ // add controller js file
187
+ const ext = controllerConfig.typescript ? 'ts' : 'js';
188
+ const viewPath = path_1.join(internalConfig.path, `${internalConfig.name}.controller.${ext}`);
189
+ if (!fs.exists(viewPath)) {
190
+ fs.copyTpl(templates_1.getTemplatePath(`controller-extension/Controller.${ext}`), viewPath, internalConfig);
191
+ }
192
+ return fs;
193
+ }
194
+ exports.generateControllerExtension = generateControllerExtension;
195
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,61 @@
1
+ import type { CustomElement, InternalCustomElement } from '../common/types';
2
+ /**
3
+ * Controller extension's associated page type.
4
+ *
5
+ * @enum {string}
6
+ */
7
+ export declare enum ControllerExtensionPageType {
8
+ ObjectPage = "ObjectPage",
9
+ ListReport = "ListReport"
10
+ }
11
+ /**
12
+ * Target page configuration for controller extension.
13
+ */
14
+ export interface ControllerExtensionPageTarget {
15
+ /**
16
+ * The page type for which controller extension should be triggered.
17
+ */
18
+ pageType: ControllerExtensionPageType;
19
+ /**
20
+ * The unique page id for which controller extension should be triggered.
21
+ */
22
+ pageId?: string;
23
+ }
24
+ /**
25
+ * Controller extension configuration for the generate function.
26
+ */
27
+ export interface ControllerExtension extends CustomElement {
28
+ /**
29
+ * Property to define extension entry point.
30
+ * Provide any extension name as string or use page configuration.
31
+ */
32
+ extension: ControllerExtensionPageTarget | string;
33
+ /**
34
+ * Controls if controller(s) for existing controller extension should be appended or replaced with new controller.
35
+ */
36
+ overwrite?: boolean;
37
+ }
38
+ /**
39
+ * Represents a controller extension configuration in manifest.
40
+ */
41
+ export interface ManifestControllerExtension {
42
+ /**
43
+ * Specifies single controller for controller extension.
44
+ */
45
+ controllerName?: string;
46
+ /**
47
+ * Specifies multiple controllers for controller extension.
48
+ */
49
+ controllerNames?: string[];
50
+ }
51
+ export interface InternalControllerExtension extends ControllerExtension, ManifestControllerExtension, InternalCustomElement {
52
+ /**
53
+ * Derived full extension key/id in manifest "sap.ui.controllerExtensions" object.
54
+ */
55
+ extensionId: string;
56
+ /**
57
+ * Delete property from existing control extension object in manifest.
58
+ */
59
+ deleteProperty?: keyof ManifestControllerExtension;
60
+ }
61
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ControllerExtensionPageType = void 0;
4
+ /**
5
+ * Controller extension's associated page type.
6
+ *
7
+ * @enum {string}
8
+ */
9
+ var ControllerExtensionPageType;
10
+ (function (ControllerExtensionPageType) {
11
+ ControllerExtensionPageType["ObjectPage"] = "ObjectPage";
12
+ ControllerExtensionPageType["ListReport"] = "ListReport";
13
+ })(ControllerExtensionPageType = exports.ControllerExtensionPageType || (exports.ControllerExtensionPageType = {}));
14
+ //# sourceMappingURL=types.js.map
package/dist/index.d.ts CHANGED
@@ -12,4 +12,6 @@ export { enableFPM, FPMConfig } from './app';
12
12
  export { validateBasePath, validateVersion } from './common/validate';
13
13
  export { BuildingBlockType, FilterBar, Chart, Field, FieldFormatOptions } from './building-block/types';
14
14
  export { generateBuildingBlock } from './building-block';
15
+ export { ControllerExtension, ControllerExtensionPageType } from './controller-extension/types';
16
+ export { generateControllerExtension } from './controller-extension';
15
17
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateBuildingBlock = exports.BuildingBlockType = exports.validateVersion = exports.validateBasePath = exports.enableFPM = exports.generateCustomView = exports.generateCustomSection = exports.generateCustomColumn = exports.generateCustomAction = exports.TargetControl = exports.generateListReport = exports.generateObjectPage = exports.generateCustomPage = void 0;
3
+ exports.generateControllerExtension = exports.ControllerExtensionPageType = exports.generateBuildingBlock = exports.BuildingBlockType = exports.validateVersion = exports.validateBasePath = exports.enableFPM = exports.generateCustomView = exports.generateCustomSection = exports.generateCustomColumn = exports.generateCustomAction = exports.TargetControl = exports.generateListReport = exports.generateObjectPage = exports.generateCustomPage = void 0;
4
4
  var page_1 = require("./page");
5
5
  Object.defineProperty(exports, "generateCustomPage", { enumerable: true, get: function () { return page_1.generateCustomPage; } });
6
6
  Object.defineProperty(exports, "generateObjectPage", { enumerable: true, get: function () { return page_1.generateObjectPage; } });
@@ -24,4 +24,8 @@ var types_2 = require("./building-block/types");
24
24
  Object.defineProperty(exports, "BuildingBlockType", { enumerable: true, get: function () { return types_2.BuildingBlockType; } });
25
25
  var building_block_1 = require("./building-block");
26
26
  Object.defineProperty(exports, "generateBuildingBlock", { enumerable: true, get: function () { return building_block_1.generateBuildingBlock; } });
27
+ var types_3 = require("./controller-extension/types");
28
+ Object.defineProperty(exports, "ControllerExtensionPageType", { enumerable: true, get: function () { return types_3.ControllerExtensionPageType; } });
29
+ var controller_extension_1 = require("./controller-extension");
30
+ Object.defineProperty(exports, "generateControllerExtension", { enumerable: true, get: function () { return controller_extension_1.generateControllerExtension; } });
27
31
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sap-ux/fe-fpm-writer",
3
3
  "description": "SAP Fiori elements flexible programming model writer",
4
- "version": "0.14.3",
4
+ "version": "0.15.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/SAP/open-ux-tools.git",
@@ -0,0 +1,18 @@
1
+ sap.ui.define(['sap/ui/core/mvc/ControllerExtension'], function (ControllerExtension) {
2
+ 'use strict';
3
+
4
+ return ControllerExtension.extend('<%- ns %>.<%- name %>', {
5
+ // this section allows to extend lifecycle hooks or hooks provided by Fiori elements
6
+ override: {
7
+ /**
8
+ * Called when a controller is instantiated and its View controls (if available) are already created.
9
+ * Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization.
10
+ * @memberOf <%- ns %>.<%- name %>
11
+ */
12
+ onInit: function () {
13
+ // you can access the Fiori elements extensionAPI via this.base.getExtensionAPI
14
+ var oModel = this.base.getExtensionAPI().getModel();
15
+ }
16
+ }
17
+ });
18
+ });
@@ -0,0 +1,26 @@
1
+ import ControllerExtension from 'sap/ui/core/mvc/ControllerExtension';
2
+ import ExtensionAPI from 'sap/fe/<%- typeof extension === "object" ? `templates/${extension.pageType}` : "core" -%>/ExtensionAPI';
3
+
4
+ /**
5
+ * Definition of the override interface as workaround until https://github.com/SAP/ui5-typescript/issues/332 is fixed.
6
+ */
7
+ interface ExtensionOverride {
8
+ base: {
9
+ getExtensionAPI(): ExtensionAPI;
10
+ }
11
+ }
12
+
13
+ export default ControllerExtension.extend('<%- ns %>.<%- name %>', {
14
+ // this section allows to extend lifecycle hooks or hooks provided by Fiori elements
15
+ override: {
16
+ /**
17
+ * Called when a controller is instantiated and its View controls (if available) are already created.
18
+ * Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization.
19
+ * @memberOf <%- ns %>.<%- name %>
20
+ */
21
+ onInit(this: ExtensionOverride) {
22
+ // you can access the Fiori elements extensionAPI via this.base.getExtensionAPI
23
+ const model = this.base.getExtensionAPI().getModel();
24
+ }
25
+ }
26
+ });
@@ -0,0 +1,14 @@
1
+ {
2
+ "sap.ui5": {
3
+ "extends": {
4
+ "extensions": {
5
+ "sap.ui.controllerExtensions": {
6
+ "<%- extensionId -%>": {<%if (typeof controllerNames !== 'undefined') {%>
7
+ "controllerNames": <%- JSON.stringify(controllerNames) %><% } else {%>
8
+ "controllerName": "<%- controllerName %>"<% } %>
9
+ }
10
+ }
11
+ }
12
+ }
13
+ }
14
+ }