@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,331 @@
|
|
|
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 { Logger } from '@xpack/logger'
|
|
15
|
+
import { ConfigurationError } from './errors.js'
|
|
16
|
+
|
|
17
|
+
// ============================================================================
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The default maximum number of combinations that can be generated.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* This constant defines the default limit for the total number of
|
|
24
|
+
* combinations that a {@link CombinationsGenerator} instance can produce.
|
|
25
|
+
* The limit exists to prevent performance issues and memory exhaustion when
|
|
26
|
+
* working with large matrices.
|
|
27
|
+
*
|
|
28
|
+
* This value can be overridden by providing a custom `maxCombinations`
|
|
29
|
+
* parameter when constructing a {@link CombinationsGenerator} instance.
|
|
30
|
+
*
|
|
31
|
+
* The limit is intentionally low (42 * 10).
|
|
32
|
+
*/
|
|
33
|
+
export const COMBINATIONS_GENERATOR_MAX_COMBINATIONS_LIMIT = 42 * 10
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A matrix combination mapping parameter names to their values.
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* This type represents a single combination generated from a matrix of
|
|
40
|
+
* parameters, where each key is a parameter name and each value is a
|
|
41
|
+
* string from that parameter's array of possible values.
|
|
42
|
+
*
|
|
43
|
+
* Example: `{ arch: 'x64', platform: 'linux', optimize: 'speed' }`
|
|
44
|
+
*/
|
|
45
|
+
export type MatrixCombination = Record<string, string>
|
|
46
|
+
|
|
47
|
+
// ============================================================================
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Configuration parameters for constructing a combinations generator instance.
|
|
51
|
+
*
|
|
52
|
+
* @remarks
|
|
53
|
+
* This interface defines the required configuration for creating an
|
|
54
|
+
* instance of {@link CombinationsGenerator}. All properties are mandatory.
|
|
55
|
+
*
|
|
56
|
+
* The parameters provide the matrix parameter names, their corresponding
|
|
57
|
+
* value arrays for Cartesian product computation, and the logger for
|
|
58
|
+
* diagnostic output during combination generation.
|
|
59
|
+
*/
|
|
60
|
+
export interface CombinationsGeneratorConstructorParameters {
|
|
61
|
+
/**
|
|
62
|
+
* The array of parameter names.
|
|
63
|
+
*/
|
|
64
|
+
matrixKeys: string[]
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The array of value arrays for each parameter.
|
|
68
|
+
*/
|
|
69
|
+
matrixValues: string[][]
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The logger instance for output and diagnostics.
|
|
73
|
+
*/
|
|
74
|
+
log: Logger
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Optional maximum combinations limit to prevent excessive generation.
|
|
78
|
+
*
|
|
79
|
+
* @remarks
|
|
80
|
+
* This parameter allows configuring a custom limit on the total number of
|
|
81
|
+
* combinations that can be generated. If the calculated total exceeds this
|
|
82
|
+
* limit, a {@link ConfigurationError} is thrown to prevent performance
|
|
83
|
+
* issues or memory exhaustion. The default value is 10,000 combinations.
|
|
84
|
+
*/
|
|
85
|
+
maxCombinations?: number
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Generates all possible combinations from a matrix of parameters.
|
|
90
|
+
*
|
|
91
|
+
* @remarks
|
|
92
|
+
* This class computes the Cartesian product of multiple parameter arrays,
|
|
93
|
+
* producing all possible combinations of parameter values using a
|
|
94
|
+
* memory-efficient generator pattern. It uses a recursive algorithm to
|
|
95
|
+
* systematically explore all combinations one at a time.
|
|
96
|
+
*
|
|
97
|
+
* The generation process:
|
|
98
|
+
*
|
|
99
|
+
* <ol>
|
|
100
|
+
* <li>Takes arrays of parameter names (keys) and their corresponding value
|
|
101
|
+
* arrays.</li>
|
|
102
|
+
* <li>Recursively iterates through each parameter, selecting one value at a
|
|
103
|
+
* time.</li>
|
|
104
|
+
* <li>Yields complete combinations one at a time without storing them all
|
|
105
|
+
* in memory.</li>
|
|
106
|
+
* <li>Backtracks to explore other value combinations.</li>
|
|
107
|
+
* </ol>
|
|
108
|
+
*
|
|
109
|
+
* Example usage:
|
|
110
|
+
* ```typescript
|
|
111
|
+
* const generator = new CombinationsGenerator({
|
|
112
|
+
* matrixKeys: ['arch', 'optimize'],
|
|
113
|
+
* matrixValues: [['x64', 'arm'], ['speed', 'size']],
|
|
114
|
+
* log
|
|
115
|
+
* });
|
|
116
|
+
* for (const combo of generator.generate()) {
|
|
117
|
+
* // Process one combination at a time without storing all in memory
|
|
118
|
+
* // Results:
|
|
119
|
+
* // { arch: 'x64', optimize: 'speed' }
|
|
120
|
+
* // { arch: 'x64', optimize: 'size' }
|
|
121
|
+
* // { arch: 'arm', optimize: 'speed' }
|
|
122
|
+
* // { arch: 'arm', optimize: 'size' }
|
|
123
|
+
* await processConfiguration(combo);
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export class CombinationsGenerator {
|
|
128
|
+
// --------------------------------------------------------------------------
|
|
129
|
+
// Protected Members.
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The logger instance for output and diagnostics.
|
|
133
|
+
*
|
|
134
|
+
* @remarks
|
|
135
|
+
* This logger provides trace-level diagnostics during combination
|
|
136
|
+
* generation, enabling visibility into the recursive exploration of the
|
|
137
|
+
* parameter space without impacting performance when tracing is disabled.
|
|
138
|
+
*/
|
|
139
|
+
protected readonly _log: Logger
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The array of parameter names.
|
|
143
|
+
*
|
|
144
|
+
* @remarks
|
|
145
|
+
* This array contains the names of all matrix parameters in the order
|
|
146
|
+
* they should be processed during combination generation. Each key
|
|
147
|
+
* corresponds to a parameter that will appear in the generated
|
|
148
|
+
* combinations.
|
|
149
|
+
*/
|
|
150
|
+
protected readonly _matrixKeys: string[]
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The array of value arrays for each parameter.
|
|
154
|
+
*
|
|
155
|
+
* @remarks
|
|
156
|
+
* This two-dimensional array contains the possible values for each
|
|
157
|
+
* parameter. The outer array corresponds one-to-one with
|
|
158
|
+
* <code>matrixKeys</code>, where <code>matrixValues[i]</code> contains
|
|
159
|
+
* all possible values for the parameter <code>matrixKeys[i]</code>.
|
|
160
|
+
*
|
|
161
|
+
* The Cartesian product of all these value arrays produces the complete
|
|
162
|
+
* set of combinations.
|
|
163
|
+
*/
|
|
164
|
+
protected readonly _matrixValues: string[][]
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* The maximum number of combinations allowed.
|
|
168
|
+
*
|
|
169
|
+
* @remarks
|
|
170
|
+
* This limit prevents excessive generation of combinations, protecting
|
|
171
|
+
* against performance issues and memory exhaustion.
|
|
172
|
+
*/
|
|
173
|
+
protected readonly _maxCombinations: number
|
|
174
|
+
|
|
175
|
+
// --------------------------------------------------------------------------
|
|
176
|
+
// Constructor.
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Constructs a combinations generator instance.
|
|
180
|
+
*
|
|
181
|
+
* @param matrixKeys - The array of parameter names.
|
|
182
|
+
* @param matrixValues - The array of value arrays for each parameter.
|
|
183
|
+
* @param log - The logger instance for output and diagnostics.
|
|
184
|
+
*
|
|
185
|
+
* @remarks
|
|
186
|
+
* The constructor validates that the structure of keys and values is
|
|
187
|
+
* correct and prepares the generator for combination generation. The
|
|
188
|
+
* actual generation is performed by calling `*generate`.
|
|
189
|
+
*/
|
|
190
|
+
constructor({
|
|
191
|
+
matrixKeys,
|
|
192
|
+
matrixValues,
|
|
193
|
+
maxCombinations = COMBINATIONS_GENERATOR_MAX_COMBINATIONS_LIMIT,
|
|
194
|
+
log,
|
|
195
|
+
}: CombinationsGeneratorConstructorParameters) {
|
|
196
|
+
this._log = log
|
|
197
|
+
this._matrixKeys = matrixKeys
|
|
198
|
+
this._matrixValues = matrixValues
|
|
199
|
+
this._maxCombinations = maxCombinations
|
|
200
|
+
|
|
201
|
+
log.trace(
|
|
202
|
+
`${CombinationsGenerator.name}.constructor: ` +
|
|
203
|
+
`matrixKeys=${JSON.stringify(this._matrixKeys)} ` +
|
|
204
|
+
`matrixValues=${JSON.stringify(this._matrixValues)}`
|
|
205
|
+
)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// --------------------------------------------------------------------------
|
|
209
|
+
// Public Methods.
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Generates combinations one at a time using a generator pattern.
|
|
213
|
+
*
|
|
214
|
+
* @remarks
|
|
215
|
+
* This method yields combinations one at a time instead of building the
|
|
216
|
+
* entire array in memory. This is particularly useful for large matrices
|
|
217
|
+
* where storing all combinations would be impractical.
|
|
218
|
+
*
|
|
219
|
+
* Memory efficiency:
|
|
220
|
+
*
|
|
221
|
+
* <ul>
|
|
222
|
+
* <li>For a matrix with 10 parameters and 5 values each (9,765,625
|
|
223
|
+
* combinations), only one combination object exists in memory at a
|
|
224
|
+
* time, regardless of matrix size.</li>
|
|
225
|
+
* <li>No array allocation or storage required.</li>
|
|
226
|
+
* <li>Immediate processing of each combination without waiting for all to
|
|
227
|
+
* be generated.</li>
|
|
228
|
+
* </ul>
|
|
229
|
+
*
|
|
230
|
+
* Example usage:
|
|
231
|
+
* ```typescript
|
|
232
|
+
* for (const combo of generator.generate()) {
|
|
233
|
+
* // Process one combination at a time
|
|
234
|
+
* await processConfiguration(combo)
|
|
235
|
+
* }
|
|
236
|
+
* ```
|
|
237
|
+
*
|
|
238
|
+
* <b>Yields:</b> Individual matrix combinations one at a time.
|
|
239
|
+
*/
|
|
240
|
+
*generate(): Generator<MatrixCombination> {
|
|
241
|
+
// Empty matrix produces no combinations
|
|
242
|
+
if (this._matrixKeys.length === 0) {
|
|
243
|
+
return
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Calculate total combinations
|
|
247
|
+
const totalCombinations = this._matrixValues.reduce(
|
|
248
|
+
(product, values) => product * values.length,
|
|
249
|
+
1
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
if (totalCombinations > this._maxCombinations) {
|
|
253
|
+
throw new ConfigurationError(
|
|
254
|
+
`Matrix would generate ${String(totalCombinations)} combinations, ` +
|
|
255
|
+
`exceeding limit of ${String(this._maxCombinations)}. ` +
|
|
256
|
+
`Consider using fewer parameters or values.`
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
yield* this._generateRecursively(0, {})
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// --------------------------------------------------------------------------
|
|
264
|
+
// Private Methods.
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Recursively generates combinations as a generator, yielding one at
|
|
268
|
+
* a time.
|
|
269
|
+
*
|
|
270
|
+
* @remarks
|
|
271
|
+
* This method implements the recursive algorithm for generating the
|
|
272
|
+
* Cartesian product of parameter values using the generator pattern.
|
|
273
|
+
*
|
|
274
|
+
* Algorithm steps:
|
|
275
|
+
*
|
|
276
|
+
* <ol>
|
|
277
|
+
* <li><b>Base case:</b> If all parameters have been assigned values
|
|
278
|
+
* (<code>index === matrixKeys.length</code>), yield a copy of the
|
|
279
|
+
* current combination and return.</li>
|
|
280
|
+
* <li><b>Recursive case:</b> For the parameter at the current index:
|
|
281
|
+
* <ul>
|
|
282
|
+
* <li>Iterate through all possible values for this parameter.</li>
|
|
283
|
+
* <li>Assign each value to the combination object.</li>
|
|
284
|
+
* <li>Recursively yield combinations for the next parameter using
|
|
285
|
+
* <code>yield*</code>.</li>
|
|
286
|
+
* <li>Remove the assigned value (backtrack) before trying the next
|
|
287
|
+
* value.</li>
|
|
288
|
+
* </ul>
|
|
289
|
+
* </li>
|
|
290
|
+
* </ol>
|
|
291
|
+
*
|
|
292
|
+
* The combination object is reused and modified during traversal, with
|
|
293
|
+
* only copies of complete combinations being yielded. This approach
|
|
294
|
+
* minimises memory allocation whilst maintaining correctness.
|
|
295
|
+
*
|
|
296
|
+
* @param index - The current parameter index being processed.
|
|
297
|
+
* @param combination - The partial combination being built.
|
|
298
|
+
*
|
|
299
|
+
* <b>Yields:</b> Complete combinations one at a time.
|
|
300
|
+
*/
|
|
301
|
+
protected *_generateRecursively(
|
|
302
|
+
index: number,
|
|
303
|
+
combination: Record<string, string>
|
|
304
|
+
): Generator<MatrixCombination> {
|
|
305
|
+
const log = this._log
|
|
306
|
+
log.trace(
|
|
307
|
+
`${CombinationsGenerator.name}.` +
|
|
308
|
+
`_generateRecursively(${String(index)},` +
|
|
309
|
+
`${JSON.stringify(combination)})`
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
if (index === this._matrixKeys.length) {
|
|
313
|
+
log.trace('combination complete =>', combination)
|
|
314
|
+
yield { ...combination }
|
|
315
|
+
|
|
316
|
+
return
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const key = this._matrixKeys[index]
|
|
320
|
+
const values = this._matrixValues[index]
|
|
321
|
+
|
|
322
|
+
for (const value of values) {
|
|
323
|
+
combination[key] = value
|
|
324
|
+
yield* this._generateRecursively(index + 1, combination)
|
|
325
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
326
|
+
delete combination[key]
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// ----------------------------------------------------------------------------
|
|
@@ -0,0 +1,337 @@
|
|
|
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 assert from 'node:assert'
|
|
15
|
+
import * as os from 'node:os'
|
|
16
|
+
|
|
17
|
+
import { Logger } from '@xpack/logger'
|
|
18
|
+
|
|
19
|
+
// ----------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
LiquidSubstitutionsVariables,
|
|
23
|
+
liquidSubstitutionsVariablesBase,
|
|
24
|
+
} from '../data/substitutions-variables.js'
|
|
25
|
+
import { isJsonObject } from '../functions/is-something.js'
|
|
26
|
+
import { Actions } from './actions.js'
|
|
27
|
+
import { BuildConfigurations } from './build-configurations.js'
|
|
28
|
+
import { LiquidEngine } from './liquid-engine.js'
|
|
29
|
+
import { JsonXpmPackage } from '../types/json.js'
|
|
30
|
+
|
|
31
|
+
// ============================================================================
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The property name used for the build folder relative path.
|
|
35
|
+
*/
|
|
36
|
+
export const buildFolderRelativePathPropertyName = 'buildFolderRelativePath'
|
|
37
|
+
|
|
38
|
+
// ============================================================================
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Configuration parameters for constructing a data model instance.
|
|
42
|
+
*
|
|
43
|
+
* @remarks
|
|
44
|
+
* This interface defines the required configuration for creating an
|
|
45
|
+
* instance of {@link DataModel}. Both properties are mandatory.
|
|
46
|
+
*
|
|
47
|
+
* The parameters provide the parsed <code>package.json</code> content
|
|
48
|
+
* containing package metadata and <b>xpm</b>-specific configuration, along
|
|
49
|
+
* with the logger for diagnostic output during data model initialization
|
|
50
|
+
* and template processing.
|
|
51
|
+
*/
|
|
52
|
+
export interface DataModelConstructorParameters {
|
|
53
|
+
/**
|
|
54
|
+
* The JSON package definition.
|
|
55
|
+
*/
|
|
56
|
+
jsonPackage: JsonXpmPackage
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The logger instance for output and diagnostics.
|
|
60
|
+
*/
|
|
61
|
+
log: Logger
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Represents a lazy-loading data model for an <b>xpm</b> package.
|
|
66
|
+
*
|
|
67
|
+
* @remarks
|
|
68
|
+
* This class prepares substitution variables, creates the Liquid
|
|
69
|
+
* engine, and exposes actions and build configurations defined in the package.
|
|
70
|
+
*
|
|
71
|
+
* The package processor serves as the top-level coordinator for all
|
|
72
|
+
* Liquid-based template processing in an <b>xpm</b> package. It establishes the
|
|
73
|
+
* foundation for variable substitution throughout the package hierarchy:
|
|
74
|
+
*
|
|
75
|
+
* <ol>
|
|
76
|
+
* <li>Initializes base substitution variables (platform detection, system
|
|
77
|
+
* information, etc.).</li>
|
|
78
|
+
* <li>Adds package-specific variables from <code>package.json</code>
|
|
79
|
+
* metadata.</li>
|
|
80
|
+
* <li>Merges user-defined properties from <code>xpack.properties</code>.</li>
|
|
81
|
+
* <li>Creates package-level actions accessible across all contexts.</li>
|
|
82
|
+
* <li>Creates build configurations, each inheriting the base substitution
|
|
83
|
+
* context and adding configuration-specific variables.</li>
|
|
84
|
+
* </ol>
|
|
85
|
+
*
|
|
86
|
+
* This hierarchical structure ensures that templates at any level have
|
|
87
|
+
* access to appropriate variables while maintaining clear scoping rules.
|
|
88
|
+
* Package-level actions are available globally, while configuration-level
|
|
89
|
+
* actions are scoped to their respective configurations.
|
|
90
|
+
*/
|
|
91
|
+
export class DataModel {
|
|
92
|
+
// --------------------------------------------------------------------------
|
|
93
|
+
// Public Members.
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The variables available for Liquid substitutions.
|
|
97
|
+
*
|
|
98
|
+
* @remarks
|
|
99
|
+
* This sealed object provides the base substitution context inherited by
|
|
100
|
+
* all actions and build configurations within the package.
|
|
101
|
+
*
|
|
102
|
+
* Variable hierarchy:
|
|
103
|
+
*
|
|
104
|
+
* <ol>
|
|
105
|
+
* <li><b>Base variables (xpmLiquidSubstitutionsVariablesBase):</b>
|
|
106
|
+
* <ul>
|
|
107
|
+
* <li><code>env</code>: Environment variables from process.env</li>
|
|
108
|
+
* <li><code>os</code>: Platform detection (platform, arch, endianness,
|
|
109
|
+
* version)</li>
|
|
110
|
+
* <li><code>path</code>: Path utilities (sep, delimiter, cwd)</li>
|
|
111
|
+
* </ul>
|
|
112
|
+
* </li>
|
|
113
|
+
* <li><b>Package metadata:</b>
|
|
114
|
+
* <ul>
|
|
115
|
+
* <li><code>package</code>: Complete <code>package.json</code> content
|
|
116
|
+
* (name, version,
|
|
117
|
+
* dependencies, etc.)</li>
|
|
118
|
+
* </ul>
|
|
119
|
+
* </li>
|
|
120
|
+
* <li><b>User-defined properties:</b>
|
|
121
|
+
* <ul>
|
|
122
|
+
* <li><code>properties</code>: Merged from
|
|
123
|
+
* <code>xpack.properties</code> if present</li>
|
|
124
|
+
* </ul>
|
|
125
|
+
* </li>
|
|
126
|
+
* </ol>
|
|
127
|
+
*
|
|
128
|
+
* The object is sealed after initialization to prevent accidental
|
|
129
|
+
* modification. Child components (actions and configurations) extend this
|
|
130
|
+
* context with their own scoped variables (configuration, matrix) without
|
|
131
|
+
* modifying the original sealed object.
|
|
132
|
+
*/
|
|
133
|
+
readonly substitutionsVariables: LiquidSubstitutionsVariables
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The actions collection for this package.
|
|
137
|
+
*
|
|
138
|
+
* @remarks
|
|
139
|
+
* This collection manages package-level actions defined in
|
|
140
|
+
* `xpack.actions`, which are globally accessible and not tied to specific
|
|
141
|
+
* build configurations.
|
|
142
|
+
*
|
|
143
|
+
* Package-level actions characteristics:
|
|
144
|
+
*
|
|
145
|
+
* <ol>
|
|
146
|
+
* <li>Created during construction but initially unpopulated.</li>
|
|
147
|
+
* <li>Populated during the collection's own initialisation when
|
|
148
|
+
* <code>Actions.initialise()</code> is called.</li>
|
|
149
|
+
* <li>Have access to package-level substitution variables but not
|
|
150
|
+
* configuration-specific variables.</li>
|
|
151
|
+
* <li>Suitable for package-wide tasks like testing, documentation
|
|
152
|
+
* generation, or global cleanup.</li>
|
|
153
|
+
* <li>Can be used alongside configuration-specific actions, which inherit
|
|
154
|
+
* from package-level actions.</li>
|
|
155
|
+
* </ol>
|
|
156
|
+
*/
|
|
157
|
+
readonly actions: Actions
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* The build configurations collection for this package.
|
|
161
|
+
*
|
|
162
|
+
* @remarks
|
|
163
|
+
* This collection manages all build configurations defined in
|
|
164
|
+
* `xpack.buildConfigurations`, supporting inheritance, template expansion,
|
|
165
|
+
* and configuration-specific properties and dependencies.
|
|
166
|
+
*
|
|
167
|
+
* Build configurations characteristics:
|
|
168
|
+
*
|
|
169
|
+
* <ol>
|
|
170
|
+
* <li>Created during construction but initially unpopulated.</li>
|
|
171
|
+
* <li>Populated during the collection's own initialisation when
|
|
172
|
+
* <code>BuildConfigurations.initialise()</code> is called.</li>
|
|
173
|
+
* <li>Each configuration inherits the package-level substitution variables
|
|
174
|
+
* and extends them with configuration-specific context.</li>
|
|
175
|
+
* <li>Support complex inheritance chains where configurations can inherit
|
|
176
|
+
* properties, dependencies, and actions from other configurations.</li>
|
|
177
|
+
* <li>Can be generated from templates with matrix expansion for
|
|
178
|
+
* multi-platform or multi-variant builds.</li>
|
|
179
|
+
* <li>Each configuration maintains its own actions collection, inheriting
|
|
180
|
+
* package-level actions and adding configuration-specific ones.</li>
|
|
181
|
+
* </ol>
|
|
182
|
+
*/
|
|
183
|
+
readonly buildConfigurations: BuildConfigurations
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* The logger instance for output and diagnostics.
|
|
187
|
+
*
|
|
188
|
+
* @remarks
|
|
189
|
+
* This logger provides trace-level diagnostics for the entire package
|
|
190
|
+
* processing hierarchy, including Liquid engine creation, variable
|
|
191
|
+
* initialization, action collection setup, and build configuration
|
|
192
|
+
* preparation. It's passed down to child components (actions and build
|
|
193
|
+
* configurations) to maintain consistent logging throughout the package
|
|
194
|
+
* lifecycle.
|
|
195
|
+
*/
|
|
196
|
+
protected readonly _log: Logger
|
|
197
|
+
|
|
198
|
+
// --------------------------------------------------------------------------
|
|
199
|
+
// Private Members.
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* The Liquid engine used for substitutions.
|
|
203
|
+
*
|
|
204
|
+
* @remarks
|
|
205
|
+
* This LiquidEngine instance is configured with strict mode and custom
|
|
206
|
+
* filters for xpm-specific operations. It's shared across all actions and
|
|
207
|
+
* build configurations within the package, ensuring consistent template
|
|
208
|
+
* processing behavior.
|
|
209
|
+
*
|
|
210
|
+
* Engine characteristics:
|
|
211
|
+
*
|
|
212
|
+
* <ol>
|
|
213
|
+
* <li>Strict mode enabled to catch undefined variable references.</li>
|
|
214
|
+
* <li>Custom filters for platform detection (<code>isPlatform</code>,
|
|
215
|
+
* <code>isArch</code>).</li>
|
|
216
|
+
* <li>Custom filters for path sanitization (<code>filterPath</code>,
|
|
217
|
+
* <code>filterPosixPath</code>,
|
|
218
|
+
* <code>filterWin32Path</code>).</li>
|
|
219
|
+
* <li>Shared instance reduces memory overhead and ensures consistent
|
|
220
|
+
* template evaluation across all package components.</li>
|
|
221
|
+
* </ol>
|
|
222
|
+
*/
|
|
223
|
+
protected readonly _engine: LiquidEngine
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* The JSON package definition.
|
|
227
|
+
*
|
|
228
|
+
* @remarks
|
|
229
|
+
* This object contains the complete `package.json` content, including both
|
|
230
|
+
* standard npm fields and xpm-specific extensions in the `xpack` section.
|
|
231
|
+
*
|
|
232
|
+
* Required structure:
|
|
233
|
+
*
|
|
234
|
+
* <ol>
|
|
235
|
+
* <li>Standard npm fields: name, version, dependencies, devDependencies.</li>
|
|
236
|
+
* <li>Required <code>xpack</code> section containing xpm-specific
|
|
237
|
+
* configuration.</li>
|
|
238
|
+
* <li>Optional <code>xpack.properties</code> for user-defined
|
|
239
|
+
* substitution variables.</li>
|
|
240
|
+
* <li>Optional <code>xpack.actions</code> for package-level executable
|
|
241
|
+
* actions.</li>
|
|
242
|
+
* <li>Optional <code>xpack.buildConfigurations</code> for build configuration
|
|
243
|
+
* definitions.</li>
|
|
244
|
+
* </ol>
|
|
245
|
+
*
|
|
246
|
+
* The package definition is validated during construction, requiring the
|
|
247
|
+
* `xpack` section to be present and be a valid JSON object.
|
|
248
|
+
*/
|
|
249
|
+
protected readonly _jsonPackage: JsonXpmPackage
|
|
250
|
+
|
|
251
|
+
// --------------------------------------------------------------------------
|
|
252
|
+
// Constructor.
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Constructs a Liquid package processor.
|
|
256
|
+
*
|
|
257
|
+
* @remarks
|
|
258
|
+
* The constructor initializes the Liquid engine and prepares the
|
|
259
|
+
* substitution variables context that will be inherited by all actions
|
|
260
|
+
* and build configurations.
|
|
261
|
+
*
|
|
262
|
+
* Initialization sequence:
|
|
263
|
+
*
|
|
264
|
+
* <ol>
|
|
265
|
+
* <li>Create <code>LiquidEngine</code> with custom filters and strict
|
|
266
|
+
* configuration.</li>
|
|
267
|
+
* <li>Validate <code>xpack</code> section exists in
|
|
268
|
+
* <code>package.json</code>.</li>
|
|
269
|
+
* <li>Initialize base substitution variables (os, platform, arch, etc.).</li>
|
|
270
|
+
* <li>Add package metadata to substitution context.</li>
|
|
271
|
+
* <li>Merge <code>xpack.properties</code> if defined, allowing user-defined
|
|
272
|
+
* variables.</li>
|
|
273
|
+
* <li>Seal substitution variables to prevent accidental modification.</li>
|
|
274
|
+
* <li>Create package-level actions collection (initially empty, populated
|
|
275
|
+
* during initialisation).</li>
|
|
276
|
+
* <li>Create build configurations collection (initially empty, populated
|
|
277
|
+
* during initialisation).</li>
|
|
278
|
+
* </ol>
|
|
279
|
+
*
|
|
280
|
+
* The substitution variables object is sealed to ensure immutability of
|
|
281
|
+
* the base context. Individual actions and configurations will extend this
|
|
282
|
+
* context with their own scoped variables without modifying the original.
|
|
283
|
+
*
|
|
284
|
+
* @param jsonPackage - The JSON package definition.
|
|
285
|
+
* @param log - The logger instance for output and diagnostics.
|
|
286
|
+
*/
|
|
287
|
+
constructor({ jsonPackage, log }: DataModelConstructorParameters) {
|
|
288
|
+
log.trace(`${DataModel.name}()`)
|
|
289
|
+
|
|
290
|
+
this._log = log
|
|
291
|
+
this._engine = new LiquidEngine()
|
|
292
|
+
|
|
293
|
+
assert(
|
|
294
|
+
isJsonObject(jsonPackage.xpack),
|
|
295
|
+
'xpack section missing in package.json'
|
|
296
|
+
)
|
|
297
|
+
this._jsonPackage = jsonPackage
|
|
298
|
+
|
|
299
|
+
// os.version() available since 12.x
|
|
300
|
+
assert(
|
|
301
|
+
typeof os.version === 'function',
|
|
302
|
+
'Mandatory os.version available only since 12.x'
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
this.substitutionsVariables = {
|
|
306
|
+
...liquidSubstitutionsVariablesBase,
|
|
307
|
+
package: jsonPackage,
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (isJsonObject(jsonPackage.xpack.properties)) {
|
|
311
|
+
this.substitutionsVariables.properties = {
|
|
312
|
+
...jsonPackage.xpack.properties,
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Prevent adding/removing properties.
|
|
317
|
+
Object.seal(this.substitutionsVariables)
|
|
318
|
+
|
|
319
|
+
// Empty actions.
|
|
320
|
+
this.actions = new Actions({
|
|
321
|
+
log: this._log,
|
|
322
|
+
engine: this._engine,
|
|
323
|
+
substitutionsVariables: this.substitutionsVariables,
|
|
324
|
+
jsonActions: this._jsonPackage.xpack.actions,
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
// Empty build configurations.
|
|
328
|
+
this.buildConfigurations = new BuildConfigurations({
|
|
329
|
+
log: this._log,
|
|
330
|
+
engine: this._engine,
|
|
331
|
+
substitutionsVariables: this.substitutionsVariables,
|
|
332
|
+
jsonBuildConfigurations: this._jsonPackage.xpack.buildConfigurations,
|
|
333
|
+
})
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ----------------------------------------------------------------------------
|