@xpack/xpm-lib 3.1.2 → 4.0.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/README.md +16 -212
- package/dist/classes/actions.d.ts +58 -0
- package/dist/classes/actions.d.ts.map +1 -0
- package/dist/classes/actions.js +250 -0
- package/dist/classes/actions.js.map +1 -0
- package/dist/classes/build-configurations.d.ts +78 -0
- package/dist/classes/build-configurations.d.ts.map +1 -0
- package/dist/classes/build-configurations.js +489 -0
- package/dist/classes/build-configurations.js.map +1 -0
- package/dist/classes/combinations-generator.d.ts +19 -0
- package/dist/classes/combinations-generator.d.ts.map +1 -0
- package/dist/classes/combinations-generator.js +48 -0
- package/dist/classes/combinations-generator.js.map +1 -0
- package/dist/classes/data-model.d.ts +21 -0
- package/dist/classes/data-model.d.ts.map +1 -0
- package/dist/classes/data-model.js +47 -0
- package/dist/classes/data-model.js.map +1 -0
- package/dist/classes/errors.d.ts +13 -0
- package/dist/classes/errors.d.ts.map +1 -0
- package/dist/classes/errors.js +13 -0
- package/dist/classes/errors.js.map +1 -0
- package/dist/classes/init-template-base.d.ts +47 -0
- package/dist/classes/init-template-base.d.ts.map +1 -0
- package/dist/classes/init-template-base.js +358 -0
- package/dist/classes/init-template-base.js.map +1 -0
- package/dist/classes/liquid-drop.d.ts +28 -0
- package/dist/classes/liquid-drop.d.ts.map +1 -0
- package/dist/classes/liquid-drop.js +70 -0
- package/dist/classes/liquid-drop.js.map +1 -0
- package/dist/classes/liquid-engine.d.ts +7 -0
- package/dist/classes/liquid-engine.d.ts.map +1 -0
- package/dist/classes/liquid-engine.js +72 -0
- package/dist/classes/liquid-engine.js.map +1 -0
- package/dist/classes/package.d.ts +31 -0
- package/dist/classes/package.d.ts.map +1 -0
- package/dist/classes/package.js +268 -0
- package/dist/classes/package.js.map +1 -0
- package/dist/classes/platform-detector.d.ts +14 -0
- package/dist/classes/platform-detector.d.ts.map +1 -0
- package/dist/classes/platform-detector.js +26 -0
- package/dist/classes/platform-detector.js.map +1 -0
- package/dist/classes/policies.d.ts +14 -0
- package/dist/classes/policies.d.ts.map +1 -0
- package/dist/classes/policies.js +20 -0
- package/dist/classes/policies.js.map +1 -0
- package/dist/classes/template-expander.d.ts +29 -0
- package/dist/classes/template-expander.d.ts.map +1 -0
- package/dist/classes/template-expander.js +62 -0
- package/dist/classes/template-expander.js.map +1 -0
- package/dist/data/substitutions-variables.d.ts +43 -0
- package/dist/data/substitutions-variables.d.ts.map +1 -0
- package/dist/{lib → data}/substitutions-variables.js +1 -16
- package/dist/data/substitutions-variables.js.map +1 -0
- package/dist/functions/chmod-recursively.d.ts +9 -0
- package/dist/functions/chmod-recursively.d.ts.map +1 -0
- package/dist/functions/chmod-recursively.js +66 -0
- package/dist/functions/chmod-recursively.js.map +1 -0
- package/dist/functions/filter-paths.d.ts +5 -0
- package/dist/functions/filter-paths.d.ts.map +1 -0
- package/dist/functions/filter-paths.js +16 -0
- package/dist/functions/filter-paths.js.map +1 -0
- package/dist/functions/is-something.d.ts +9 -0
- package/dist/functions/is-something.d.ts.map +1 -0
- package/dist/functions/is-something.js +25 -0
- package/dist/functions/is-something.js.map +1 -0
- package/dist/functions/matrix-expander.d.ts +17 -0
- package/dist/functions/matrix-expander.d.ts.map +1 -0
- package/dist/functions/matrix-expander.js +52 -0
- package/dist/functions/matrix-expander.js.map +1 -0
- package/dist/functions/perform-substitutions.d.ts +12 -0
- package/dist/functions/perform-substitutions.d.ts.map +1 -0
- package/dist/functions/perform-substitutions.js +76 -0
- package/dist/functions/perform-substitutions.js.map +1 -0
- package/dist/functions/utils.d.ts +8 -0
- package/dist/functions/utils.d.ts.map +1 -0
- package/dist/functions/utils.js +16 -0
- package/dist/functions/utils.js.map +1 -0
- package/dist/index.d.ts +22 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -29
- package/dist/index.js.map +1 -1
- package/dist/{lib/types.d.ts → types/json.d.ts} +31 -22
- package/dist/types/json.d.ts.map +1 -0
- package/dist/types/json.js +2 -0
- package/dist/types/json.js.map +1 -0
- package/dist/types/xpm-init-template.d.ts +21 -0
- package/dist/types/xpm-init-template.d.ts.map +1 -0
- package/dist/types/xpm-init-template.js +2 -0
- package/dist/types/xpm-init-template.js.map +1 -0
- package/dist/types/xpm.d.ts +16 -0
- package/dist/types/xpm.d.ts.map +1 -0
- package/dist/types/xpm.js +2 -0
- package/dist/types/xpm.js.map +1 -0
- package/package.json +53 -44
- package/src/CODE-REVIEW.md +2167 -0
- package/src/README.md +393 -6
- package/src/classes/actions.ts +1157 -0
- package/src/classes/build-configurations.ts +2127 -0
- package/src/classes/combinations-generator.ts +331 -0
- package/src/classes/data-model.ts +337 -0
- package/src/classes/errors.ts +105 -0
- package/src/classes/init-template-base.ts +1028 -0
- package/src/classes/liquid-drop.ts +376 -0
- package/src/classes/liquid-engine.ts +249 -0
- package/src/classes/package.ts +765 -0
- package/src/classes/platform-detector.ts +237 -0
- package/src/classes/policies.ts +200 -0
- package/src/classes/template-expander.ts +330 -0
- package/src/data/substitutions-variables.ts +390 -0
- package/src/functions/chmod-recursively.ts +195 -0
- package/src/functions/filter-paths.ts +126 -0
- package/src/functions/is-something.ts +223 -0
- package/src/functions/matrix-expander.ts +172 -0
- package/src/functions/perform-substitutions.ts +253 -0
- package/src/functions/utils.ts +151 -0
- package/src/index.ts +72 -19
- package/src/types/json.ts +519 -0
- package/src/types/xpm-init-template.ts +282 -0
- package/src/types/xpm.ts +162 -0
- package/dist/lib/chmod-recursive.d.ts +0 -7
- package/dist/lib/chmod-recursive.d.ts.map +0 -1
- package/dist/lib/chmod-recursive.js +0 -81
- package/dist/lib/chmod-recursive.js.map +0 -1
- package/dist/lib/errors.d.ts +0 -11
- package/dist/lib/errors.d.ts.map +0 -1
- package/dist/lib/errors.js +0 -26
- package/dist/lib/errors.js.map +0 -1
- package/dist/lib/functions/chmod-recursive.d.ts +0 -7
- package/dist/lib/functions/chmod-recursive.d.ts.map +0 -1
- package/dist/lib/functions/chmod-recursive.js +0 -81
- package/dist/lib/functions/chmod-recursive.js.map +0 -1
- package/dist/lib/functions/perform-substitutions.d.ts +0 -20
- package/dist/lib/functions/perform-substitutions.d.ts.map +0 -1
- package/dist/lib/functions/perform-substitutions.js +0 -85
- package/dist/lib/functions/perform-substitutions.js.map +0 -1
- package/dist/lib/functions/utils.d.ts +0 -30
- package/dist/lib/functions/utils.d.ts.map +0 -1
- package/dist/lib/functions/utils.js +0 -70
- package/dist/lib/functions/utils.js.map +0 -1
- package/dist/lib/init-template-base.d.ts +0 -46
- package/dist/lib/init-template-base.d.ts.map +0 -1
- package/dist/lib/init-template-base.js +0 -281
- package/dist/lib/init-template-base.js.map +0 -1
- package/dist/lib/liquid-actions.d.ts +0 -37
- package/dist/lib/liquid-actions.d.ts.map +0 -1
- package/dist/lib/liquid-actions.js +0 -148
- package/dist/lib/liquid-actions.js.map +0 -1
- package/dist/lib/liquid-build-configurations.d.ts +0 -47
- package/dist/lib/liquid-build-configurations.d.ts.map +0 -1
- package/dist/lib/liquid-build-configurations.js +0 -282
- package/dist/lib/liquid-build-configurations.js.map +0 -1
- package/dist/lib/liquid-drop.d.ts +0 -13
- package/dist/lib/liquid-drop.d.ts.map +0 -1
- package/dist/lib/liquid-drop.js +0 -56
- package/dist/lib/liquid-drop.js.map +0 -1
- package/dist/lib/liquid-engine.d.ts +0 -5
- package/dist/lib/liquid-engine.d.ts.map +0 -1
- package/dist/lib/liquid-engine.js +0 -85
- package/dist/lib/liquid-engine.js.map +0 -1
- package/dist/lib/liquid-package.d.ts +0 -17
- package/dist/lib/liquid-package.d.ts.map +0 -1
- package/dist/lib/liquid-package.js +0 -70
- package/dist/lib/liquid-package.js.map +0 -1
- package/dist/lib/package.d.ts +0 -66
- package/dist/lib/package.d.ts.map +0 -1
- package/dist/lib/package.js +0 -700
- package/dist/lib/package.js.map +0 -1
- package/dist/lib/perform-substitutions.d.ts +0 -20
- package/dist/lib/perform-substitutions.d.ts.map +0 -1
- package/dist/lib/perform-substitutions.js +0 -85
- package/dist/lib/perform-substitutions.js.map +0 -1
- package/dist/lib/policies.d.ts +0 -14
- package/dist/lib/policies.d.ts.map +0 -1
- package/dist/lib/policies.js +0 -33
- package/dist/lib/policies.js.map +0 -1
- package/dist/lib/substitutions-variables.d.ts +0 -117
- package/dist/lib/substitutions-variables.d.ts.map +0 -1
- package/dist/lib/substitutions-variables.js.map +0 -1
- package/dist/lib/types.d.ts.map +0 -1
- package/dist/lib/types.js +0 -13
- package/dist/lib/types.js.map +0 -1
- package/dist/lib/utils.d.ts +0 -30
- package/dist/lib/utils.d.ts.map +0 -1
- package/dist/lib/utils.js +0 -70
- package/dist/lib/utils.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/lib/errors.ts +0 -29
- package/src/lib/functions/chmod-recursive.ts +0 -103
- package/src/lib/functions/perform-substitutions.ts +0 -116
- package/src/lib/functions/utils.ts +0 -88
- package/src/lib/init-template-base.ts +0 -408
- package/src/lib/liquid-actions.ts +0 -223
- package/src/lib/liquid-build-configurations.ts +0 -433
- package/src/lib/liquid-drop.ts +0 -99
- package/src/lib/liquid-engine.ts +0 -135
- package/src/lib/liquid-package.ts +0 -108
- package/src/lib/package.ts +0 -947
- package/src/lib/policies.ts +0 -51
- package/src/lib/substitutions-variables.ts +0 -177
- package/src/lib/types.ts +0 -109
- package/src/package.json +0 -3
- package/src/tsconfig.json +0 -10
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the xPack project (http://xpack.github.io).
|
|
3
|
+
* Copyright (c) 2021-2026 Liviu Ionescu. All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* Permission to use, copy, modify, and/or distribute this software
|
|
6
|
+
* for any purpose is hereby granted, under the terms of the MIT license.
|
|
7
|
+
*
|
|
8
|
+
* If a copy of the license was not distributed with this file, it can
|
|
9
|
+
* be obtained from https://opensource.org/license/mit.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// ----------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
import { PlatformDetector } from '../classes/platform-detector.js'
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Replaces non-alphanumeric characters with dashes to make paths
|
|
20
|
+
* comply with file system names.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* This function sanitizes strings to be safely used as file or folder names
|
|
24
|
+
* by removing or replacing problematic characters that could cause issues
|
|
25
|
+
* across different file systems.
|
|
26
|
+
*
|
|
27
|
+
* Platform-specific processing:
|
|
28
|
+
*
|
|
29
|
+
* <ul>
|
|
30
|
+
* <li><b>Windows:</b> Preserves backslashes (<code>\\</code>) and colons
|
|
31
|
+
* (<code>:</code>) for drive letters
|
|
32
|
+
* and path separators (e.g., <code>C:\\path\\to\\file</code>). Replaces all
|
|
33
|
+
* other non-alphanumeric characters with dashes.</li>
|
|
34
|
+
* <li><b>POSIX (Linux, macOS):</b> Preserves forward slashes (<code>/</code>)
|
|
35
|
+
* for path separators. Replaces all other non-alphanumeric characters with
|
|
36
|
+
* dashes.</li>
|
|
37
|
+
* </ul>
|
|
38
|
+
*
|
|
39
|
+
* Post-processing: After character replacement, consecutive dashes are
|
|
40
|
+
* collapsed to a single dash to avoid excessive dashes from adjacent
|
|
41
|
+
* special characters (e.g., "foo--bar" becomes "foo-bar").
|
|
42
|
+
*
|
|
43
|
+
* Common use cases include sanitizing build configuration names,
|
|
44
|
+
* user-provided identifiers, and template-generated path components.
|
|
45
|
+
*
|
|
46
|
+
* @param input - A path candidate.
|
|
47
|
+
* @param platformDetector - The platform detector instance to use. Defaults
|
|
48
|
+
* to a new {@link PlatformDetector} instance.
|
|
49
|
+
* @returns A validated path.
|
|
50
|
+
*/
|
|
51
|
+
export function filterPath(
|
|
52
|
+
input: string,
|
|
53
|
+
platformDetector: PlatformDetector = new PlatformDetector()
|
|
54
|
+
): string {
|
|
55
|
+
const fixed = platformDetector.isWindows()
|
|
56
|
+
? input.replace(/[^a-zA-Z0-9\\:]+/g, '-')
|
|
57
|
+
: input.replace(/[^a-zA-Z0-9/]+/g, '-')
|
|
58
|
+
return fixed.replace(/--/g, '-')
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Replaces non-alphanumeric characters with dashes to make paths
|
|
63
|
+
* comply with POSIX file system names.
|
|
64
|
+
*
|
|
65
|
+
* @remarks
|
|
66
|
+
* This function provides explicit POSIX path sanitization regardless of the
|
|
67
|
+
* current platform. Useful when generating paths that will be used on
|
|
68
|
+
* Linux or macOS systems, or when consistency across platforms is required.
|
|
69
|
+
*
|
|
70
|
+
* Processing rules:
|
|
71
|
+
*
|
|
72
|
+
* <ul>
|
|
73
|
+
* <li>Preserves forward slashes (<code>/</code>) for path separators.</li>
|
|
74
|
+
* <li>Replaces all non-alphanumeric characters (except <code>/</code>) with
|
|
75
|
+
* dashes.</li>
|
|
76
|
+
* <li>Collapses consecutive dashes to single dashes.</li>
|
|
77
|
+
* </ul>
|
|
78
|
+
*
|
|
79
|
+
* Use this function instead of {@link filterPath} when you need guaranteed
|
|
80
|
+
* POSIX-style sanitization even when running on Windows, such as when
|
|
81
|
+
* generating paths for remote Linux systems or container images.
|
|
82
|
+
*
|
|
83
|
+
* @param input - A path candidate.
|
|
84
|
+
* @returns A validated path.
|
|
85
|
+
*/
|
|
86
|
+
export function filterPosixPath(input: string): string {
|
|
87
|
+
/* istanbul ignore next */
|
|
88
|
+
const fixed = input.replace(/[^a-zA-Z0-9/]+/g, '-')
|
|
89
|
+
|
|
90
|
+
return fixed.replace(/--/g, '-')
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Replaces non-alphanumeric characters with dashes to make paths
|
|
95
|
+
* comply with Windows file system names.
|
|
96
|
+
*
|
|
97
|
+
* @remarks
|
|
98
|
+
* This function provides explicit Windows path sanitization regardless of
|
|
99
|
+
* the current platform. Useful when generating paths that will be used on
|
|
100
|
+
* Windows systems, or when consistency across platforms is required.
|
|
101
|
+
*
|
|
102
|
+
* Processing rules:
|
|
103
|
+
*
|
|
104
|
+
* <ul>
|
|
105
|
+
* <li>Preserves backslashes (<code>\\</code>) for path separators.</li>
|
|
106
|
+
* <li>Preserves colons (<code>:</code>) for drive letter designation (e.g.,
|
|
107
|
+
* <code>C:</code>).</li>
|
|
108
|
+
* <li>Replaces all other non-alphanumeric characters with dashes.</li>
|
|
109
|
+
* <li>Collapses consecutive dashes to single dashes.</li>
|
|
110
|
+
* </ul>
|
|
111
|
+
*
|
|
112
|
+
* Use this function instead of {@link filterPath} when you need guaranteed
|
|
113
|
+
* Windows-style sanitization even when running on POSIX systems, such as
|
|
114
|
+
* when generating paths for remote Windows systems or WSL environments.
|
|
115
|
+
*
|
|
116
|
+
* @param input - A path candidate.
|
|
117
|
+
* @returns A validated path.
|
|
118
|
+
*/
|
|
119
|
+
export function filterWin32Path(input: string): string {
|
|
120
|
+
/* istanbul ignore next */
|
|
121
|
+
const fixed = input.replace(/[^a-zA-Z0-9\\:]+/g, '-')
|
|
122
|
+
|
|
123
|
+
return fixed.replace(/--/g, '-')
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ----------------------------------------------------------------------------
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the xPack project (http://xpack.github.io).
|
|
3
|
+
* Copyright (c) 2021-2026 Liviu Ionescu. All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* Permission to use, copy, modify, and/or distribute this software
|
|
6
|
+
* for any purpose is hereby granted, under the terms of the MIT license.
|
|
7
|
+
*
|
|
8
|
+
* If a copy of the license was not distributed with this file, it can
|
|
9
|
+
* be obtained from https://opensource.org/license/mit.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Determines whether a value is a JavaScript primitive.
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* In JavaScript, primitives are immutable values that are not objects:
|
|
19
|
+
* `string`, `number`, `bigint`, `boolean`, `undefined`, and `symbol`.
|
|
20
|
+
* This function
|
|
21
|
+
* also treats null as a primitive, following JavaScript's `typeof` behavior
|
|
22
|
+
* despite null being technically an object type.
|
|
23
|
+
*
|
|
24
|
+
* Returns `true` for: `string`, `number`, `bigint`, `boolean`, `undefined`,
|
|
25
|
+
* `symbol`, and `null`.
|
|
26
|
+
*
|
|
27
|
+
* Returns `false` for: objects, arrays, functions, and class instances.
|
|
28
|
+
*
|
|
29
|
+
* Useful for distinguishing between value types and reference types when
|
|
30
|
+
* processing JSON data or validating configuration inputs.
|
|
31
|
+
*
|
|
32
|
+
* @param value - The value to test.
|
|
33
|
+
* @returns `true` if the value is a primitive or `null`, `false` otherwise.
|
|
34
|
+
*/
|
|
35
|
+
export function isPrimitive(value: unknown): boolean {
|
|
36
|
+
return (
|
|
37
|
+
(typeof value !== 'object' && typeof value !== 'function') || value === null
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Determines whether a value is a string.
|
|
43
|
+
*
|
|
44
|
+
* @remarks
|
|
45
|
+
* This function acts as a TypeScript type guard, narrowing the type to
|
|
46
|
+
* `string` within conditional blocks. This enables safe string operations
|
|
47
|
+
* without type assertions.
|
|
48
|
+
*
|
|
49
|
+
* Example usage:
|
|
50
|
+
* ```typescript
|
|
51
|
+
* if (isString(value)) {
|
|
52
|
+
* // TypeScript knows value is a string here
|
|
53
|
+
* const length = value.length;
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* Only returns `true` for primitive string values, not String objects
|
|
58
|
+
* created with `new String()`.
|
|
59
|
+
*
|
|
60
|
+
* @param value - The value to test.
|
|
61
|
+
* @returns `true` if the value is a string, `false` otherwise.
|
|
62
|
+
*/
|
|
63
|
+
export function isString(value: unknown): boolean {
|
|
64
|
+
return typeof value === 'string'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Determines whether a value is a finite number.
|
|
69
|
+
*
|
|
70
|
+
* @remarks
|
|
71
|
+
* This function validates that a value is both a number type and
|
|
72
|
+
* mathematically finite, excluding `NaN`, `Infinity`, and `-Infinity`.
|
|
73
|
+
* This is essential when validating numeric configuration values or
|
|
74
|
+
* processing JSON data where numeric fields must contain valid,
|
|
75
|
+
* computable values.
|
|
76
|
+
*
|
|
77
|
+
* Returns `true` for: all finite numeric values, including `0`, negative
|
|
78
|
+
* numbers, and floating-point numbers.
|
|
79
|
+
*
|
|
80
|
+
* Returns `false` for: `NaN`, `Infinity`, `-Infinity`, strings, objects,
|
|
81
|
+
* arrays, and any non-number types.
|
|
82
|
+
*
|
|
83
|
+
* Only returns `true` for primitive number values, not Number objects
|
|
84
|
+
* created with `new Number()`.
|
|
85
|
+
*
|
|
86
|
+
* The finiteness check is crucial for mathematical operations and ensures
|
|
87
|
+
* that numeric properties in `package.json` or configuration files contain
|
|
88
|
+
* usable values rather than special numeric constants that could cause
|
|
89
|
+
* unexpected behaviour in calculations.
|
|
90
|
+
*
|
|
91
|
+
* @param value - The value to test.
|
|
92
|
+
* @returns `true` if the value is a finite number, `false` otherwise.
|
|
93
|
+
*/
|
|
94
|
+
export function isNumber(value: unknown): boolean {
|
|
95
|
+
return typeof value === 'number' && isFinite(value)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Determines whether a value is a boolean.
|
|
100
|
+
*
|
|
101
|
+
* @remarks
|
|
102
|
+
* Tests for primitive boolean values (`true` or `false`). Useful when
|
|
103
|
+
* validating configuration options or parsing JSON where boolean flags
|
|
104
|
+
* need to be distinguished from truthy/falsy values.
|
|
105
|
+
*
|
|
106
|
+
* Only returns `true` for the primitive boolean values `true` and `false`,
|
|
107
|
+
* not for boolean objects created with `new Boolean()`.
|
|
108
|
+
*
|
|
109
|
+
* Note: This does not check for truthy or falsy values - it only returns
|
|
110
|
+
* `true` for actual boolean primitives. Use standard JavaScript truthiness
|
|
111
|
+
* checks for conditional logic.
|
|
112
|
+
*
|
|
113
|
+
* @param value - The value to test.
|
|
114
|
+
* @returns `true` if the value is a boolean, `false` otherwise.
|
|
115
|
+
*/
|
|
116
|
+
export function isBoolean(value: unknown): boolean {
|
|
117
|
+
return typeof value === 'boolean'
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Determines whether a value is a non-array object.
|
|
122
|
+
*
|
|
123
|
+
* @remarks
|
|
124
|
+
* This function distinguishes between objects and arrays, which is crucial
|
|
125
|
+
* when processing JSON structures where both use the object type but require
|
|
126
|
+
* different handling.
|
|
127
|
+
*
|
|
128
|
+
* Returns `true` for: plain objects, class instances, null and other
|
|
129
|
+
* object types.
|
|
130
|
+
*
|
|
131
|
+
* Returns `false` for: arrays, primitives, and functions.
|
|
132
|
+
*
|
|
133
|
+
* Note: Arrays in JavaScript are objects, so this function explicitly
|
|
134
|
+
* excludes them using `Array.isArray()`. Use {@link isJsonObject} for
|
|
135
|
+
* stricter JSON object validation that also excludes `undefined` and `null`.
|
|
136
|
+
*
|
|
137
|
+
* @param value - The value to test.
|
|
138
|
+
* @returns `true` if the value is a non-array object, `false` otherwise.
|
|
139
|
+
*/
|
|
140
|
+
export function isObject(value: unknown): boolean {
|
|
141
|
+
return typeof value === 'object' && !Array.isArray(value)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ----------------------------------------------------------------------------
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Determines whether a value is a JSON object.
|
|
148
|
+
*
|
|
149
|
+
* @remarks
|
|
150
|
+
* Validates that a value represents a JSON object, which is stricter than
|
|
151
|
+
* JavaScript's general object type. This is essential when working with
|
|
152
|
+
* parsed JSON data or `package.json` structures.
|
|
153
|
+
*
|
|
154
|
+
* Returns `true` for: plain objects (non-null,
|
|
155
|
+
* non-primitive, non-array values).
|
|
156
|
+
*
|
|
157
|
+
* Returns `false` for: undefined, null, primitives (string, number,
|
|
158
|
+
* boolean, etc.), and arrays.
|
|
159
|
+
*
|
|
160
|
+
* This is the primary validation function for JSON objects in the <b>xpm</b>
|
|
161
|
+
* codebase, used extensively when parsing `package.json` sections like
|
|
162
|
+
* `xpack.properties`, `xpack.buildConfigurations`, etc.
|
|
163
|
+
*
|
|
164
|
+
* @param value - The value to test.
|
|
165
|
+
* @returns `true` if the value is a JSON object, `false` otherwise.
|
|
166
|
+
*/
|
|
167
|
+
export function isJsonObject(value: unknown): boolean {
|
|
168
|
+
return value !== undefined && !isPrimitive(value) && !Array.isArray(value)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Determines whether a value is a JSON array.
|
|
173
|
+
*
|
|
174
|
+
* @remarks
|
|
175
|
+
* Validates that a value represents a JSON array, excluding `undefined`.
|
|
176
|
+
* This ensures the value is a proper array that could have been parsed
|
|
177
|
+
* from JSON.
|
|
178
|
+
*
|
|
179
|
+
* Returns `true` for: any array, including empty arrays.
|
|
180
|
+
*
|
|
181
|
+
* Returns `false` for: undefined, null, objects, and primitives.
|
|
182
|
+
*
|
|
183
|
+
* The undefined check is important for distinguishing between optional
|
|
184
|
+
* properties that are missing (undefined) versus properties that are
|
|
185
|
+
* explicitly empty arrays. This is common in package.json where array
|
|
186
|
+
* fields may be absent or present but empty.
|
|
187
|
+
*
|
|
188
|
+
* @param value - The value to test.
|
|
189
|
+
* @returns `true` if the value is a JSON array, `false` otherwise.
|
|
190
|
+
*/
|
|
191
|
+
export function isJsonArray(value: unknown): boolean {
|
|
192
|
+
return value !== undefined && Array.isArray(value)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Determines whether a value is a non-empty JSON object.
|
|
197
|
+
*
|
|
198
|
+
* @remarks
|
|
199
|
+
* Combines JSON object validation with a non-empty check, ensuring the
|
|
200
|
+
* object has at least one property. This is useful for validating
|
|
201
|
+
* configuration sections that must contain data to be meaningful.
|
|
202
|
+
*
|
|
203
|
+
* Returns `true` for: objects with one or more enumerable properties.
|
|
204
|
+
*
|
|
205
|
+
* Returns `false` for: empty objects `{}`, undefined, null, primitives,
|
|
206
|
+
* arrays, and any non-object types.
|
|
207
|
+
*
|
|
208
|
+
* The enumerable properties check uses `Object.keys()`, which only counts
|
|
209
|
+
* own enumerable string-keyed properties, not inherited properties or
|
|
210
|
+
* symbol-keyed properties.
|
|
211
|
+
*
|
|
212
|
+
* Common use cases include validating `xpack.actions`, `xpack.dependencies`,
|
|
213
|
+
* and other `package.json` sections where an empty object would be
|
|
214
|
+
* meaningless.
|
|
215
|
+
*
|
|
216
|
+
* @param value - The value to test.
|
|
217
|
+
* @returns `true` if the value is a non-empty JSON object, `false` otherwise.
|
|
218
|
+
*/
|
|
219
|
+
export function isNonEmptyJsonObject(value: unknown): boolean {
|
|
220
|
+
return isJsonObject(value) && Object.keys(value as object).length > 0
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ----------------------------------------------------------------------------
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the xPack project (http://xpack.github.io).
|
|
3
|
+
* Copyright (c) 2021-2026 Liviu Ionescu. All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* Permission to use, copy, modify, and/or distribute this software
|
|
6
|
+
* for any purpose is hereby granted, under the terms of the MIT license.
|
|
7
|
+
*
|
|
8
|
+
* If a copy of the license was not distributed with this file, it can
|
|
9
|
+
* be obtained from https://opensource.org/license/mit.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// ----------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
import * as os from 'node:os'
|
|
15
|
+
|
|
16
|
+
import { Logger } from '@xpack/logger'
|
|
17
|
+
|
|
18
|
+
// ----------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
import { LiquidEngine } from '../classes/liquid-engine.js'
|
|
21
|
+
import { LiquidSubstitutionsVariables } from '../data/substitutions-variables.js'
|
|
22
|
+
import { ConfigurationError } from '../classes/errors.js'
|
|
23
|
+
import { isJsonArray, isString } from './is-something.js'
|
|
24
|
+
import { performSubstitutions } from './perform-substitutions.js'
|
|
25
|
+
import { hasLiquidSyntax } from './utils.js'
|
|
26
|
+
import { getErrorMessage } from './utils.js'
|
|
27
|
+
import { JsonTemplateMatrix } from '../types/json.js'
|
|
28
|
+
|
|
29
|
+
// ============================================================================
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Result of matrix validation and processing.
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* This interface encapsulates the processed matrix data ready for
|
|
36
|
+
* Cartesian product generation.
|
|
37
|
+
*/
|
|
38
|
+
export interface ProcessedMatrix {
|
|
39
|
+
/**
|
|
40
|
+
* Array of matrix parameter names.
|
|
41
|
+
*/
|
|
42
|
+
matrixKeys: string[]
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Array of value arrays for each parameter.
|
|
46
|
+
*/
|
|
47
|
+
matrixValues: string[][]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ============================================================================
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Validates and processes a matrix object for template expansion.
|
|
54
|
+
*
|
|
55
|
+
* @remarks
|
|
56
|
+
* This function extracts common matrix processing logic used by both
|
|
57
|
+
* actions and build configurations template expansion. It validates the
|
|
58
|
+
* matrix structure, performs Liquid substitutions on matrix values if needed,
|
|
59
|
+
* and prepares the data for Cartesian product generation.
|
|
60
|
+
*
|
|
61
|
+
* Processing steps:
|
|
62
|
+
*
|
|
63
|
+
* <ol>
|
|
64
|
+
* <li>Validates that each matrix property is an array of strings.</li>
|
|
65
|
+
* <li>For each matrix parameter:
|
|
66
|
+
* <ul>
|
|
67
|
+
* <li>Collects the parameter name (key).</li>
|
|
68
|
+
* <li>Joins array values with line breaks for substitution.</li>
|
|
69
|
+
* <li>If values contain Liquid syntax, performs substitutions.</li>
|
|
70
|
+
* <li>Splits the result back into individual values.</li>
|
|
71
|
+
* </ul>
|
|
72
|
+
* </li>
|
|
73
|
+
* <li>Returns processed matrix keys and values ready for combination
|
|
74
|
+
* generation.</li>
|
|
75
|
+
* </ol>
|
|
76
|
+
*
|
|
77
|
+
* Matrix value substitution enables dynamic matrix generation where matrix
|
|
78
|
+
* values themselves can reference other substitution variables, enabling
|
|
79
|
+
* flexible configuration without hardcoding platform-specific or
|
|
80
|
+
* environment-specific values.
|
|
81
|
+
*
|
|
82
|
+
* @param matrix - The matrix object from JSON template.
|
|
83
|
+
* @param templateName - The template name for error messages.
|
|
84
|
+
* @param templateType - The template type ('action' or 'buildConfiguration')
|
|
85
|
+
* for error messages.
|
|
86
|
+
* @param engine - The Liquid engine for substitutions.
|
|
87
|
+
* @param substitutionsVariables - The variables available for substitution.
|
|
88
|
+
* @param log - The logger instance for diagnostics.
|
|
89
|
+
* @returns The processed matrix keys and values.
|
|
90
|
+
*
|
|
91
|
+
* @throws {@link ConfigurationError}
|
|
92
|
+
* If the matrix structure is invalid or substitution fails.
|
|
93
|
+
*/
|
|
94
|
+
export async function processMatrixForExpansion({
|
|
95
|
+
matrix,
|
|
96
|
+
templateName,
|
|
97
|
+
templateType,
|
|
98
|
+
engine,
|
|
99
|
+
substitutionsVariables,
|
|
100
|
+
log,
|
|
101
|
+
}: {
|
|
102
|
+
matrix: JsonTemplateMatrix
|
|
103
|
+
templateName: string
|
|
104
|
+
templateType: 'action' | 'buildConfiguration'
|
|
105
|
+
engine: LiquidEngine
|
|
106
|
+
substitutionsVariables: LiquidSubstitutionsVariables
|
|
107
|
+
log: Logger
|
|
108
|
+
}): Promise<ProcessedMatrix> {
|
|
109
|
+
const matrixKeys: string[] = []
|
|
110
|
+
const matrixValues: string[][] = []
|
|
111
|
+
|
|
112
|
+
for (const [matrixKey, matrixValueArray] of Object.entries(matrix)) {
|
|
113
|
+
if (!isJsonArray(matrixValueArray)) {
|
|
114
|
+
throw new ConfigurationError(
|
|
115
|
+
`${templateType} "${templateName}" ` +
|
|
116
|
+
`matrix.${matrixKey} is not an array`
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (matrixValueArray.length === 0) {
|
|
121
|
+
throw new ConfigurationError(
|
|
122
|
+
`${templateType} "${templateName}" ` +
|
|
123
|
+
`matrix.${matrixKey} cannot be empty`
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Type assertion after validation
|
|
128
|
+
const validatedArray = matrixValueArray as unknown[]
|
|
129
|
+
|
|
130
|
+
for (const matrixValue of validatedArray) {
|
|
131
|
+
if (!isString(matrixValue)) {
|
|
132
|
+
throw new ConfigurationError(
|
|
133
|
+
`${templateType} "${templateName}" ` +
|
|
134
|
+
`matrix.${matrixKey} value is not a string`
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
matrixKeys.push(matrixKey)
|
|
140
|
+
const stringValue = (validatedArray as string[]).join(os.EOL)
|
|
141
|
+
|
|
142
|
+
if (hasLiquidSyntax(stringValue)) {
|
|
143
|
+
let substitutedValue
|
|
144
|
+
try {
|
|
145
|
+
substitutedValue = await performSubstitutions({
|
|
146
|
+
input: stringValue,
|
|
147
|
+
engine,
|
|
148
|
+
substitutionsVariables,
|
|
149
|
+
log,
|
|
150
|
+
})
|
|
151
|
+
} catch (error) {
|
|
152
|
+
const message =
|
|
153
|
+
getErrorMessage(error) +
|
|
154
|
+
` in ${templateType} "${templateName}" ` +
|
|
155
|
+
`matrix substitution`
|
|
156
|
+
throw new ConfigurationError(message)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Split back into array, removing trailing newline if present
|
|
160
|
+
matrixValues.push(
|
|
161
|
+
substitutedValue.replace(new RegExp(os.EOL + '$'), '').split(os.EOL)
|
|
162
|
+
)
|
|
163
|
+
} else {
|
|
164
|
+
// Type assertion safe here after validation
|
|
165
|
+
matrixValues.push(validatedArray as string[])
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return { matrixKeys, matrixValues }
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ----------------------------------------------------------------------------
|