@ui5/builder 2.11.5 → 3.0.0-alpha.10

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +125 -12
  2. package/index.js +4 -59
  3. package/jsdoc.json +0 -1
  4. package/lib/lbt/analyzer/JSModuleAnalyzer.js +31 -5
  5. package/lib/lbt/analyzer/XMLTemplateAnalyzer.js +2 -1
  6. package/lib/lbt/bundle/AutoSplitter.js +10 -24
  7. package/lib/lbt/bundle/Builder.js +367 -168
  8. package/lib/lbt/bundle/BundleWriter.js +17 -0
  9. package/lib/lbt/bundle/Resolver.js +3 -3
  10. package/lib/lbt/resources/LocatorResource.js +7 -9
  11. package/lib/lbt/resources/LocatorResourcePool.js +8 -4
  12. package/lib/lbt/resources/Resource.js +7 -0
  13. package/lib/lbt/resources/ResourceCollector.js +43 -18
  14. package/lib/lbt/resources/ResourceInfoList.js +0 -1
  15. package/lib/lbt/resources/ResourcePool.js +7 -6
  16. package/lib/lbt/utils/escapePropertiesFile.js +3 -6
  17. package/lib/lbt/utils/parseUtils.js +1 -1
  18. package/lib/processors/bundlers/moduleBundler.js +42 -17
  19. package/lib/processors/jsdoc/lib/createIndexFiles.js +1 -1
  20. package/lib/processors/jsdoc/lib/transformApiJson.js +7 -16
  21. package/lib/processors/jsdoc/lib/ui5/plugin.js +111 -6
  22. package/lib/processors/jsdoc/lib/ui5/template/publish.js +112 -91
  23. package/lib/processors/jsdoc/lib/ui5/template/utils/versionUtil.js +1 -1
  24. package/lib/processors/manifestCreator.js +8 -45
  25. package/lib/processors/minifier.js +90 -0
  26. package/lib/processors/resourceListCreator.js +2 -16
  27. package/lib/tasks/buildThemes.js +1 -1
  28. package/lib/tasks/bundlers/generateBundle.js +82 -14
  29. package/lib/tasks/bundlers/generateComponentPreload.js +31 -17
  30. package/lib/tasks/bundlers/generateFlexChangesBundle.js +7 -3
  31. package/lib/tasks/bundlers/generateLibraryPreload.js +127 -79
  32. package/lib/tasks/bundlers/generateManifestBundle.js +8 -10
  33. package/lib/tasks/bundlers/generateStandaloneAppBundle.js +54 -15
  34. package/lib/tasks/bundlers/utils/createModuleNameMapping.js +31 -0
  35. package/lib/tasks/generateCachebusterInfo.js +7 -3
  36. package/lib/tasks/generateLibraryManifest.js +6 -8
  37. package/lib/tasks/generateResourcesJson.js +15 -9
  38. package/lib/tasks/generateThemeDesignerResources.js +118 -2
  39. package/lib/tasks/generateVersionInfo.js +5 -5
  40. package/lib/tasks/jsdoc/generateJsdoc.js +1 -1
  41. package/lib/tasks/minify.js +41 -0
  42. package/lib/tasks/replaceVersion.js +1 -1
  43. package/lib/tasks/taskRepository.js +7 -15
  44. package/lib/tasks/transformBootstrapHtml.js +6 -1
  45. package/package.json +20 -19
  46. package/lib/builder/BuildContext.js +0 -39
  47. package/lib/builder/ProjectBuildContext.js +0 -55
  48. package/lib/builder/builder.js +0 -420
  49. package/lib/processors/debugFileCreator.js +0 -52
  50. package/lib/processors/resourceCopier.js +0 -24
  51. package/lib/processors/uglifier.js +0 -45
  52. package/lib/tasks/TaskUtil.js +0 -160
  53. package/lib/tasks/createDebugFiles.js +0 -30
  54. package/lib/tasks/uglify.js +0 -33
  55. package/lib/types/AbstractBuilder.js +0 -270
  56. package/lib/types/AbstractFormatter.js +0 -66
  57. package/lib/types/AbstractUi5Formatter.js +0 -95
  58. package/lib/types/application/ApplicationBuilder.js +0 -220
  59. package/lib/types/application/ApplicationFormatter.js +0 -227
  60. package/lib/types/application/applicationType.js +0 -15
  61. package/lib/types/library/LibraryBuilder.js +0 -237
  62. package/lib/types/library/LibraryFormatter.js +0 -519
  63. package/lib/types/library/libraryType.js +0 -15
  64. package/lib/types/module/ModuleBuilder.js +0 -7
  65. package/lib/types/module/ModuleFormatter.js +0 -54
  66. package/lib/types/module/moduleType.js +0 -15
  67. package/lib/types/themeLibrary/ThemeLibraryBuilder.js +0 -62
  68. package/lib/types/themeLibrary/ThemeLibraryFormatter.js +0 -90
  69. package/lib/types/themeLibrary/themeLibraryType.js +0 -15
  70. package/lib/types/typeRepository.js +0 -46
