@sap-ux/fe-fpm-writer 0.35.14 → 0.36.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.
@@ -54,6 +54,7 @@ const semver_1 = require("semver");
54
54
  const project_access_1 = require("@sap-ux/project-access");
55
55
  const file_1 = require("../common/file");
56
56
  const utils_1 = require("../common/utils");
57
+ const xml_1 = require("./prompts/utils/xml");
57
58
  const PLACEHOLDERS = {
58
59
  'id': 'REPLACE_WITH_BUILDING_BLOCK_ID',
59
60
  'entitySet': 'REPLACE_WITH_ENTITY',
@@ -81,7 +82,7 @@ async function generateBuildingBlock(basePath, config, fs) {
81
82
  const xmlDocument = getUI5XmlDocument(basePath, viewOrFragmentPath, fs);
82
83
  const { content: manifest } = await (0, utils_1.getManifest)(basePath, fs);
83
84
  const templateDocument = getTemplateDocument(buildingBlockData, xmlDocument, fs, manifest);
84
- fs = updateViewFile(basePath, viewOrFragmentPath, aggregationPath, xmlDocument, templateDocument, fs);
85
+ fs = updateViewFile(basePath, viewOrFragmentPath, aggregationPath, xmlDocument, templateDocument, fs, config.replace);
85
86
  if (allowAutoAddDependencyLib && manifest && !(0, validate_1.validateDependenciesLibs)(manifest, ['sap.fe.macros'])) {
86
87
  // "sap.fe.macros" is missing - enhance manifest.json for missing "sap.fe.macros"
87
88
  const manifestPath = await (0, utils_1.getManifestPath)(basePath, fs);
@@ -125,21 +126,6 @@ function getUI5XmlDocument(basePath, viewPath, fs) {
125
126
  }
126
127
  return viewDocument;
127
128
  }
128
- /**
129
- * Returns the macros namespace from the xml document if it exists or creates a new one and returns it.
130
- *
131
- * @param {Document} ui5XmlDocument - the view/fragment xml file document
132
- * @returns {string} the macros namespace
133
- */
134
- function getOrAddMacrosNamespace(ui5XmlDocument) {
135
- const namespaceMap = ui5XmlDocument.firstChild._nsMap;
136
- const macrosNamespaceEntry = Object.entries(namespaceMap).find(([_, value]) => value === 'sap.fe.macros');
137
- if (!macrosNamespaceEntry) {
138
- ui5XmlDocument.firstChild._nsMap['macros'] = 'sap.fe.macros';
139
- ui5XmlDocument.documentElement.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:macros', 'sap.fe.macros');
140
- }
141
- return macrosNamespaceEntry ? macrosNamespaceEntry[0] : 'macros';
142
- }
143
129
  /**
144
130
  * Method returns default values for metadata path.
145
131
  *
@@ -219,7 +205,7 @@ function getTemplateContent(buildingBlockData, viewDocument, manifest, fs, usePl
219
205
  buildingBlockData.id = PLACEHOLDERS.id;
220
206
  }
221
207
  return (0, ejs_1.render)(fs.read(templateFilePath), {
222
- macrosNamespace: viewDocument ? getOrAddMacrosNamespace(viewDocument) : 'macros',
208
+ macrosNamespace: viewDocument ? (0, xml_1.getOrAddMacrosNamespace)(viewDocument) : 'macros',
223
209
  data: buildingBlockData
224
210
  }, {});
225
211
  }
@@ -267,16 +253,23 @@ function getTemplateDocument(buildingBlockData, viewDocument, fs, manifest) {
267
253
  * @param {Document} viewDocument - the view xml document
268
254
  * @param {Document} templateDocument - the template xml document
269
255
  * @param {Editor} [fs] - the memfs editor instance
256
+ * @param {boolean} [replace] - If true, replaces the target element with the template xml document;
257
+ * if false, appends the source node.
270
258
  * @returns {Editor} the updated memfs editor instance
271
259
  */
272
- function updateViewFile(basePath, viewPath, aggregationPath, viewDocument, templateDocument, fs) {
260
+ function updateViewFile(basePath, viewPath, aggregationPath, viewDocument, templateDocument, fs, replace = false) {
273
261
  const xpathSelect = xpath.useNamespaces(viewDocument.firstChild._nsMap);
274
262
  // Find target aggregated element and append template as child
275
263
  const targetNodes = xpathSelect(aggregationPath, viewDocument);
276
264
  if (targetNodes && Array.isArray(targetNodes) && targetNodes.length > 0) {
277
265
  const targetNode = targetNodes[0];
278
266
  const sourceNode = viewDocument.importNode(templateDocument.documentElement, true);
279
- targetNode.appendChild(sourceNode);
267
+ if (replace) {
268
+ targetNode.parentNode?.replaceChild(sourceNode, targetNode);
269
+ }
270
+ else {
271
+ targetNode.appendChild(sourceNode);
272
+ }
280
273
  // Serialize and format new view xml document
281
274
  const newXmlContent = new xmldom_1.XMLSerializer().serializeToString(viewDocument);
282
275
  fs.write((0, path_1.join)(basePath, viewPath), (0, xml_formatter_1.default)(newXmlContent));
@@ -2,4 +2,5 @@ export * from './building-blocks';
2
2
  export * from './chart';
3
3
  export * from './filter-bar';
4
4
  export * from './table';
5
+ export * from './page';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -18,4 +18,5 @@ __exportStar(require("./building-blocks"), exports);
18
18
  __exportStar(require("./chart"), exports);
19
19
  __exportStar(require("./filter-bar"), exports);
20
20
  __exportStar(require("./table"), exports);
21
+ __exportStar(require("./page"), exports);
21
22
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,12 @@
1
+ import type { Answers } from 'inquirer';
2
+ import type { PromptContext, Prompts } from '../../../prompts/types';
3
+ import type { BuildingBlockConfig, Page } from '../../types';
4
+ export type PagePromptsAnswer = BuildingBlockConfig<Page> & Answers;
5
+ /**
6
+ * Returns a list of prompts required to generate a page building block.
7
+ *
8
+ * @param context - prompt context including data about project
9
+ * @returns Prompt with questions for page.
10
+ */
11
+ export declare function getPageBuildingBlockPrompts(context: PromptContext): Promise<Prompts<PagePromptsAnswer>>;
12
+ //# sourceMappingURL=page.d.ts.map
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPageBuildingBlockPrompts = getPageBuildingBlockPrompts;
4
+ const i18n_1 = require("../../../i18n");
5
+ const utils_1 = require("../utils");
6
+ const types_1 = require("../../types");
7
+ /**
8
+ * Returns a list of prompts required to generate a page building block.
9
+ *
10
+ * @param context - prompt context including data about project
11
+ * @returns Prompt with questions for page.
12
+ */
13
+ async function getPageBuildingBlockPrompts(context) {
14
+ const t = (0, i18n_1.translate)(i18n_1.i18nNamespaces.buildingBlock, 'prompts.page.');
15
+ return {
16
+ questions: [
17
+ (0, utils_1.getViewOrFragmentPathPrompt)(context, t('viewOrFragmentPath.validate'), {
18
+ message: t('viewOrFragmentPath.message'),
19
+ guiOptions: {
20
+ mandatory: true,
21
+ dependantPromptNames: ['aggregationPath']
22
+ }
23
+ }),
24
+ (0, utils_1.getAggregationPathPrompt)(context, {
25
+ message: t('aggregation'),
26
+ guiOptions: {
27
+ mandatory: true
28
+ }
29
+ }),
30
+ (0, utils_1.getBuildingBlockIdPrompt)(context, t('id.validation'), {
31
+ message: t('id.message'),
32
+ default: 'Page',
33
+ guiOptions: {
34
+ mandatory: true
35
+ }
36
+ }),
37
+ {
38
+ type: 'input',
39
+ name: 'buildingBlockData.title',
40
+ message: t('title.message'),
41
+ guiOptions: {
42
+ mandatory: true
43
+ }
44
+ },
45
+ {
46
+ type: 'input',
47
+ name: 'buildingBlockData.description',
48
+ message: t('description.message')
49
+ }
50
+ ],
51
+ initialAnswers: {
52
+ buildingBlockData: {
53
+ buildingBlockType: types_1.BuildingBlockType.Page
54
+ }
55
+ }
56
+ };
57
+ }
58
+ //# sourceMappingURL=page.js.map
@@ -196,6 +196,7 @@ function getAggregationPathPrompt(context, properties = {}) {
196
196
  ...properties,
197
197
  type: 'list',
198
198
  name: 'aggregationPath',
199
+ defaultIndex: 0,
199
200
  choices: project
200
201
  ? (answers) => {
201
202
  const { viewOrFragmentPath } = answers;
@@ -24,4 +24,11 @@ export declare function getXPathStringsForXmlFile(xmlFilePath: string, fs: Edito
24
24
  * @returns an array of ids found in passed xml file.
25
25
  */
26
26
  export declare function getFilterBarIdsInFile(viewOrFragmentPath: string, fs: Editor): Promise<string[]>;
27
+ /**
28
+ * Returns the macros namespace from the xml document if it exists or creates a new one and returns it.
29
+ *
30
+ * @param {Document} ui5XmlDocument - the view/fragment xml file document
31
+ * @returns {string} the macros namespace
32
+ */
33
+ export declare function getOrAddMacrosNamespace(ui5XmlDocument: Document): string;
27
34
  //# sourceMappingURL=xml.d.ts.map
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isElementIdAvailable = isElementIdAvailable;
4
4
  exports.getXPathStringsForXmlFile = getXPathStringsForXmlFile;
5
5
  exports.getFilterBarIdsInFile = getFilterBarIdsInFile;
6
+ exports.getOrAddMacrosNamespace = getOrAddMacrosNamespace;
6
7
  const xmldom_1 = require("@xmldom/xmldom");
7
8
  /**
8
9
  * Method validates if passed id is available.
@@ -47,12 +48,23 @@ function getXPathStringsForXmlFile(xmlFilePath, fs) {
47
48
  };
48
49
  const xmlDocument = new xmldom_1.DOMParser({ errorHandler }).parseFromString(xmlContent);
49
50
  const nodes = [{ parentNode: '', node: xmlDocument.firstChild }];
51
+ // check macros namespace and page macro definition
52
+ const macrosNamespace = getOrAddMacrosNamespace(xmlDocument);
53
+ const pageMacroDefinition = macrosNamespace ? `${macrosNamespace}:Page` : 'macros:Page';
54
+ let hasPageMacroChild = false;
50
55
  while (nodes && nodes.length > 0) {
51
56
  const { parentNode, node } = nodes.shift();
52
57
  if (!node) {
53
58
  continue;
54
59
  }
55
- result[`${parentNode}/${node.nodeName}`] = augmentXpathWithLocalNames(`${parentNode}/${node.nodeName}`);
60
+ // If the current node does NOT have a <macros:Page> child, add <mvc:View> XPath to the result.
61
+ // This prevents suggesting insertion points outside macros:Page when a macros:Page is present.
62
+ hasPageMacroChild = Array.from(node.childNodes).some((child) => child.nodeType === child.ELEMENT_NODE &&
63
+ child.localName === 'Page' &&
64
+ child.nodeName === pageMacroDefinition);
65
+ if (!hasPageMacroChild) {
66
+ result[`${parentNode}/${node.nodeName}`] = augmentXpathWithLocalNames(`${parentNode}/${node.nodeName}`);
67
+ }
56
68
  const childNodes = Array.from(node.childNodes);
57
69
  for (const childNode of childNodes) {
58
70
  if (childNode.nodeType === childNode.ELEMENT_NODE) {
@@ -100,4 +112,19 @@ async function getFilterBarIdsInFile(viewOrFragmentPath, fs) {
100
112
  }
101
113
  return ids;
102
114
  }
115
+ /**
116
+ * Returns the macros namespace from the xml document if it exists or creates a new one and returns it.
117
+ *
118
+ * @param {Document} ui5XmlDocument - the view/fragment xml file document
119
+ * @returns {string} the macros namespace
120
+ */
121
+ function getOrAddMacrosNamespace(ui5XmlDocument) {
122
+ const namespaceMap = ui5XmlDocument.firstChild._nsMap;
123
+ const macrosNamespaceEntry = Object.entries(namespaceMap).find(([_, value]) => value === 'sap.fe.macros');
124
+ if (!macrosNamespaceEntry) {
125
+ ui5XmlDocument.firstChild._nsMap['macros'] = 'sap.fe.macros';
126
+ ui5XmlDocument.documentElement.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:macros', 'sap.fe.macros');
127
+ }
128
+ return macrosNamespaceEntry ? macrosNamespaceEntry[0] : 'macros';
129
+ }
103
130
  //# sourceMappingURL=xml.js.map
@@ -7,6 +7,7 @@ export declare enum BuildingBlockType {
7
7
  FilterBar = "filter-bar",
8
8
  Chart = "chart",
9
9
  Field = "field",
10
+ Page = "page",
10
11
  Table = "table"
11
12
  }
12
13
  /**
@@ -367,6 +368,24 @@ export interface Table extends BuildingBlock {
367
368
  */
368
369
  variantManagement?: string;
369
370
  }
371
+ /**
372
+ * Building block used to create a page.
373
+ * The page building block allows configuration of the title, and description.
374
+ *
375
+ * @example
376
+ * <macro:Page title="My Page Title" description="My Page Description" />
377
+ * @extends {BuildingBlock}
378
+ */
379
+ export interface Page extends BuildingBlock {
380
+ /**
381
+ * The title of the page.
382
+ */
383
+ title?: string;
384
+ /**
385
+ * The description of the page.
386
+ */
387
+ description?: string;
388
+ }
370
389
  /**
371
390
  * Input configuration for the generate function.
372
391
  */
@@ -390,5 +409,10 @@ export interface BuildingBlockConfig<T extends BuildingBlock> {
390
409
  * @default true
391
410
  */
392
411
  allowAutoAddDependencyLib?: boolean;
412
+ /**
413
+ * If true, replaces the element selected by aggregationPath in the view with the page building block.
414
+ * If false or undefined, the page building block will be appended.
415
+ */
416
+ replace?: boolean;
393
417
  }
394
418
  //# sourceMappingURL=types.d.ts.map
@@ -11,6 +11,7 @@ var BuildingBlockType;
11
11
  BuildingBlockType["FilterBar"] = "filter-bar";
12
12
  BuildingBlockType["Chart"] = "chart";
13
13
  BuildingBlockType["Field"] = "field";
14
+ BuildingBlockType["Page"] = "page";
14
15
  BuildingBlockType["Table"] = "table";
15
16
  })(BuildingBlockType || (exports.BuildingBlockType = BuildingBlockType = {}));
16
17
  //# sourceMappingURL=types.js.map
package/dist/index.d.ts CHANGED
@@ -12,9 +12,9 @@ export { CustomView } from './view/types';
12
12
  export { generateCustomView } from './view';
13
13
  export { enableFPM, FPMConfig } from './app';
14
14
  export { validateBasePath, validateVersion } from './common/validate';
15
- export { BuildingBlockType, FilterBar, Chart, Field, FieldFormatOptions, Table, BuildingBlockConfig } from './building-block/types';
15
+ export { BuildingBlockType, FilterBar, Chart, Field, FieldFormatOptions, Table, BuildingBlockConfig, Page } from './building-block/types';
16
16
  export { generateBuildingBlock, getSerializedFileContent } from './building-block';
17
- export { ChartPromptsAnswer, FilterBarPromptsAnswer, TablePromptsAnswer, BuildingBlockTypePromptsAnswer } from './building-block/prompts/questions';
17
+ export { ChartPromptsAnswer, FilterBarPromptsAnswer, TablePromptsAnswer, PagePromptsAnswer, BuildingBlockTypePromptsAnswer } from './building-block/prompts/questions';
18
18
  export { PromptsType, SupportedGeneratorAnswers, PromptsAPI, PromptsGroup, Prompts, ValidationResults, Answers, Subset, CodeSnippet } from './prompts';
19
19
  export { ControllerExtension, ControllerExtensionPageType } from './controller-extension/types';
20
20
  export { generateControllerExtension } from './controller-extension';
@@ -1,10 +1,11 @@
1
1
  import type { PromptContext, Prompts, Subset } from './types';
2
2
  import { PromptsType } from './types';
3
- import type { ChartPromptsAnswer, TablePromptsAnswer, FilterBarPromptsAnswer, BuildingBlockTypePromptsAnswer } from '../building-block/prompts/questions';
3
+ import type { ChartPromptsAnswer, TablePromptsAnswer, PagePromptsAnswer, FilterBarPromptsAnswer, BuildingBlockTypePromptsAnswer } from '../building-block/prompts/questions';
4
4
  import { generateBuildingBlock, getSerializedFileContent } from '../building-block';
5
5
  type AnswerMapping = {
6
6
  [PromptsType.Chart]: ChartPromptsAnswer;
7
7
  [PromptsType.Table]: TablePromptsAnswer;
8
+ [PromptsType.Page]: PagePromptsAnswer;
8
9
  [PromptsType.FilterBar]: FilterBarPromptsAnswer;
9
10
  [PromptsType.BuildingBlocks]: BuildingBlockTypePromptsAnswer;
10
11
  };
@@ -13,8 +14,8 @@ type BasePrompt<T extends keyof AnswerMapping> = {
13
14
  answers: AnswerMapping[T];
14
15
  initialAnswers?: Subset<AnswerMapping[T]>;
15
16
  };
16
- export type SupportedPrompts = BasePrompt<PromptsType.Chart> | BasePrompt<PromptsType.Table> | BasePrompt<PromptsType.FilterBar> | BasePrompt<PromptsType.BuildingBlocks>;
17
- export type SupportedGeneratorPrompts = BasePrompt<PromptsType.Chart> | BasePrompt<PromptsType.Table> | BasePrompt<PromptsType.FilterBar>;
17
+ export type SupportedPrompts = BasePrompt<PromptsType.Chart> | BasePrompt<PromptsType.Table> | BasePrompt<PromptsType.FilterBar> | BasePrompt<PromptsType.Page> | BasePrompt<PromptsType.BuildingBlocks>;
18
+ export type SupportedGeneratorPrompts = BasePrompt<PromptsType.Chart> | BasePrompt<PromptsType.Table> | BasePrompt<PromptsType.Page> | BasePrompt<PromptsType.FilterBar>;
18
19
  export type NarrowPrompt<T, N = SupportedPrompts> = N extends {
19
20
  type: T;
20
21
  } ? N : never;
@@ -26,12 +27,14 @@ export declare const PromptsGeneratorsMap: {
26
27
  chart: typeof generateBuildingBlock;
27
28
  table: typeof generateBuildingBlock;
28
29
  "filter-bar": typeof generateBuildingBlock;
30
+ page: typeof generateBuildingBlock;
29
31
  };
30
32
  export declare const PromptsCodePreviewMap: {
31
33
  chart: typeof getSerializedFileContent;
32
34
  table: typeof getSerializedFileContent;
33
35
  "filter-bar": typeof getSerializedFileContent;
36
+ page: typeof getSerializedFileContent;
34
37
  };
35
- export type SupportedGeneratorAnswers = TablePromptsAnswer | ChartPromptsAnswer | FilterBarPromptsAnswer;
38
+ export type SupportedGeneratorAnswers = TablePromptsAnswer | ChartPromptsAnswer | FilterBarPromptsAnswer | PagePromptsAnswer;
36
39
  export {};
37
40
  //# sourceMappingURL=map.d.ts.map
@@ -8,16 +8,19 @@ exports.PromptsQuestionsMap = {
8
8
  [types_1.PromptsType.Chart]: questions_1.getChartBuildingBlockPrompts,
9
9
  [types_1.PromptsType.Table]: questions_1.getTableBuildingBlockPrompts,
10
10
  [types_1.PromptsType.FilterBar]: questions_1.getFilterBarBuildingBlockPrompts,
11
- [types_1.PromptsType.BuildingBlocks]: questions_1.getBuildingBlockTypePrompts
11
+ [types_1.PromptsType.BuildingBlocks]: questions_1.getBuildingBlockTypePrompts,
12
+ [types_1.PromptsType.Page]: questions_1.getPageBuildingBlockPrompts
12
13
  };
13
14
  exports.PromptsGeneratorsMap = {
14
15
  [types_1.PromptsType.Chart]: building_block_1.generateBuildingBlock,
15
16
  [types_1.PromptsType.Table]: building_block_1.generateBuildingBlock,
16
- [types_1.PromptsType.FilterBar]: building_block_1.generateBuildingBlock
17
+ [types_1.PromptsType.FilterBar]: building_block_1.generateBuildingBlock,
18
+ [types_1.PromptsType.Page]: building_block_1.generateBuildingBlock
17
19
  };
18
20
  exports.PromptsCodePreviewMap = {
19
21
  [types_1.PromptsType.Chart]: building_block_1.getSerializedFileContent,
20
22
  [types_1.PromptsType.Table]: building_block_1.getSerializedFileContent,
21
- [types_1.PromptsType.FilterBar]: building_block_1.getSerializedFileContent
23
+ [types_1.PromptsType.FilterBar]: building_block_1.getSerializedFileContent,
24
+ [types_1.PromptsType.Page]: building_block_1.getSerializedFileContent
22
25
  };
23
26
  //# sourceMappingURL=map.js.map
@@ -182,6 +182,27 @@ declare const ns1: {
182
182
  tableSearchableToggle: string;
183
183
  valuesDependentOnEntityTypeInfo: string;
184
184
  };
185
+ page: {
186
+ id: {
187
+ message: string;
188
+ validation: string;
189
+ };
190
+ viewOrFragmentPath: {
191
+ message: string;
192
+ validation: string;
193
+ };
194
+ aggregation: string;
195
+ title: {
196
+ message: string;
197
+ validation: string;
198
+ translationAnnotation: string;
199
+ };
200
+ description: {
201
+ message: string;
202
+ validation: string;
203
+ translationAnnotation: string;
204
+ };
205
+ };
185
206
  };
186
207
  };
187
208
  export default ns1;
@@ -207,6 +207,27 @@ const ns1 = {
207
207
  'pasteFromClipboard': 'Enable Paste From Clipboard',
208
208
  'tableSearchableToggle': 'Table Searchable Toggle',
209
209
  'valuesDependentOnEntityTypeInfo': 'Values are dependent on entity set'
210
+ },
211
+ 'page': {
212
+ 'id': {
213
+ 'message': 'Building Block ID',
214
+ 'validation': 'An ID is required to generate the page building block.'
215
+ },
216
+ 'viewOrFragmentPath': {
217
+ 'message': 'View or Fragment File',
218
+ 'validation': 'A View or Fragment is required to generate the page building block.'
219
+ },
220
+ 'aggregation': 'Aggregation Path',
221
+ 'title': {
222
+ 'message': 'Page Title',
223
+ 'validation': 'Enter a Page Title',
224
+ 'translationAnnotation': 'Title of the Page.'
225
+ },
226
+ 'description': {
227
+ 'message': 'Page Description',
228
+ 'validation': 'Enter a Page Description',
229
+ 'translationAnnotation': 'Description of the Page.'
230
+ }
210
231
  }
211
232
  }
212
233
  };
@@ -6,6 +6,7 @@ export declare enum PromptsType {
6
6
  FilterBar = "filter-bar",
7
7
  Chart = "chart",
8
8
  Table = "table",
9
+ Page = "page",
9
10
  BuildingBlocks = "building-blocks"
10
11
  }
11
12
  export interface Prompts<T extends Answers = Answers> {
@@ -6,6 +6,7 @@ var PromptsType;
6
6
  PromptsType["FilterBar"] = "filter-bar";
7
7
  PromptsType["Chart"] = "chart";
8
8
  PromptsType["Table"] = "table";
9
+ PromptsType["Page"] = "page";
9
10
  PromptsType["BuildingBlocks"] = "building-blocks";
10
11
  })(PromptsType || (exports.PromptsType = PromptsType = {}));
