@ui5/builder 3.0.9 → 3.1.1

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/CHANGELOG.md CHANGED
@@ -2,10 +2,30 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
  This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
4
4
 
5
- A list of unreleased changes can be found [here](https://github.com/SAP/ui5-builder/compare/v3.0.9...HEAD).
5
+ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-builder/compare/v3.1.1...HEAD).
6
+
7
+ <a name="v3.1.1"></a>
8
+ ## [v3.1.1] - 2023-11-19
9
+ ### Bug Fixes
10
+ - Handle graceful termination of workerpool for parallel builds ([#953](https://github.com/SAP/ui5-builder/issues/953)) [`f7b9f27`](https://github.com/SAP/ui5-builder/commit/f7b9f27ac5966bd89e52e4c2d5b03482a0f3dbb7)
11
+ - **Bundling:** Detect manifest.json dependency of libraries [`6f9995f`](https://github.com/SAP/ui5-builder/commit/6f9995f5b47a6094fa93b5d433be849b1d3cdc7e)
12
+
13
+
14
+ <a name="v3.1.0"></a>
15
+ ## [v3.1.0] - 2023-10-11
16
+ ### Bug Fixes
17
+ - **bundle/Builder:** Add missing 'names' attribute to generated source maps [`57e0e50`](https://github.com/SAP/ui5-builder/commit/57e0e5047638a9a704a696b8af7780fbbceefbc4)
18
+
19
+ ### Features
20
+ - Validate apiVersion property in Library.init ([#943](https://github.com/SAP/ui5-builder/issues/943)) [`52bf258`](https://github.com/SAP/ui5-builder/commit/52bf25842a59c3fa1ddbe71b482b232e18b55288)
21
+ - **Minifier:** Support input source maps ([#780](https://github.com/SAP/ui5-builder/issues/780)) [`67ecb27`](https://github.com/SAP/ui5-builder/commit/67ecb27e44a2d84e6b2203f31049220dcbcd41f0)
22
+
23
+ ### Reverts
24
+ - [INTERNAL] Azure Pipelines: Switch back to Node 20.5.x
25
+
6
26
 
7
27
  <a name="v3.0.9"></a>
8
- ## [v3.0.9] - 2023-07-25
28
+ ## [v3.0.9] - 2023-07-26
9
29
 
10
30
  <a name="v3.0.8"></a>
11
31
  ## [v3.0.8] - 2023-07-19
@@ -819,6 +839,8 @@ to load the custom bundle file instead.
819
839
 
820
840
  ### Features
821
841
  - Add ability to configure component preloads and custom bundles [`2241e5f`](https://github.com/SAP/ui5-builder/commit/2241e5ff98fd95f1f80cc74959655ae7a9c660e7)
842
+ [v3.1.1]: https://github.com/SAP/ui5-builder/compare/v3.1.0...v3.1.1
843
+ [v3.1.0]: https://github.com/SAP/ui5-builder/compare/v3.0.9...v3.1.0
822
844
  [v3.0.9]: https://github.com/SAP/ui5-builder/compare/v3.0.8...v3.0.9
823
845
  [v3.0.8]: https://github.com/SAP/ui5-builder/compare/v3.0.7...v3.0.8
824
846
  [v3.0.7]: https://github.com/SAP/ui5-builder/compare/v3.0.6...v3.0.7
@@ -61,6 +61,9 @@ async function analyze(resource) {
61
61
  libInfo.elements = getStringArray(value, true);
62
62
  } else if ( ["designtime", "dependencies", "extensions", "name", "version"].includes(key) ) {
63
63
  // do nothing, for all other supported properties
64
+ } else if ( key === "apiVersion" &&
65
+ (value.type === Syntax.Literal && typeof value.value === "number") ) {
66
+ // just a validation
64
67
  } else {
65
68
  log.error(
66
69
  "Unexpected property '" + key +
@@ -18,7 +18,7 @@ import BundleWriter from "./BundleWriter.js";
18
18
  import {getLogger} from "@ui5/logger";
19
19
  const log = getLogger("lbt:bundle:Builder");
20
20
 
21
- const sourceMappingUrlPattern = /\/\/# sourceMappingURL=(.+)\s*$/;
21
+ const sourceMappingUrlPattern = /\/\/# sourceMappingURL=(\S+)\s*$/;
22
22
  const httpPattern = /^https?:\/\//i;
23
23
  const xmlHtmlPrePattern = /<(?:\w+:)?pre\b/;
24
24
 
@@ -332,11 +332,18 @@ class BundleBuilder {
332
332
  throw new Error("No source map provided");
333
333
  }
334
334
 
335
+ // Reminder on the structure of line-segments in the map:
336
+ // [generatedCodeColumn, sourceIndex, sourceCodeLine, sourceCodeColumn, nameIndex]
335
337
  if (map.mappings.startsWith(";")) {
336
338
  // If first line is not already mapped (typical for comments or parentheses), add a mapping to
337
339
  // make sure that dev-tools (especially Chrome's) don't choose the end of the preceding module
338
340
  // when the user tries to set a breakpoint from the bundle file
339
341
  map.mappings = "AAAA" + map.mappings;
342
+ } else if (this.outW.columnOffset === 0 && !map.mappings.startsWith("A")) {
343
+ // If first column of the first line is not already mapped, add a mapping for the same reason as above.
344
+ // This is typical for transpiled code, where there is a bunch of generated code at the beginning that
345
+ // can't be mapped to the original source
346
+ map.mappings = "AAAA," + map.mappings;
340
347
  }
341
348
 
342
349
  map.sourceRoot = path.posix.relative(
@@ -592,9 +599,7 @@ class BundleBuilder {
592
599
  `Attempting to find a source map resource based on the module's path: ${sourceMapFileCandidate}`);
593
600
  try {
594
601
  const sourceMapResource = await this.pool.findResource(sourceMapFileCandidate);
595
- if (sourceMapResource) {
596
- moduleSourceMap = (await sourceMapResource.buffer()).toString();
597
- }
602
+ moduleSourceMap = (await sourceMapResource.buffer()).toString();
598
603
  } catch (e) {
599
604
  // No input source map
600
605
  log.silly(`Could not find a source map for module ${moduleName}: ${e.message}`);
@@ -772,6 +777,7 @@ async function transform(changes, moduleContent, moduleSourceMap) {
772
777
  function createTransientSourceMap({moduleName, moduleContent, includeContent = false}) {
773
778
  const sourceMap = {
774
779
  version: 3,
780
+ names: [],
775
781
  sources: [moduleName],
776
782
  // TODO: check whether moduleContent.match() with \n is better w.r.t performance/memory usage
777
783
  mappings: encodeMappings(moduleContent.split("\n").map((line, i) => {
@@ -95,6 +95,16 @@ async function determineDependencyInfo(resource, rawInfo, pool) {
95
95
  new ComponentAnalyzer(pool).analyze(resource, info),
96
96
  new SmartTemplateAnalyzer(pool).analyze(resource, info)
97
97
  );
98
+ } else if ( /(?:^|\/)library\.js/.test(resource.name) ) {
99
+ promises.push(
100
+ (async () => {
101
+ const manifestName = resource.name.replace(/library\.js$/, "manifest.json");
102
+ const manifestResource = await pool.findResource(manifestName).catch(() => null);
103
+ if (manifestResource) {
104
+ info.addDependency(manifestName);
105
+ }
106
+ })()
107
+ );
98
108
  }
99
109
 
100
110
  await Promise.all(promises);
@@ -1,10 +1,12 @@
1
1
  import {fileURLToPath} from "node:url";
2
2
  import posixPath from "node:path/posix";
3
+ import {promisify} from "node:util";
3
4
  import os from "node:os";
4
5
  import workerpool from "workerpool";
5
6
  import Resource from "@ui5/fs/Resource";
6
7
  import {getLogger} from "@ui5/logger";
7
8
  const log = getLogger("builder:processors:minifier");
9
+ import {setTimeout as setTimeoutPromise} from "node:timers/promises";
8
10
 
9
11
  const debugFileRegex = /((?:\.view|\.fragment|\.controller|\.designtime|\.support)?\.js)$/;
10
12
 
@@ -13,6 +15,9 @@ const MAX_WORKERS = 4;
13
15
  const osCpus = os.cpus().length || 1;
14
16
  const maxWorkers = Math.max(Math.min(osCpus - 1, MAX_WORKERS), MIN_WORKERS);
15
17
 
18
+ const sourceMappingUrlPattern = /\/\/# sourceMappingURL=(\S+)\s*$/;
19
+ const httpPattern = /^https?:\/\//i;
20
+
16
21
  // Shared workerpool across all executions until the taskUtil cleanup is triggered
17
22
  let pool;
18
23
 
@@ -24,11 +29,28 @@ function getPool(taskUtil) {
24
29
  workerType: "auto",
25
30
  maxWorkers
26
31
  });
27
- taskUtil.registerCleanupTask(() => {
28
- log.verbose(`Terminating workerpool`);
29
- const poolToBeTerminated = pool;
30
- pool = null;
31
- poolToBeTerminated.terminate();
32
+ taskUtil.registerCleanupTask((force) => {
33
+ const attemptPoolTermination = async () => {
34
+ log.verbose(`Attempt to terminate the workerpool...`);
35
+
36
+ if (!pool) {
37
+ return;
38
+ }
39
+
40
+ // There are many stats that could be used, but these ones seem the most
41
+ // convenient. When all the (available) workers are idle, then it's safe to terminate.
42
+ let {idleWorkers, totalWorkers} = pool.stats();
43
+ while (idleWorkers !== totalWorkers && !force) {
44
+ await setTimeoutPromise(100); // Wait a bit workers to finish and try again
45
+ ({idleWorkers, totalWorkers} = pool.stats());
46
+ }
47
+
48
+ const poolToBeTerminated = pool;
49
+ pool = null;
50
+ return poolToBeTerminated.terminate(force);
51
+ };
52
+
53
+ return attemptPoolTermination();
32
54
  });
33
55
  }
34
56
  return pool;
@@ -38,6 +60,63 @@ async function minifyInWorker(options, taskUtil) {
38
60
  return getPool(taskUtil).exec("execMinification", [options]);
39
61
  }
40
62
 
63
+ async function extractAndRemoveSourceMappingUrl(resource) {
64
+ const resourceContent = await resource.getString();
65
+ const resourcePath = resource.getPath();
66
+ const sourceMappingUrlMatch = resourceContent.match(sourceMappingUrlPattern);
67
+ if (sourceMappingUrlMatch) {
68
+ const sourceMappingUrl = sourceMappingUrlMatch[1];
69
+ if (log.isLevelEnabled("silly")) {
70
+ log.silly(`Found source map reference in content of resource ${resourcePath}: ${sourceMappingUrl}`);
71
+ }
72
+
73
+ // Strip sourceMappingURL from the resource to be minified
74
+ // It is not required anymore and will be replaced for in the minified resource
75
+ // and its debug variant anyways
76
+ resource.setString(resourceContent.replace(sourceMappingUrlPattern, ""));
77
+ return sourceMappingUrl;
78
+ }
79
+ return null;
80
+ }
81
+
82
+ async function getSourceMapFromUrl({sourceMappingUrl, resourcePath, readFile}) {
83
+ // =======================================================================
84
+ // This code is almost identical to code located in lbt/bundle/Builder.js
85
+ // Please try to update both places when making changes
86
+ // =======================================================================
87
+ if (sourceMappingUrl.startsWith("data:")) {
88
+ // Data-URI indicates an inline source map
89
+ const expectedTypeAndEncoding = "data:application/json;charset=utf-8;base64,";
90
+ if (sourceMappingUrl.startsWith(expectedTypeAndEncoding)) {
91
+ const base64Content = sourceMappingUrl.slice(expectedTypeAndEncoding.length);
92
+ // Create a resource with a path suggesting it's the source map for the resource
93
+ // (which it is but inlined)
94
+ return Buffer.from(base64Content, "base64").toString();
95
+ } else {
96
+ log.warn(
97
+ `Source map reference in resource ${resourcePath} is a data URI but has an unexpected` +
98
+ `encoding: ${sourceMappingUrl}. Expected it to start with ` +
99
+ `"data:application/json;charset=utf-8;base64,"`);
100
+ }
101
+ } else if (httpPattern.test(sourceMappingUrl)) {
102
+ log.warn(`Source map reference in resource ${resourcePath} is an absolute URL. ` +
103
+ `Currently, only relative URLs are supported.`);
104
+ } else if (posixPath.isAbsolute(sourceMappingUrl)) {
105
+ log.warn(`Source map reference in resource ${resourcePath} is an absolute path. ` +
106
+ `Currently, only relative paths are supported.`);
107
+ } else {
108
+ const sourceMapPath = posixPath.join(posixPath.dirname(resourcePath), sourceMappingUrl);
109
+
110
+ try {
111
+ const sourceMapContent = await readFile(sourceMapPath);
112
+ return sourceMapContent.toString();
113
+ } catch (e) {
114
+ // No input source map
115
+ log.warn(`Unable to read source map for resource ${resourcePath}: ${e.message}`);
116
+ }
117
+ }
118
+ }
119
+
41
120
  /**
42
121
  * @public
43
122
  * @module @ui5/builder/processors/minifier
@@ -62,9 +141,16 @@ async function minifyInWorker(options, taskUtil) {
62
141
  *
63
142
  * @param {object} parameters Parameters
64
143
  * @param {@ui5/fs/Resource[]} parameters.resources List of resources to be processed
144
+ * @param {fs|module:@ui5/fs/fsInterface} parameters.fs Node fs or custom
145
+ * [fs interface]{@link module:@ui5/fs/fsInterface}. Required when setting "readSourceMappingUrl" to true
65
146
  * @param {@ui5/builder/tasks/TaskUtil|object} [parameters.taskUtil] TaskUtil instance.
66
147
  * Required when using the <code>useWorkers</code> option
67
148
  * @param {object} [parameters.options] Options
149
+ * @param {boolean} [parameters.options.readSourceMappingUrl=false]
150
+ * Whether to make use of any existing source maps referenced in the resources to be minified. Use this option to
151
+ * preserve references to the original source files, such as TypeScript files, in the generated source map.<br>
152
+ * If a resource has been modified by a previous task, any existing source map will be ignored regardless of this
153
+ * setting. This is to ensure that no inconsistent source maps are used. Check the verbose log for details.
68
154
  * @param {boolean} [parameters.options.addSourceMappingUrl=true]
69
155
  * Whether to add a sourceMappingURL reference to the end of the minified resource
70
156
  * @param {boolean} [parameters.options.useWorkers=false]
@@ -72,8 +158,14 @@ async function minifyInWorker(options, taskUtil) {
72
158
  * @returns {Promise<module:@ui5/builder/processors/minifier~MinifierResult[]>}
73
159
  * Promise resolving with object of resource, dbgResource and sourceMap
74
160
  */
75
- export default async function({resources, taskUtil, options: {addSourceMappingUrl = true, useWorkers = false} = {}}) {
161
+ export default async function({
162
+ resources, fs, taskUtil, options: {readSourceMappingUrl = false, addSourceMappingUrl = true, useWorkers = false
163
+ } = {}}) {
76
164
  let minify;
165
+ if (readSourceMappingUrl && !fs) {
166
+ throw new Error(`Option 'readSourceMappingUrl' requires parameter 'fs' to be provided`);
167
+ }
168
+
77
169
  if (useWorkers) {
78
170
  if (!taskUtil) {
79
171
  // TaskUtil is required for worker support
@@ -86,12 +178,11 @@ export default async function({resources, taskUtil, options: {addSourceMappingUr
86
178
  }
87
179
 
88
180
  return Promise.all(resources.map(async (resource) => {
89
- const dbgPath = resource.getPath().replace(debugFileRegex, "-dbg$1");
90
- const dbgResource = await resource.clone();
91
- dbgResource.setPath(dbgPath);
181
+ const resourcePath = resource.getPath();
182
+ const dbgPath = resourcePath.replace(debugFileRegex, "-dbg$1");
183
+ const dbgFilename = posixPath.basename(dbgPath);
92
184
 
93
185
  const filename = posixPath.basename(resource.getPath());
94
- const code = await resource.getString();
95
186
 
96
187
  const sourceMapOptions = {
97
188
  filename
@@ -99,7 +190,81 @@ export default async function({resources, taskUtil, options: {addSourceMappingUr
99
190
  if (addSourceMappingUrl) {
100
191
  sourceMapOptions.url = filename + ".map";
101
192
  }
102
- const dbgFilename = posixPath.basename(dbgPath);
193
+
194
+ // Remember contentModified flag before making changes to the resource via setString
195
+ const resourceContentModified = resource.getSourceMetadata()?.contentModified;
196
+
197
+ // In any case: Extract *and remove* source map reference from resource before cloning it
198
+ const sourceMappingUrl = await extractAndRemoveSourceMappingUrl(resource);
199
+
200
+ const code = await resource.getString();
201
+ // Create debug variant based off the original resource before minification
202
+ const dbgResource = await resource.clone();
203
+ dbgResource.setPath(dbgPath);
204
+
205
+ let dbgSourceMapResource;
206
+ if (sourceMappingUrl) {
207
+ if (resourceContentModified) {
208
+ log.verbose(
209
+ `Source map found in resource will be ignored because the resource has been ` +
210
+ `modified in a previous task: ${resourcePath}`);
211
+ } else if (readSourceMappingUrl) {
212
+ // Try to find a source map reference in the to-be-minified resource
213
+ // If we find one, provide it to terser as an input source map and keep using it for the
214
+ // debug variant of the resource
215
+ const sourceMapContent = await getSourceMapFromUrl({
216
+ sourceMappingUrl,
217
+ resourcePath,
218
+ readFile: promisify(fs.readFile)
219
+ });
220
+
221
+ if (sourceMapContent) {
222
+ const sourceMapJson = JSON.parse(sourceMapContent);
223
+
224
+ if (sourceMapJson.sections) {
225
+ // TODO 4.0
226
+ // Module "@jridgewell/trace-mapping" (used by Terser) can't handle index map sections lacking
227
+ // a "names" array. Since this is a common occurrence for UI5 Tooling bundles, we search for
228
+ // such cases here and fix them until https://github.com/jridgewell/trace-mapping/pull/29 is
229
+ // resolved and Terser upgraded the dependency
230
+
231
+ // Create a dedicated clone before modifying the source map as to not alter the debug source map
232
+ const clonedSourceMapJson = JSON.parse(sourceMapContent);
233
+ clonedSourceMapJson.sections.forEach(({map}) => {
234
+ if (!map.names) {
235
+ // Add missing names array
236
+ map.names = [];
237
+ }
238
+ });
239
+ // Use modified source map as input source map
240
+ sourceMapOptions.content = JSON.stringify(clonedSourceMapJson);
241
+ } else {
242
+ // Provide source map to terser as "input source map"
243
+ sourceMapOptions.content = sourceMapContent;
244
+ }
245
+
246
+ // Use the original source map for the debug variant of the resource
247
+ // First update the file reference within the source map
248
+ sourceMapJson.file = dbgFilename;
249
+
250
+ // Then create a new resource
251
+ dbgSourceMapResource = new Resource({
252
+ string: JSON.stringify(sourceMapJson),
253
+ path: dbgPath + ".map"
254
+ });
255
+ // And reference the resource in the debug resource
256
+ dbgResource.setString(code + `//# sourceMappingURL=${dbgFilename}.map\n`);
257
+ }
258
+ } else {
259
+ // If the original resource content was unmodified and the input source map was not parsed,
260
+ // re-add the original source map reference to the debug variant
261
+ if (!sourceMappingUrl.startsWith("data:") && !sourceMappingUrl.endsWith(filename + ".map")) {
262
+ // Do not re-add inline source maps as well as references to the source map of
263
+ // the minified resource
264
+ dbgResource.setString(code + `//# sourceMappingURL=${sourceMappingUrl}\n`);
265
+ }
266
+ }
267
+ }
103
268
 
104
269
  const result = await minify({
105
270
  filename,
@@ -112,6 +277,9 @@ export default async function({resources, taskUtil, options: {addSourceMappingUr
112
277
  path: resource.getPath() + ".map",
113
278
  string: result.map
114
279
  });
115
- return {resource, dbgResource, sourceMapResource};
280
+ return {resource, dbgResource, sourceMapResource, dbgSourceMapResource};
116
281
  }));
117
282
  }
283
+
284
+ export const __localFunctions__ = (process.env.NODE_ENV === "test") ?
285
+ {getSourceMapFromUrl} : undefined;
@@ -62,7 +62,9 @@ export default async function execMinification({
62
62
  // Note: err.filename contains the debug-name
63
63
  throw new Error(
64
64
  `Minification failed with error: ${err.message} in file ${filename} ` +
65
- `(line ${err.line}, col ${err.col}, pos ${err.pos})`);
65
+ `(line ${err.line}, col ${err.col}, pos ${err.pos})`, {
66
+ cause: err
67
+ });
66
68
  }
67
69
  }
68
70
 
@@ -7,6 +7,7 @@ import {fileURLToPath} from "node:url";
7
7
  import os from "node:os";
8
8
  import workerpool from "workerpool";
9
9
  import {deserializeResources, serializeResources, FsMainThreadInterface} from "../processors/themeBuilderWorker.js";
10
+ import {setTimeout as setTimeoutPromise} from "node:timers/promises";
10
11
 
11
12
  let pool;
12
13
 
@@ -23,11 +24,28 @@ function getPool(taskUtil) {
23
24
  workerType: "thread",
24
25
  maxWorkers
25
26
  });
26
- taskUtil.registerCleanupTask(() => {
27
- log.verbose(`Terminating workerpool`);
28
- const poolToBeTerminated = pool;
29
- pool = null;
30
- poolToBeTerminated.terminate();
27
+ taskUtil.registerCleanupTask((force) => {
28
+ const attemptPoolTermination = async () => {
29
+ log.verbose(`Attempt to terminate the workerpool...`);
30
+
31
+ if (!pool) {
32
+ return;
33
+ }
34
+
35
+ // There are many stats that could be used, but these ones seem the most
36
+ // convenient. When all the (available) workers are idle, then it's safe to terminate.
37
+ let {idleWorkers, totalWorkers} = pool.stats();
38
+ while (idleWorkers !== totalWorkers && !force) {
39
+ await setTimeoutPromise(100); // Wait a bit workers to finish and try again
40
+ ({idleWorkers, totalWorkers} = pool.stats());
41
+ }
42
+
43
+ const poolToBeTerminated = pool;
44
+ pool = null;
45
+ return poolToBeTerminated.terminate(force);
46
+ };
47
+
48
+ return attemptPoolTermination();
31
49
  });
32
50
  }
33
51
  return pool;
@@ -32,7 +32,11 @@ function getDefaultLibraryPreloadFilters(namespace, excludes) {
32
32
  }
33
33
 
34
34
  function getBundleDefinition(namespace, excludes) {
35
- // TODO: move to config of actual core project
35
+ // Note: This configuration is only used when no bundle definition in ui5.yaml exists (see "skipBundles" parameter)
36
+
37
+ // TODO: Remove this hardcoded bundle definition.
38
+ // sap.ui.core ui5.yaml contains a configuration since UI5 1.103.0 (specVersion 2.4)
39
+ // so this is still required to build UI5 versions <= 1.102.0.
36
40
  if (namespace === "sap/ui/core") {
37
41
  return {
38
42
  name: `${namespace}/library-preload.js`,
@@ -51,8 +55,6 @@ function getBundleDefinition(namespace, excludes) {
51
55
  filters: [
52
56
  // Note: Don't pass configured preload excludes for sap.ui.core
53
57
  // as they are already hardcoded below.
54
- // In future the sap/ui/core/library-preload should be configured
55
- // as a custom bundle in the ui5.yaml.
56
58
  ...getDefaultLibraryPreloadFilters(namespace),
57
59
 
58
60
  `!${namespace}/cldr/`,
@@ -18,8 +18,8 @@ export default function({resources, taskUtil}) {
18
18
  const moduleNameMapping = Object.create(null);
19
19
  for (let i = resources.length - 1; i >= 0; i--) {
20
20
  const resource = resources[i];
21
- if (taskUtil.getTag(resource, taskUtil.STANDARD_TAGS.IsDebugVariant)) {
22
- const resourcePath = resource.getPath();
21
+ const resourcePath = resource.getPath();
22
+ if (resourcePath.endsWith(".js") && taskUtil.getTag(resource, taskUtil.STANDARD_TAGS.IsDebugVariant)) {
23
23
  const nonDbgPath = getNonDebugName(resourcePath);
24
24
  if (!nonDbgPath) {
25
25
  throw new Error(`Failed to resolve non-debug name for ${resourcePath}`);
@@ -1,4 +1,5 @@
1
1
  import minifier from "../processors/minifier.js";
2
+ import fsInterface from "@ui5/fs/fsInterface";
2
3
 
3
4
  /**
4
5
  * @public
@@ -19,20 +20,29 @@ import minifier from "../processors/minifier.js";
19
20
  * @param {string} parameters.options.pattern Pattern to locate the files to be processed
20
21
  * @param {boolean} [parameters.options.omitSourceMapResources=false] Whether source map resources shall
21
22
  * be tagged as "OmitFromBuildResult" and no sourceMappingURL shall be added to the minified resource
23
+ * @param {boolean} [parameters.options.useInputSourceMaps=true] Whether to make use of any existing source
24
+ * maps referenced in the resources to be minified. Use this option to preserve reference to the original
25
+ * source files, such as TypeScript files, in the generated source map.
22
26
  * @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
23
27
  */
24
- export default async function({workspace, taskUtil, options: {pattern, omitSourceMapResources = false}}) {
28
+ export default async function({
29
+ workspace, taskUtil, options: {pattern, omitSourceMapResources = false, useInputSourceMaps = true
30
+ }}) {
25
31
  const resources = await workspace.byGlob(pattern);
26
32
  const processedResources = await minifier({
27
33
  resources,
34
+ fs: fsInterface(workspace),
28
35
  taskUtil,
29
36
  options: {
30
37
  addSourceMappingUrl: !omitSourceMapResources,
38
+ readSourceMappingUrl: !!useInputSourceMaps,
31
39
  useWorkers: !!taskUtil,
32
40
  }
33
41
  });
34
42
 
35
- return Promise.all(processedResources.map(async ({resource, dbgResource, sourceMapResource}) => {
43
+ return Promise.all(processedResources.map(async ({
44
+ resource, dbgResource, sourceMapResource, dbgSourceMapResource
45
+ }) => {
36
46
  if (taskUtil) {
37
47
  taskUtil.setTag(resource, taskUtil.STANDARD_TAGS.HasDebugVariant);
38
48
  taskUtil.setTag(dbgResource, taskUtil.STANDARD_TAGS.IsDebugVariant);
@@ -40,11 +50,18 @@ export default async function({workspace, taskUtil, options: {pattern, omitSourc
40
50
  if (omitSourceMapResources) {
41
51
  taskUtil.setTag(sourceMapResource, taskUtil.STANDARD_TAGS.OmitFromBuildResult);
42
52
  }
53
+ if (dbgSourceMapResource) {
54
+ taskUtil.setTag(dbgSourceMapResource, taskUtil.STANDARD_TAGS.IsDebugVariant);
55
+ if (omitSourceMapResources) {
56
+ taskUtil.setTag(dbgSourceMapResource, taskUtil.STANDARD_TAGS.OmitFromBuildResult);
57
+ }
58
+ }
43
59
  }
44
60
  return Promise.all([
45
61
  workspace.write(resource),
46
62
  workspace.write(dbgResource),
47
- workspace.write(sourceMapResource)
63
+ workspace.write(sourceMapResource),
64
+ dbgSourceMapResource && workspace.write(dbgSourceMapResource)
48
65
  ]);
49
66
  }));
50
67
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ui5/builder",
3
- "version": "3.0.9",
3
+ "version": "3.1.1",
4
4
  "description": "UI5 Tooling - Builder",
5
5
  "author": {
6
6
  "name": "SAP SE",
@@ -119,7 +119,7 @@
119
119
  },
120
120
  "dependencies": {
121
121
  "@jridgewell/sourcemap-codec": "^1.4.15",
122
- "@ui5/fs": "^3.0.4",
122
+ "@ui5/fs": "^3.0.5",
123
123
  "@ui5/logger": "^3.0.0",
124
124
  "cheerio": "1.0.0-rc.12",
125
125
  "escape-unicode": "^0.2.0",
@@ -129,31 +129,33 @@
129
129
  "jsdoc": "^4.0.2",
130
130
  "less-openui5": "^0.11.6",
131
131
  "pretty-data": "^0.40.0",
132
- "rimraf": "^5.0.1",
132
+ "rimraf": "^5.0.5",
133
133
  "semver": "^7.5.4",
134
- "terser": "^5.19.2",
135
- "workerpool": "^6.4.0",
136
- "xml2js": "^0.6.0"
134
+ "terser": "^5.24.0",
135
+ "workerpool": "^6.5.1",
136
+ "xml2js": "^0.6.2"
137
137
  },
138
138
  "devDependencies": {
139
139
  "@istanbuljs/esm-loader-hook": "^0.2.0",
140
- "@ui5/project": "^3.4.2",
140
+ "@jridgewell/trace-mapping": "^0.3.20",
141
+ "@ui5/project": "^3.7.3",
141
142
  "ava": "^5.3.1",
142
- "chai": "^4.3.7",
143
+ "chai": "^4.3.10",
143
144
  "chai-fs": "^2.0.0",
144
145
  "chokidar-cli": "^3.0.0",
145
146
  "cross-env": "^7.0.3",
146
- "depcheck": "^1.4.3",
147
- "docdash": "^2.0.1",
148
- "eslint": "^8.45.0",
147
+ "depcheck": "^1.4.7",
148
+ "docdash": "^2.0.2",
149
+ "eslint": "^8.54.0",
149
150
  "eslint-config-google": "^0.14.0",
150
151
  "eslint-plugin-ava": "^14.0.0",
151
- "eslint-plugin-jsdoc": "^46.4.4",
152
- "esmock": "^2.3.2",
152
+ "eslint-plugin-jsdoc": "^46.9.0",
153
+ "esmock": "^2.6.0",
154
+ "line-column": "^1.0.2",
153
155
  "nyc": "^15.1.0",
154
156
  "open-cli": "^7.2.0",
155
157
  "recursive-readdir": "^2.2.3",
156
- "sinon": "^15.2.0",
158
+ "sinon": "^16.1.3",
157
159
  "tap-xunit": "^2.4.1"
158
160
  }
159
161
  }