@@ -0,0 +1,90 @@
1
+ const path = require("path");
2
+ const terser = require("terser");
3
+ const Resource = require("@ui5/fs").Resource;
4
+ /**
5
+ * Preserve comments which contain:
6
+ * <ul>
7
+ * <li>copyright notice</li>
8
+ * <li>license terms</li>
9
+ * <li>"@ui5-bundle"</li>
10
+ * <li>"@ui5-bundle-raw-include"</li>
11
+ * </ul>
12
+ *
13
+ * @type {RegExp}
14
+ */
15
+ const copyrightCommentsAndBundleCommentPattern = /copyright|\(c\)(?:[0-9]+|\s+[0-9A-za-z])|released under|license|\u00a9|^@ui5-bundle-raw-include |^@ui5-bundle /i;
16
+ const debugFileRegex = /((?:\.view|\.fragment|\.controller|\.designtime|\.support)?\.js)$/;
17
+
18
+
19
+ /**
20
+ * Result set
21
+ *
22
+ * @public
23
+ * @typedef {object} MinifierResult
24
+ * @property {module:@ui5/fs.Resource} resource Minified resource
25
+ * @property {module:@ui5/fs.Resource} dbgResource Debug (non-minified) variant
26
+ * @property {module:@ui5/fs.Resource} sourceMap Source Map
27
+ * @memberof module:@ui5/builder.processors
28
+ */
29
+
30
+ /**
31
+ * Minifies the supplied resources.
32
+ *
33
+ * @public
34
+ * @alias module:@ui5/builder.processors.minifier
35
+ * @param {object} parameters Parameters
36
+ * @param {module:@ui5/fs.Resource[]} parameters.resources List of resources to be processed
37
+ * @param {object} [parameters.options] Options
38
+ * @param {boolean} [parameters.options.addSourceMappingUrl=true]
39
+ * Whether to add a sourceMappingURL reference to the end of the minified resource
40
+ * @returns {Promise<module:@ui5/builder.processors.MinifierResult[]>}
41
+ * Promise resolving with object of resource, dbgResource and sourceMap
42
+ */
43
+ module.exports = async function({resources, options: {addSourceMappingUrl = true} = {}}) {
44
+ return Promise.all(resources.map(async (resource) => {
45
+ const dbgPath = resource.getPath().replace(debugFileRegex, "-dbg$1");
46
+ const dbgResource = await resource.clone();
47
+ dbgResource.setPath(dbgPath);
48
+
49
+ const filename = path.posix.basename(resource.getPath());
50
+ const code = await resource.getString();
51
+ try {
52
+ const sourceMapOptions = {
53
+ filename
54
+ };
55
+ if (addSourceMappingUrl) {
56
+ sourceMapOptions.url = filename + ".map";
57
+ }
58
+ const dbgFilename = path.posix.basename(dbgPath);
59
+ const result = await terser.minify({
60
+ // Use debug-name since this will be referenced in the source map "sources"
61
+ [dbgFilename]: code
62
+ }, {
63
+ output: {
64
+ comments: copyrightCommentsAndBundleCommentPattern,
65
+ wrap_func_args: false
66
+ },
67
+ compress: false,
68
+ mangle: {
69
+ reserved: [
70
+ "jQuery",
71
+ "jquery",
72
+ "sap",
73
+ ]
74
+ },
75
+ sourceMap: sourceMapOptions
76
+ });
77
+ resource.setString(result.code);
78
+ const sourceMapResource = new Resource({
79
+ path: resource.getPath() + ".map",
80
+ string: result.map
81
+ });
82
+ return {resource, dbgResource, sourceMapResource};
83
+ } catch (err) {
84
+ // Note: err.filename contains the debug-name
85
+ throw new Error(
86
+ `Minification failed with error: ${err.message} in file ${filename} ` +
87
+ `(line ${err.line}, col ${err.col}, pos ${err.pos})`);
88
+ }
89
+ }));
90
+ };
@@ -66,17 +66,6 @@ const DEFAULT_SUPPORT_RESOURCES_FILTER = [
66
66
  "**/*.support.js"
67
67
  ];
