diff --git a/index.js b/index.js index ef078852f..db8ee8ae9 100644 --- a/index.js +++ b/index.js @@ -13,7 +13,9 @@ module.exports = { flexChangesBundler: require("./lib/processors/bundlers/flexChangesBundler"), manifestBundler: require("./lib/processors/bundlers/manifestBundler"), moduleBundler: require("./lib/processors/bundlers/moduleBundler"), + apiIndexGenerator: require("./lib/processors/jsdoc/apiIndexGenerator"), jsdocGenerator: require("./lib/processors/jsdoc/jsdocGenerator"), + sdkTransformer: require("./lib/processors/jsdoc/sdkTransformer"), bootstrapHtmlTransformer: require("./lib/processors/bootstrapHtmlTransformer"), debugFileCreator: require("./lib/processors/debugFileCreator"), resourceCopier: require("./lib/processors/resourceCopier"), @@ -36,8 +38,9 @@ module.exports = { generateBundle: require("./lib/tasks/bundlers/generateBundle"), buildThemes: require("./lib/tasks/buildThemes"), createDebugFiles: require("./lib/tasks/createDebugFiles"), - generateJsdoc: require("./lib/tasks/jsdoc/generateJsdoc"), executeJsdocSdkTransformation: require("./lib/tasks/jsdoc/executeJsdocSdkTransformation"), + generateApiIndex: require("./lib/tasks/jsdoc/generateApiIndex"), + generateJsdoc: require("./lib/tasks/jsdoc/generateJsdoc"), generateVersionInfo: require("./lib/tasks/generateVersionInfo"), replaceCopyright: require("./lib/tasks/replaceCopyright"), replaceVersion: require("./lib/tasks/replaceVersion"), diff --git a/lib/builder/builder.js b/lib/builder/builder.js index 16ca364f7..7235c3382 100644 --- a/lib/builder/builder.js +++ b/lib/builder/builder.js @@ -54,6 +54,7 @@ function composeTaskList({dev, selfContained, jsdoc, includedTasks, excludedTask selectedTasks.transformBootstrapHtml = false; selectedTasks.generateJsdoc = false; selectedTasks.executeJsdocSdkTransformation = false; + selectedTasks.generateApiIndex = false; if (selfContained) { // No preloads, bundle only @@ -67,6 +68,7 @@ function composeTaskList({dev, selfContained, jsdoc, includedTasks, excludedTask // Include JSDoc tasks selectedTasks.generateJsdoc = true; selectedTasks.executeJsdocSdkTransformation = true; + selectedTasks.generateApiIndex = true; // Exclude all tasks not relevant to JSDoc generation selectedTasks.generateComponentPreload = false; @@ -75,6 +77,8 @@ function composeTaskList({dev, selfContained, jsdoc, includedTasks, excludedTask selectedTasks.buildThemes = false; selectedTasks.createDebugFiles = false; selectedTasks.uglify = false; + selectedTasks.generateFlexChangesBundle = false; + selectedTasks.generateManifestBundle = false; } // Only run essential tasks in development mode, it is not desired to run time consuming tasks during development. diff --git a/lib/processors/jsdoc/apiIndexGenerator.js b/lib/processors/jsdoc/apiIndexGenerator.js new file mode 100644 index 000000000..aa3ba3d25 --- /dev/null +++ b/lib/processors/jsdoc/apiIndexGenerator.js @@ -0,0 +1,50 @@ +const resourceFactory = require("@ui5/fs").resourceFactory; +const createIndex = require("./lib/create-api-index"); + +/** + * Compiles API index resources from all api.json resources available in the given test resources directory + * as created by the [sdkTransformer]{@link module:@ui5/builder.processors.sdkTransformer} processor. + * The resulting index resources (e.g. api-index.json, api-index-deprecated.json, + * api-index-experimental.json and api-index-since.json) are mainly to be used in the SDK. + * + * @public + * @alias module:@ui5/builder.processors.apiIndexGenerator + * @param {Object} parameters Parameters + * @param {string} parameters.versionInfoFile Path to sap-ui-version.json resource + * @param {string} parameters.unpackedTestresourcesRoot Path to /test-resources root directory in the + * given fs + * @param {string} parameters.targetFile Path to create the generated API index JSON resource for + * @param {string} parameters.targetFileDeprecated Path to create the generated API index "deprecated" JSON resource for + * @param {string} parameters.targetFileExperimental Path to create the generated API index "experimental" JSON + * resource for + * @param {string} parameters.targetFileSince Path to create the generated API index "since" JSON resource for + * @param {fs|module:@ui5/fs.fsInterface} parameters.fs Node fs or + * custom [fs interface]{@link module:resources/module:@ui5/fs.fsInterface} to use + * @returns {Promise} Promise resolving with created resources api-index.json, + * api-index-deprecated.json, api-index-experimental.json and + * api-index-since.json (names depend on the supplied paths) + */ +const apiIndexGenerator = async function({ + versionInfoFile, unpackedTestresourcesRoot, targetFile, targetFileDeprecated, targetFileExperimental, + targetFileSince, fs +}) { + if (!versionInfoFile || !unpackedTestresourcesRoot || !targetFile || !targetFileDeprecated || + !targetFileExperimental || !targetFileSince || !fs) { + throw new Error("[apiIndexGenerator]: One or more mandatory parameters not provided"); + } + + const resourceMap = await createIndex(versionInfoFile, unpackedTestresourcesRoot, targetFile, + targetFileDeprecated, targetFileExperimental, targetFileSince, { + fs, + returnOutputFiles: true + }); + + return Object.keys(resourceMap).map((resPath) => { + return resourceFactory.createResource({ + path: resPath, + string: resourceMap[resPath] + }); + }); +}; + +module.exports = apiIndexGenerator; diff --git a/lib/processors/jsdoc/lib/create-api-index.js b/lib/processors/jsdoc/lib/create-api-index.js index e722ad8a9..a2186a8e5 100644 --- a/lib/processors/jsdoc/lib/create-api-index.js +++ b/lib/processors/jsdoc/lib/create-api-index.js @@ -7,25 +7,41 @@ "use strict"; const path = require("path"); +const log = (function() { + try { + return require("@ui5/logger").getLogger("builder:processors:jsdoc:create-api-index"); + } catch (error) { + /* eslint-disable no-console */ + return { + info: function info(...msg) { + console.log("[INFO]", ...msg); + }, + error: function error(...msg) { + console.error(...msg); + } + }; + /* eslint-enable no-console */ + } +}()); function process(versionInfoFile, unpackedTestresourcesRoot, targetFile, targetFileDeprecated, targetFileExperimental, targetFileSince, options) { const fs = options && options.fs || require("fs"); const returnOutputFiles = options && !!options.returnOutputFiles; - console.log("[INFO] creating API index files"); - console.log("[INFO] sap-ui-version.json: " + versionInfoFile); - console.log("[INFO] unpacked test-resources: " + unpackedTestresourcesRoot); - console.log("[INFO] target file: " + targetFile); - console.log("[INFO] target file deprecated: " + targetFileDeprecated); - console.log("[INFO] target file experimental: " + targetFileExperimental); - console.log("[INFO] target file since: " + targetFileSince); + log.info("creating API index files"); + log.info(" sap-ui-version.json: " + versionInfoFile); + log.info(" unpacked test-resources: " + unpackedTestresourcesRoot); + log.info(" target file: " + targetFile); + log.info(" target file deprecated: " + targetFileDeprecated); + log.info(" target file experimental: " + targetFileExperimental); + log.info(" target file since: " + targetFileSince); if (options && options.fs) { - console.log("[INFO] Using custom fs"); + log.info("Using custom fs"); } if (returnOutputFiles) { - console.log("[INFO] Returning output files instead of writing to fs.") + log.info("Returning output files instead of writing to fs.") } - console.log("[INFO]"); + log.info(""); // Deprecated, Experimental and Since collections let oListCollection = { @@ -422,7 +438,7 @@ function process(versionInfoFile, unpackedTestresourcesRoot, targetFile, targetF } }) .catch(err => { - console.error("**** failed to create API index for libraries:", err) + log.error("**** failed to create API index for libraries:", err) throw err; }); diff --git a/lib/processors/jsdoc/sdkTransformer.js b/lib/processors/jsdoc/sdkTransformer.js index c8defa19b..0dbb98dd2 100644 --- a/lib/processors/jsdoc/sdkTransformer.js +++ b/lib/processors/jsdoc/sdkTransformer.js @@ -27,8 +27,8 @@ const sdkTransformer = async function({ } const fakeTargetPath = "/ignore/this/path/resource/will/be/returned"; const apiJsonContent = await transformer(apiJsonPath, fakeTargetPath, dotLibraryPath, dependencyApiJsonPaths, { - customFs: fs, - returnOutputFile: true + fs, + returnOutputFiles: true }); return [resourceFactory.createResource({ path: targetApiJsonPath, diff --git a/lib/tasks/jsdoc/generateApiIndex.js b/lib/tasks/jsdoc/generateApiIndex.js new file mode 100644 index 000000000..b0d1774f4 --- /dev/null +++ b/lib/tasks/jsdoc/generateApiIndex.js @@ -0,0 +1,49 @@ +const ui5Fs = require("@ui5/fs"); +const ReaderCollectionPrioritized = ui5Fs.ReaderCollectionPrioritized; +const fsInterface = ui5Fs.fsInterface; +const apiIndexGenerator = require("../../processors/jsdoc/apiIndexGenerator"); + +/** + * Compiles an api-index.json resource from all available api.json resources as created by the + * [executeJsdocSdkTransformation]{@link module:@ui5/builder.tasks.executeJsdocSdkTransformation} task. + * The resulting api-index.json resource is mainly to be used in the SDK. + * + * @public + * @alias module:@ui5/builder.tasks.generateApiIndex + * @param {Object} parameters Parameters + * @param {module:@ui5/fs.DuplexCollection} parameters.workspace DuplexCollection to read and write files + * @param {module:@ui5/fs.AbstractReader} parameters.dependencies Reader or Collection to read dependency files + * @param {Object} parameters.options Options + * @param {string} parameters.options.projectName Project name + * @returns {Promise} Promise resolving with undefined once data has been written + */ +module.exports = async function({workspace, dependencies, options}) { + if (!options || !options.projectName) { + throw new Error("[generateApiIndex]: One or more mandatory options not provided"); + } + const combo = new ReaderCollectionPrioritized({ + name: `generateApiIndex - workspace + dependencies: ${options.projectName}`, + readers: [workspace, dependencies] + }); + + const versionInfoFile = "/resources/sap-ui-version.json"; + const unpackedTestresourcesRoot = "/test-resources"; + const targetFile = "/docs/api/api-index.json"; + const targetFileDeprecated = "/docs/api/api-index-deprecated.json"; + const targetFileExperimental = "/docs/api/api-index-experimental.json"; + const targetFileSince = "/docs/api/api-index-since.json"; + + const createdResources = await apiIndexGenerator({ + versionInfoFile, + unpackedTestresourcesRoot, + targetFile, + targetFileDeprecated, + targetFileExperimental, + targetFileSince, + fs: fsInterface(combo), + }); + + await Promise.all(createdResources.map((resource) => { + return workspace.write(resource); + })); +}; diff --git a/lib/tasks/taskRepository.js b/lib/tasks/taskRepository.js index 570e80408..d510e2459 100644 --- a/lib/tasks/taskRepository.js +++ b/lib/tasks/taskRepository.js @@ -2,8 +2,9 @@ const tasks = { replaceCopyright: require("./replaceCopyright"), replaceVersion: require("./replaceVersion"), createDebugFiles: require("./createDebugFiles"), - generateJsdoc: require("./jsdoc/generateJsdoc"), executeJsdocSdkTransformation: require("./jsdoc/executeJsdocSdkTransformation"), + generateApiIndex: require("./jsdoc/generateApiIndex"), + generateJsdoc: require("./jsdoc/generateJsdoc"), uglify: require("./uglify"), buildThemes: require("./buildThemes"), transformBootstrapHtml: require("./transformBootstrapHtml"), diff --git a/lib/types/application/ApplicationBuilder.js b/lib/types/application/ApplicationBuilder.js index b4dbdd764..c5bd612d1 100644 --- a/lib/types/application/ApplicationBuilder.js +++ b/lib/types/application/ApplicationBuilder.js @@ -13,7 +13,8 @@ const tasks = { // can't require index.js due to circular dependency replaceCopyright: require("../../tasks/replaceCopyright"), replaceVersion: require("../../tasks/replaceVersion"), transformBootstrapHtml: require("../../tasks/transformBootstrapHtml"), - uglify: require("../../tasks/uglify") + uglify: require("../../tasks/uglify"), + generateApiIndex: require("../../tasks/jsdoc/generateApiIndex") }; class ApplicationBuilder extends AbstractBuilder { @@ -159,6 +160,16 @@ class ApplicationBuilder extends AbstractBuilder { } }); }); + + this.addTask("generateApiIndex", () => { + return tasks.generateApiIndex({ + workspace: resourceCollections.workspace, + dependencies: resourceCollections.dependencies, + options: { + projectName: project.metadata.name + } + }); + }); } } diff --git a/test/lib/processors/jsdoc/sdkTransformer.js b/test/lib/processors/jsdoc/sdkTransformer.js index 09bfd94dd..215392988 100644 --- a/test/lib/processors/jsdoc/sdkTransformer.js +++ b/test/lib/processors/jsdoc/sdkTransformer.js @@ -41,8 +41,8 @@ test.serial("sdkTransformer", async (t) => { "/some/path/y/api.json" ], "transform-apijson-for-sdk called with correct argument #4"); t.deepEqual(transformerStub.getCall(0).args[4], { - customFs: "custom fs", - returnOutputFile: true + fs: "custom fs", + returnOutputFiles: true }, "transform-apijson-for-sdk called with correct argument #5"); t.deepEqual(createResourceStub.callCount, 1, "createResource called once"); diff --git a/test/lib/types/application/ApplicationBuilder.js b/test/lib/types/application/ApplicationBuilder.js index 359550558..a25eccfde 100644 --- a/test/lib/types/application/ApplicationBuilder.js +++ b/test/lib/types/application/ApplicationBuilder.js @@ -67,7 +67,8 @@ test("Instantiation", (t) => { "generateBundle", "createDebugFiles", "uglify", - "generateVersionInfo" + "generateVersionInfo", + "generateApiIndex" ], "ApplicationBuilder is instantiated with standard tasks"); }); @@ -87,7 +88,8 @@ test("Instantiation without component preload project configuration", (t) => { "generateBundle", "createDebugFiles", "uglify", - "generateVersionInfo" + "generateVersionInfo", + "generateApiIndex" ], "ApplicationBuilder is still instantiated with standard tasks"); }); @@ -107,7 +109,8 @@ test("Instantiation without project namespace", (t) => { "generateBundle", "createDebugFiles", "uglify", - "generateVersionInfo" + "generateVersionInfo", + "generateApiIndex" ], "All standard tasks but generateComponentPreload will be executed"); }); @@ -132,6 +135,7 @@ test("Instantiation with custom tasks", (t) => { "createDebugFiles", "uglify", "replaceVersion--1", - "generateVersionInfo" + "generateVersionInfo", + "generateApiIndex" ], "ApplicationBuilder is still instantiated with standard tasks"); });