@sap-ux/fe-fpm-writer 1.1.6 → 1.2.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.
- package/dist/common/validate.d.ts +9 -0
- package/dist/common/validate.js +20 -0
- package/dist/fragment/index.d.ts +17 -0
- package/dist/fragment/index.js +41 -0
- package/dist/fragment/types.d.ts +18 -0
- package/dist/fragment/types.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +4 -4
|
@@ -31,4 +31,13 @@ export declare function validateBasePath(basePath: string, fs?: Editor, dependen
|
|
|
31
31
|
* @returns {string} the error message
|
|
32
32
|
*/
|
|
33
33
|
export declare function getErrorMessage(error: Error | unknown): string;
|
|
34
|
+
/**
|
|
35
|
+
* Validates that a folder path is relative and does not contain path traversal sequences.
|
|
36
|
+
* This prevents security issues where malicious paths like '../../../etc' could write files outside the project.
|
|
37
|
+
*
|
|
38
|
+
* @param {string} folder - the folder path to validate
|
|
39
|
+
* @param {string} [paramName] - optional parameter name for error messages
|
|
40
|
+
* @throws {Error} if the path is absolute or contains '..'
|
|
41
|
+
*/
|
|
42
|
+
export declare function validateRelativePath(folder: string, paramName?: string): void;
|
|
34
43
|
//# sourceMappingURL=validate.d.ts.map
|
package/dist/common/validate.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { create as createStorage } from 'mem-fs';
|
|
2
2
|
import { create } from 'mem-fs-editor';
|
|
3
3
|
import { coerce, lt } from 'semver';
|
|
4
|
+
import { isAbsolute } from 'node:path';
|
|
4
5
|
import { getManifestPath } from './utils.js';
|
|
5
6
|
/**
|
|
6
7
|
* Validate that the UI5 version requirement is valid.
|
|
@@ -68,4 +69,23 @@ export async function validateBasePath(basePath, fs, dependencies = ['sap.fe.tem
|
|
|
68
69
|
export function getErrorMessage(error) {
|
|
69
70
|
return error instanceof Error ? error.message : String(error);
|
|
70
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Validates that a folder path is relative and does not contain path traversal sequences.
|
|
74
|
+
* This prevents security issues where malicious paths like '../../../etc' could write files outside the project.
|
|
75
|
+
*
|
|
76
|
+
* @param {string} folder - the folder path to validate
|
|
77
|
+
* @param {string} [paramName] - optional parameter name for error messages
|
|
78
|
+
* @throws {Error} if the path is absolute or contains '..'
|
|
79
|
+
*/
|
|
80
|
+
export function validateRelativePath(folder, paramName = 'Path') {
|
|
81
|
+
// Check for absolute paths
|
|
82
|
+
if (isAbsolute(folder)) {
|
|
83
|
+
throw new Error(`${paramName} must not be an absolute path, got: ${folder}`);
|
|
84
|
+
}
|
|
85
|
+
// Check for path traversal attempts by examining path segments
|
|
86
|
+
const segments = folder.split(/[/\\]/);
|
|
87
|
+
if (segments.includes('..')) {
|
|
88
|
+
throw new Error(`${paramName} must not contain '..' (path traversal), got: ${folder}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
71
91
|
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Editor } from 'mem-fs-editor';
|
|
2
|
+
import type { Fragment } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Generate a standalone fragment file with default content.
|
|
5
|
+
* Does NOT modify manifest.json - fragment-only generation.
|
|
6
|
+
*
|
|
7
|
+
* @param {string} basePath - the base path
|
|
8
|
+
* @param {Fragment} fragment - fragment generation configuration
|
|
9
|
+
* @param {Editor} [fs] - the mem-fs editor instance
|
|
10
|
+
* @returns {Promise<Editor>} the updated mem-fs editor instance
|
|
11
|
+
* @throws {Error} if the project folder is invalid or manifest.json cannot be found
|
|
12
|
+
* @throws {Error} if sap.fe.templates is missing from manifest.json dependencies (only FPM projects are supported)
|
|
13
|
+
* @throws {Error} if fragment.folder is an absolute path or contains path traversal sequences (..)
|
|
14
|
+
* @throws {Error} if fragment.name is an absolute path or contains path traversal sequences (..)
|
|
15
|
+
*/
|
|
16
|
+
export declare function generateFragment(basePath: string, fragment: Fragment, fs?: Editor): Promise<Editor>;
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { create as createStorage } from 'mem-fs';
|
|
2
|
+
import { create } from 'mem-fs-editor';
|
|
3
|
+
import { join, dirname } from 'node:path';
|
|
4
|
+
import { validateBasePath, validateRelativePath } from '../common/validate.js';
|
|
5
|
+
import { getDefaultFragmentContent } from '../common/defaults.js';
|
|
6
|
+
import { copyTpl, createIdGenerator } from '../common/file.js';
|
|
7
|
+
import { getTemplatePath } from '../templates.js';
|
|
8
|
+
import { getManifest } from '../common/utils.js';
|
|
9
|
+
/**
|
|
10
|
+
* Generate a standalone fragment file with default content.
|
|
11
|
+
* Does NOT modify manifest.json - fragment-only generation.
|
|
12
|
+
*
|
|
13
|
+
* @param {string} basePath - the base path
|
|
14
|
+
* @param {Fragment} fragment - fragment generation configuration
|
|
15
|
+
* @param {Editor} [fs] - the mem-fs editor instance
|
|
16
|
+
* @returns {Promise<Editor>} the updated mem-fs editor instance
|
|
17
|
+
* @throws {Error} if the project folder is invalid or manifest.json cannot be found
|
|
18
|
+
* @throws {Error} if sap.fe.templates is missing from manifest.json dependencies (only FPM projects are supported)
|
|
19
|
+
* @throws {Error} if fragment.folder is an absolute path or contains path traversal sequences (..)
|
|
20
|
+
* @throws {Error} if fragment.name is an absolute path or contains path traversal sequences (..)
|
|
21
|
+
*/
|
|
22
|
+
export async function generateFragment(basePath, fragment, fs) {
|
|
23
|
+
fs ??= create(createStorage());
|
|
24
|
+
await validateBasePath(basePath, fs);
|
|
25
|
+
const fnGenerateId = await createIdGenerator({ basePath, fsEditor: fs });
|
|
26
|
+
const { path: manifestPath } = await getManifest(basePath, fs);
|
|
27
|
+
// Calculate path for fragment with validation
|
|
28
|
+
const folder = fragment.folder ?? 'ext/fragment';
|
|
29
|
+
validateRelativePath(folder, 'Fragment folder');
|
|
30
|
+
validateRelativePath(fragment.name, 'Fragment name');
|
|
31
|
+
const path = join(dirname(manifestPath), folder);
|
|
32
|
+
// Generate default content if not provided
|
|
33
|
+
const content = fragment.content ?? getDefaultFragmentContent('Sample Text', fnGenerateId);
|
|
34
|
+
// Create fragment file
|
|
35
|
+
const viewPath = join(path, `${fragment.name}.fragment.xml`);
|
|
36
|
+
if (!fs.exists(viewPath)) {
|
|
37
|
+
copyTpl(fs, getTemplatePath('common/Fragment.xml'), viewPath, { content }, fnGenerateId);
|
|
38
|
+
}
|
|
39
|
+
return fs;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fragment generation configuration.
|
|
3
|
+
*/
|
|
4
|
+
export interface Fragment {
|
|
5
|
+
/**
|
|
6
|
+
* Fragment name (without .fragment.xml extension).
|
|
7
|
+
*/
|
|
8
|
+
name: string;
|
|
9
|
+
/**
|
|
10
|
+
* Optional folder path relative to webapp directory. Defaults to 'ext/fragment'.
|
|
11
|
+
*/
|
|
12
|
+
folder?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Optional XML content for the fragment. If not provided, a default fragment will be generated.
|
|
15
|
+
*/
|
|
16
|
+
content?: string;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=types.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export { TargetControl as ActionMenuTargetControl } from './action-menu/types.js
|
|
|
8
8
|
export { generateActionMenu } from './action-menu/index.js';
|
|
9
9
|
export type { CustomTableColumn } from './column/types.js';
|
|
10
10
|
export { generateCustomColumn } from './column/index.js';
|
|
11
|
+
export type { Fragment } from './fragment/types.js';
|
|
12
|
+
export { generateFragment } from './fragment/index.js';
|
|
11
13
|
export type { CustomHeaderSection, CustomSection, CustomSubSection } from './section/types.js';
|
|
12
14
|
export { RequestGroupId, DesignTime } from './section/types.js';
|
|
13
15
|
export { generateCustomSection, generateCustomSubSection, generateCustomHeaderSection } from './section/index.js';
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export { generateCustomAction } from './action/index.js';
|
|
|
4
4
|
export { TargetControl as ActionMenuTargetControl } from './action-menu/types.js';
|
|
5
5
|
export { generateActionMenu } from './action-menu/index.js';
|
|
6
6
|
export { generateCustomColumn } from './column/index.js';
|
|
7
|
+
export { generateFragment } from './fragment/index.js';
|
|
7
8
|
export { RequestGroupId, DesignTime } from './section/types.js';
|
|
8
9
|
export { generateCustomSection, generateCustomSubSection, generateCustomHeaderSection } from './section/index.js';
|
|
9
10
|
export { generateCustomFilter } from './filter/index.js';
|
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": "1.
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/SAP/open-ux-tools.git",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"semver": "7.8.4",
|
|
32
32
|
"xml-formatter": "3.7.0",
|
|
33
33
|
"xpath": "0.0.34",
|
|
34
|
-
"@sap-ux/fiori-annotation-api": "1.0.
|
|
34
|
+
"@sap-ux/fiori-annotation-api": "1.0.15",
|
|
35
35
|
"@sap-ux/i18n": "1.0.2",
|
|
36
36
|
"@sap-ux/project-access": "2.1.6",
|
|
37
|
-
"@sap-ux/logger": "1.0.
|
|
37
|
+
"@sap-ux/logger": "1.0.3"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@jest/globals": "30.4.1",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@types/mem-fs-editor": "7.0.1",
|
|
45
45
|
"@types/semver": "7.7.1",
|
|
46
46
|
"@types/vinyl": "2.0.12",
|
|
47
|
-
"@sap-ux/ui-prompting": "1.0.
|
|
47
|
+
"@sap-ux/ui-prompting": "1.0.7"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|
|
50
50
|
"node": ">=22.x"
|