68
68
 
69
- /**
70
- * Hard coded debug bundle, to trigger separate analysis for this filename
71
- * because sap-ui-core.js and sap-ui-core-dbg.js have different includes
72
- *
73
- * @type {string[]}
74
- */
75
- const DEBUG_BUNDLES = [
76
- "sap-ui-core-dbg.js",
77
- "sap-ui-core-nojQuery-dbg.js"
78
- ];
79
-
80
69
  /**
81
70
  * Creates and adds resources.json entry (itself) to the list.
82
71
  *
@@ -138,8 +127,7 @@ module.exports = async function({resources, dependencyResources = [], options})
138
127
  debugResources: DEFAULT_DEBUG_RESOURCES_FILTER,
139
128
  mergedResources: DEFAULT_BUNDLE_RESOURCES_FILTER,
140
129
  designtimeResources: DEFAULT_DESIGNTIME_RESOURCES_FILTER,
141
- supportResources: DEFAULT_SUPPORT_RESOURCES_FILTER,
142
- debugBundles: DEBUG_BUNDLES
130
+ supportResources: DEFAULT_SUPPORT_RESOURCES_FILTER
143
131
  }, options);
144
132
 
145
133
  const pool = new LocatorResourcePool();
@@ -158,12 +146,10 @@ module.exports = async function({resources, dependencyResources = [], options})
158
146
  }
159
147
 
160
148
  await collector.determineResourceDetails({
161
- pool,
162
149
  debugResources: options.debugResources,
163
150
  mergedResources: options.mergedResources,
164
151
  designtimeResources: options.designtimeResources,
165
- supportResources: options.supportResources,
166
- debugBundles: options.debugBundles
152
+ supportResources: options.supportResources
167
153
  });
168
154
 
169
155
  // group resources by components and create ResourceInfoLists
@@ -97,7 +97,7 @@ module.exports = async function({
97
97
 
98
98
  if (log.isLevelEnabled("verbose")) {
99
99
  if (!libraryAvailable) {
100
- log.verbose(`Skipping ${resourcePath}: Library is not available`);
100
+ log.silly(`Skipping ${resourcePath}: Library is not available`);
101
101
  }
102
102
  if (!themeAvailable) {
103
103
  log.verbose(`Skipping ${resourcePath}: sap.ui.core theme '${themeName}' is not available. ` +
@@ -1,4 +1,5 @@
1
1
  const moduleBundler = require("../../processors/bundlers/moduleBundler");
2
+ const createModuleNameMapping = require("./utils/createModuleNameMapping");
2
3
  const ReaderCollectionPrioritized = require("@ui5/fs").ReaderCollectionPrioritized;
3
4
 
4
5
  /**
@@ -9,34 +10,101 @@ const ReaderCollectionPrioritized = require("@ui5/fs").ReaderCollectionPrioritiz
9
10
  * @param {object} parameters Parameters
10
11
  * @param {module:@ui5/fs.DuplexCollection} parameters.workspace DuplexCollection to read and write files
11
12
  * @param {module:@ui5/fs.ReaderCollection} parameters.dependencies Collection to read dependency files
12
- * @param {module:@ui5/builder.tasks.TaskUtil|object} [parameters.taskUtil] TaskUtil
13
+ * @param {module:@ui5/project.build.helpers.TaskUtil|object} [parameters.taskUtil] TaskUtil
13
14
  * @param {object} parameters.options Options
14
15
  * @param {string} parameters.options.projectName Project name
15
16
  * @param {ModuleBundleDefinition} parameters.options.bundleDefinition Module bundle definition
16
- * @param {ModuleBundleOptions} parameters.options.bundleOptions Module bundle options
17
+ * @param {ModuleBundleOptions} [parameters.options.bundleOptions] Module bundle options
17
18
  * @returns {Promise} Promise resolving with <code>undefined</code> once data has been written
18
19
  */