11
12
  var CodeSnippetLanguage;
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.35.14",
4
+ "version": "0.36.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/SAP/open-ux-tools.git",
@@ -30,8 +30,8 @@
30
30
  "semver": "7.5.4",
31
31
  "xml-formatter": "2.6.1",
32
32
  "xpath": "0.0.33",
33
- "@sap-ux/fiori-annotation-api": "0.6.12",
34
- "@sap-ux/project-access": "1.30.9"
33
+ "@sap-ux/fiori-annotation-api": "0.6.13",
34
+ "@sap-ux/project-access": "1.30.10"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/inquirer": "8.2.6",
@@ -41,7 +41,7 @@
41
41
  "@types/semver": "7.5.2",
42
42
  "@types/vinyl": "2.0.7",
43
43
  "@sap-ux/i18n": "0.3.2",
44
- "@sap-ux/ui-prompting": "0.3.35"
44
+ "@sap-ux/ui-prompting": "0.3.37"
45
45
  },
46
46
  "engines": {
47
47
  "node": ">=20.x"
@@ -0,0 +1,5 @@
1
+ <<%- macrosNamespace %>:Page
2
+ id="<%- data.id %>"<% if (data.title) { %>
3
+ title="<%- data.title %>"<% } %><% if (data.description) { %>
4
+ description="<%- data.description %>"<% } %>
5
+ />