19
20
  module.exports = function({
20
21
  workspace, dependencies, taskUtil, options: {projectName, bundleDefinition, bundleOptions}
21
22
  }) {
22
- const combo = new ReaderCollectionPrioritized({
23
- name: `libraryBundler - prioritize workspace over dependencies: ${projectName}`,
23
+ let combo = new ReaderCollectionPrioritized({
24
+ name: `generateBundle - prioritize workspace over dependencies: ${projectName}`,
24
25
  readers: [workspace, dependencies]
25
26
  });
26
27
 
27
- return combo.byGlob("/resources/**/*.{js,json,xml,html,properties,library}").then((resources) => {
28
- return moduleBundler({
29
- options: {
30
- bundleDefinition,
31
- bundleOptions
32
- },
33
- resources
34
- }).then((bundles) => {
35
- return Promise.all(bundles.map((bundle) => {
28
+ const optimize = !bundleOptions || bundleOptions.optimize !== false;
29
+ if (taskUtil) {
30
+ /* Scenarios
31
+ 1. Optimize bundle with minification already done
32
+ Workspace:
33
+ * /resources/my/lib/Control.js [ui5:HasDebugVariant]
34
+ * /resources/my/lib/Control.js.map [ui5:HasDebugVariant]
35
+ * /resources/my/lib/Control-dbg.js [ui5:IsDebugVariant]
36
+
37
+ Bundler input:
38
+ * /resources/my/lib/Control.js
39
+ * /resources/my/lib/Control.js.map
40
+
41
+ => Filter out debug resources
42
+
43
+ 2. Optimize bundle with no minification
44
+ * /resources/my/lib/Control.js
45
+
46
+ => No action necessary
47
+
48
+ 3. Debug-bundle with minification already done
49
+ Workspace:
50
+ * /resources/my/lib/Control.js [ui5:HasDebugVariant]
51
+ * /resources/my/lib/Control.js.map [ui5:HasDebugVariant]
52
+ * /resources/my/lib/Control-dbg.js [ui5:IsDebugVariant]
53
+
54
+ Bundler input:
55
+ * /resources/my/lib/Control-dbg.js
56
+ * moduleNameMapping: [{"/resources/my/lib/Control-dbg.js": "my/lib/Control.js"}]
57
+
58
+ => Filter out minified-resources (tagged as "HasDebugVariant", incl. source maps) and rename debug-files
59
+
60
+ 4. Debug-bundle with no minification
61
+ * /resources/my/lib/Control.js
62
+
63
+ => No action necessary
64
+
65
+ 5. Bundle with external input (optimize or not), e.g. TS-project
66
+ Workspace:
67
+ * /resources/my/lib/Control.ts
68
+ * /resources/my/lib/Control.js
69
+ * /resources/my/lib/Control.js.map
70
+
71
+ Bundler input:
72
+ * /resources/my/lib/Control.js
73
+ * /resources/my/lib/Control.js.map
74
+ */
75
+
76
+ // Omit -dbg files for optimize bundles and vice versa
77
+ const filterTag = optimize ?
78
+ taskUtil.STANDARD_TAGS.IsDebugVariant : taskUtil.STANDARD_TAGS.HasDebugVariant;
79
+ combo = combo.filter(function(resource) {
80
+ return !taskUtil.getTag(resource, filterTag);
81
+ });
82
+ }
83
+
84
+ return combo.byGlob("/resources/**/*.{js,json,xml,html,properties,library,js.map}").then((resources) => {
85
+ const options = {bundleDefinition, bundleOptions};
86
+ if (!optimize && taskUtil) {
87
+ options.moduleNameMapping = createModuleNameMapping({resources, taskUtil});
88
+ }
89
+ return moduleBundler({options, resources}).then((bundles) => {
90
+ return Promise.all(bundles.map(({bundle, sourceMap} = {}) => {
91
+ if (!bundle) {
92
+ // Skip empty bundles
93
+ return;
94
+ }
36
95
  if (taskUtil) {
37
96
  taskUtil.setTag(bundle, taskUtil.STANDARD_TAGS.IsBundle);
97
+ if (sourceMap) {
98
+ // Clear tag that might have been set by the minify task, in cases where
99
+ // the bundle name is identical to a source file
100
+ taskUtil.clearTag(sourceMap, taskUtil.STANDARD_TAGS.OmitFromBuildResult);
101
+ }
102
+ }
103
+ const writes = [workspace.write(bundle)];
104
+ if (sourceMap) {
105
+ writes.push(workspace.write(sourceMap));
38
106
  }
39
- return workspace.write(bundle);
107
+ return Promise.all(writes);
40
108
  }));
41
109
  });
42
110
  });
@@ -1,7 +1,6 @@
1
1
  const path = require("path");
2
2
  const moduleBundler = require("../../processors/bundlers/moduleBundler");
3
3
  const log = require("@ui5/logger").getLogger("builder:tasks:bundlers:generateComponentPreload");
4
- const ReaderCollectionPrioritized = require("@ui5/fs").ReaderCollectionPrioritized;
5
4
  const {negateFilters} = require("../../lbt/resources/ResourceFilterList");
6
5
 
7
6
  /**
@@ -11,8 +10,7 @@ const {negateFilters} = require("../../lbt/resources/ResourceFilterList");
11
10
  * @alias module:@ui5/builder.tasks.generateComponentPreload
12
11
  * @param {object} parameters Parameters
13
12
  * @param {module:@ui5/fs.DuplexCollection} parameters.workspace DuplexCollection to read and write files
14
- * @param {module:@ui5/fs.AbstractReader} parameters.dependencies Reader or Collection to read dependency files
15
- * @param {module:@ui5/builder.tasks.TaskUtil|object} [parameters.taskUtil] TaskUtil
13
+ * @param {module:@ui5/project.build.helpers.TaskUtil|object} [parameters.taskUtil] TaskUtil
16
14
  * @param {object} parameters.options Options
17
15
  * @param {string} parameters.options.projectName Project name
18
16
  * @param {string[]} [parameters.options.excludes=[]] List of modules declared as glob patterns (resource name patterns)
@@ -23,25 +21,28 @@ const {negateFilters} = require("../../lbt/resources/ResourceFilterList");
23
21
  * inclusion overrides an earlier exclusion, and vice versa.
24
22
  * @param {string[]} [parameters.options.paths] Array of paths (or glob patterns) for component files
25
23
  * @param {string[]} [parameters.options.namespaces] Array of component namespaces
24
+ * @param {string[]} [parameters.options.skipBundles] Names of bundles that should not be created
26
25
  * @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
27
26
  */
28
27
  module.exports = function({
29
- workspace, dependencies, taskUtil, options: {projectName, paths, namespaces, excludes = []}
28
+ workspace, taskUtil, options: {projectName, paths, namespaces, skipBundles = [], excludes = []}
30
29
  }) {
31
- const combo = new ReaderCollectionPrioritized({
32
- name: `generateComponentPreload - prioritize workspace over dependencies: ${projectName}`,
33
- readers: [workspace, dependencies]
34
- });
30
+ let nonDbgWorkspace = workspace;
31
+ if (taskUtil) {
32
+ nonDbgWorkspace = workspace.filter(function(resource) {
33
+ // Remove any debug variants
34
+ return !taskUtil.getTag(resource, taskUtil.STANDARD_TAGS.IsDebugVariant);
35
+ });
36
+ }
35
37
 
36
- // TODO 3.0: Limit to workspace resources?
37
- return combo.byGlob("/resources/**/*.{js,json,xml,html,properties,library}")
38
+ return nonDbgWorkspace.byGlob("/resources/**/*.{js,json,xml,html,properties,library,js.map}")
38
39
  .then(async (resources) => {
39
40
  let allNamespaces = [];
40
41
  if (paths) {
41
42
  allNamespaces = await Promise.all(paths.map(async (componentPath) => {
42
43
  const globPath = "/resources/" + componentPath;
43
44
  log.verbose(`Globbing for Components directories with configured path ${globPath}...`);
44
- const components = await combo.byGlob(globPath); // TODO 3.0: Limit to workspace resources?
45
+ const components = await nonDbgWorkspace.byGlob(globPath);
45
46
  return components.map((component) => {
46
47
  const compDir = path.dirname(component.getPath()).replace(/^\/resources\//i, "");
47
48
  log.verbose(`Found component namespace ${compDir}`);
@@ -65,6 +66,12 @@ module.exports = function({
65
66
  const unusedFilterExcludes = new Set(allFilterExcludes);
66
67
 
67
68
  const bundleDefinitions = allNamespaces.map((namespace) => {
69
+ const bundleName = `${namespace}/Component-preload.js`;
70
+ if (skipBundles.includes(bundleName)) {
71
+ log.verbose(`Skipping generation of bundle ${bundleName}`);
72
+ return null;
73
+ }
74
+
68
75
  const filters = [
69
76
  `${namespace}/`,
70
77
  `${namespace}/**/manifest.json`,
@@ -94,7 +101,7 @@ module.exports = function({
94
101
  });
95
102
 
96
103
  return {
97
- name: `${namespace}/Component-preload.js`,
104
+ name: bundleName,
98
105
  defaultFileTypes: [
99
106
  ".js",
100
107
  ".control.xml",
@@ -127,7 +134,7 @@ module.exports = function({
127
134
  });
128
135
  }
129
136
 
130
- return Promise.all(bundleDefinitions.map((bundleDefinition) => {
137
+ return Promise.all(bundleDefinitions.filter(Boolean).map((bundleDefinition) => {
131
138
  log.verbose(`Generating ${bundleDefinition.name}...`);
132
139
  return moduleBundler({
133
140
  resources,
@@ -141,12 +148,19 @@ module.exports = function({
141
148
  });
142
149
  }));
143
150
  })
144
- .then((processedResources) => {
145
- return Promise.all(processedResources.map((resource) => {
151
+ .then((results) => {
152
+ const bundles = Array.prototype.concat.apply([], results);
153
+ return Promise.all(bundles.map(({bundle, sourceMap}) => {
146
154
  if (taskUtil) {
147
- taskUtil.setTag(resource[0], taskUtil.STANDARD_TAGS.IsBundle);
155
+ taskUtil.setTag(bundle, taskUtil.STANDARD_TAGS.IsBundle);
156
+ // Clear tag that might have been set by the minify task, in cases where
157
+ // the bundle name is identical to a source file
158
+ taskUtil.clearTag(sourceMap, taskUtil.STANDARD_TAGS.OmitFromBuildResult);
148
159
  }
149
- return workspace.write(resource[0]);
160
+ return Promise.all([
161
+ workspace.write(bundle),
162
+ workspace.write(sourceMap)
163
+ ]);
150
164
  }));
151
165
  });
152
166
  };
@@ -2,6 +2,7 @@ const log = require("@ui5/logger").getLogger("builder:tasks:bundlers:generateFle
2
2
  const flexChangesBundler = require("../../processors/bundlers/flexChangesBundler");
3
3
  const semver = require("semver");
4
4
 
5
+ /* eslint "jsdoc/check-param-names": ["error", {"disableExtraPropertyReporting":true}] */
5
6
  /**
6
7
  * Task to create changesBundle.json file containing all changes stored in the /changes folder for easier consumption
7
8
  * at runtime.
@@ -14,12 +15,15 @@ const semver = require("semver");
14
15
  * @alias module:@ui5/builder.tasks.generateFlexChangesBundle
15
16
  * @param {object} parameters Parameters
16
17
  * @param {module:@ui5/fs.DuplexCollection} parameters.workspace DuplexCollection to read and write files
17
- * @param {module:@ui5/builder.tasks.TaskUtil|object} [parameters.taskUtil] TaskUtil
18
+ * @param {module:@ui5/project.build.helpers.TaskUtil|object} [parameters.taskUtil] TaskUtil
18
19
  * @param {object} [parameters.options] Options
19
- * @param {string} [parameters.options.namespace] Application Namespace
20
+ * @param {string} [parameters.options.projectNamespace] Project Namespace
20
21
  * @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
21
22
  */
22
- module.exports = async function({workspace, taskUtil, options: {namespace}}) {
23
+ module.exports = async function({workspace, taskUtil, options = {}}) {
24
+ // Backward compatibility: "namespace" option got renamed to "projectNamespace"
25
+ const namespace = options.projectNamespace || options.namespace;
26
+
23
27
  // Use the given namespace if available, otherwise use no namespace
24
28
  // (e.g. in case no manifest.json is present)
25
29
  let pathPrefix = "";