Skip to content

Commit

Permalink
Collect dependency APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
RandomByte committed Mar 7, 2019
1 parent 5c683c0 commit b93d4bd
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 23 deletions.
16 changes: 15 additions & 1 deletion lib/builder/builder.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const log = require("@ui5/logger").getGroupLogger("builder:builder");
const resourceFactory = require("@ui5/fs").resourceFactory;
const MemAdapter = require("@ui5/fs").adapters.Memory;
const typeRepository = require("../types/typeRepository");
const taskRepository = require("../tasks/taskRepository");

Expand Down Expand Up @@ -148,6 +149,7 @@ module.exports = {


const projects = {}; // Unique project index to prevent building the same project multiple times
const projectWriters = {}; // Collection of memory adapters of already built libraries

const projectCountMarker = {};
function projectCount(project, count = 0) {
Expand Down Expand Up @@ -188,17 +190,29 @@ module.exports = {

const projectType = typeRepository.getType(project.type);
const resourceCollections = resourceFactory.createCollectionsForTree(project, {
useNamespaces: true
useNamespaces: true,
virtualReaders: projectWriters
});

const writer = new MemAdapter({
virBasePath: "/"
});
// Store project writer as virtual reader for parent projects
// so they can access the build results of this project
projectWriters[project.metadata.name] = writer;

// TODO: Add getter for writer of DuplexColection
const workspace = resourceFactory.createWorkspace({
virBasePath: "/",
writer,
reader: resourceCollections.source,
name: project.metadata.name
});

if (dev && devExcludeProject.indexOf(project.metadata.name) !== -1) {
projectTasks = composeTaskList({dev: false, selfContained, includedTasks, excludedTasks});
}

return projectType.build({
resourceCollections: {
workspace,
Expand Down
2 changes: 1 addition & 1 deletion lib/processors/jsdoc/jsdocGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ async function generateJsdocConfig({targetPath, tmpPath, namespace, projectName,
"variants": ${JSON.stringify(variants)},
"version": "${version}",
"jsapiFile": "${targetPath}/libraries/${projectName}.js",
"apiJsonFolder": "${targetPath}/dependency-apis",
"apiJsonFolder": "${tmpPath}/dependency-apis",
"apiJsonFile": "${targetPath}/test-resources/${namespace}/designtime/api.json"
}
}
Expand Down
52 changes: 40 additions & 12 deletions lib/tasks/generateJsdoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const {resourceFactory} = require("@ui5/fs");
* @alias module:@ui5/builder.tasks.generateJsdoc
* @param {Object} parameters Parameters
* @param {module:@ui5/fs.DuplexCollection} parameters.workspace DuplexCollection to read and write files
* @param {module:@ui5/fs.ReaderCollection} parameters.dependencies DuplexCollection to read and write files
* @param {Object} parameters.options Options
* @param {string} parameters.options.pattern Pattern to locate the files to be processed
* @param {string} parameters.options.projectName Project name
Expand All @@ -21,18 +22,25 @@ const {resourceFactory} = require("@ui5/fs");
* resources shall be generated
* @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
*/
const generateJsdoc = async function({workspace, options} = {}) {
const generateJsdoc = async function({workspace, dependencies, options} = {}) {
if (!options || !options.projectName || !options.version || !options.pattern) {
throw new Error("[generateJsdoc]: One or more mandatory options not provided");
}

const {sourcePath: resourcePath, targetPath, tmpPath} = await generateJsdoc._createTmpDirs(options.projectName);

await generateJsdoc._writeResourcesToDir({
workspace,
pattern: options.pattern,
targetPath: resourcePath
});
await Promise.all([
generateJsdoc._writeResourcesToDir({
workspace,
dependencies,
pattern: options.pattern,
targetPath: resourcePath
}),
generateJsdoc._writeDependencyApisToDir({
dependencies,
targetPath: path.posix.join(tmpPath, "dependency-apis")
})
]);

const createdResources = await jsdocGenerator({
sourcePath: resourcePath,
Expand All @@ -45,8 +53,8 @@ const generateJsdoc = async function({workspace, options} = {}) {
}
});

await Promise.all(createdResources.map(async (resource) => {
await workspace.write(resource);
await Promise.all(createdResources.map((resource) => {
return workspace.write(resource);
}));
};

Expand Down Expand Up @@ -79,15 +87,16 @@ async function createTmpDirs(projectName) {
*
* @private
* @param {string} projectName Project name used for naming the temporary directory
* @param {boolean} [keep=false] Whether to keep the temporary directory
* @returns {Promise<Object>} Promise resolving with path of the temporary directory
*/
function createTmpDir(projectName) {
function createTmpDir(projectName, keep = false) {
// Remove all non alpha-num characters from project name
const sanitizedProjectName = projectName.replace(/[^A-Za-z0-9]/g, "");
return new Promise((resolve, reject) => {
tmp.dir({
prefix: `ui5-tooling-tmp-jsdoc-${sanitizedProjectName}-`,
// keep: true,
keep,
unsafeCleanup: true
}, (err, path) => {
if (err) {
Expand All @@ -113,7 +122,7 @@ function createTmpDir(projectName) {
* @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
*/
async function writeResourcesToDir({workspace, pattern, targetPath}) {
const fsSource = resourceFactory.createAdapter({
const fsTarget = resourceFactory.createAdapter({
fsBasePath: targetPath,
virBasePath: "/resources/"
});
Expand All @@ -124,11 +133,30 @@ async function writeResourcesToDir({workspace, pattern, targetPath}) {
} else {
allResources = await workspace.byGlob(pattern);
}

// write all resources to the tmp folder
await Promise.all(allResources.map((resource) => fsSource.write(resource)));
await Promise.all(allResources.map((resource) => fsTarget.write(resource)));
}

async function writeDependencyApisToDir({dependencies, targetPath}) {
const depApis = await dependencies.byGlob("/test-resources/**/designtime/api.json");

// Clone resources before changing their path
const apis = await Promise.all(depApis.map((resource) => resource.clone()));

for (let i = 0; i < apis.length; i++) {
apis[i].setPath(`/api-${i}.json`);
}

const fsTarget = resourceFactory.createAdapter({
fsBasePath: targetPath,
virBasePath: "/"
});
await Promise.all(apis.map((resource) => fsTarget.write(resource)));
}

module.exports = generateJsdoc;
module.exports._createTmpDirs = createTmpDirs;
module.exports._createTmpDir = createTmpDir;
module.exports._writeResourcesToDir = writeResourcesToDir;
module.exports._writeDependencyApisToDir = writeDependencyApisToDir;
1 change: 1 addition & 0 deletions lib/types/library/LibraryBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class LibraryBuilder extends AbstractBuilder {
const generateJsdoc = tasks.generateJsdoc;
return generateJsdoc({
workspace: resourceCollections.workspace,
dependencies: resourceCollections.dependencies,
options: {
projectName: project.metadata.name,
version: project.version,
Expand Down
2 changes: 1 addition & 1 deletion test/lib/processors/jsdoc/jsdocGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ test("generateJsdocConfig", async (t) => {
"variants": ["apijson"],
"version": "1.0.0",
"jsapiFile": "/some/target/path/libraries/some.namespace.js",
"apiJsonFolder": "/some/target/path/dependency-apis",
"apiJsonFolder": "/some/tmp/path/dependency-apis",
"apiJsonFile": "/some/target/path/test-resources/some/namespace/designtime/api.json"
}
}
Expand Down
86 changes: 78 additions & 8 deletions test/lib/tasks/generateJsdoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ test.serial("writeResourcesToDir with byGlobSource", async (t) => {
virBasePath: "/resources/"
}, "createAdapter called with correct arguments");

t.deepEqual(writeStub.callCount, 2, "Write got called twice");
t.deepEqual(writeStub.getCall(0).args[0], "resource A", "Write got called with correct arguments");
t.deepEqual(writeStub.getCall(1).args[0], "resource B", "Write got called with correct arguments");
t.deepEqual(writeStub.callCount, 2, "Write got called four times");
t.deepEqual(writeStub.getCall(0).args[0], "resource A", "Write got called for resource A");
t.deepEqual(writeStub.getCall(1).args[0], "resource B", "Write got called for resource B");
});

test.serial("writeResourcesToDir with byGlob", async (t) => {
Expand All @@ -87,7 +87,6 @@ test.serial("writeResourcesToDir with byGlob", async (t) => {

await generateJsdoc._writeResourcesToDir({
workspace: {
// stub byGlobSource
byGlob: (pattern) => {
t.deepEqual(pattern, "some pattern", "Glob with correct pattern");
return Promise.resolve(["resource A", "resource B"]);
Expand All @@ -102,13 +101,71 @@ test.serial("writeResourcesToDir with byGlob", async (t) => {
virBasePath: "/resources/"
}, "createAdapter called with correct arguments");

t.deepEqual(writeStub.callCount, 2, "Write got called twice");
t.deepEqual(writeStub.getCall(0).args[0], "resource A", "Write got called with correct arguments");
t.deepEqual(writeStub.getCall(1).args[0], "resource B", "Write got called with correct arguments");
t.deepEqual(writeStub.callCount, 2, "Write got called four times");
t.deepEqual(writeStub.getCall(0).args[0], "resource A", "Write got called for resource A");
t.deepEqual(writeStub.getCall(1).args[0], "resource B", "Write got called for resource B");
});

test.serial("writeDependencyApisToDir with byGlob", async (t) => {
const writeStub = sinon.stub().resolves();
const createAdapterStub = sinon.stub(require("@ui5/fs").resourceFactory, "createAdapter").returns({
write: writeStub
});

const setPathStubA = sinon.stub();
const setPathStubB = sinon.stub();

const cloneStubA = sinon.stub().resolves({
// Cloned resource
id: "resource A",
setPath: setPathStubA
});
const cloneStubB = sinon.stub().resolves({
// Cloned resource
id: "resource B",
setPath: setPathStubB
});
const initialResourceA = {
// Globbed resource
clone: cloneStubA
};
const initialResourceB = {
// Globbed resource
clone: cloneStubB
};

await generateJsdoc._writeDependencyApisToDir({
dependencies: {
byGlob: (pattern) => {
t.deepEqual(pattern, "/test-resources/**/designtime/api.json",
"Dependency api.json glob with correct pattern");
return Promise.resolve([initialResourceA, initialResourceB]);
}
},
targetPath: "/some/target/path"
});

t.deepEqual(cloneStubA.callCount, 1, "resource A got cloned once");
t.deepEqual(cloneStubB.callCount, 1, "resource B got cloned once");

t.deepEqual(setPathStubA.callCount, 1, "Path of cloned resource A got changed");
t.deepEqual(setPathStubA.getCall(0).args[0], "/api-0.json", "Path of cloned resource A got changed correctly");

t.deepEqual(setPathStubB.callCount, 1, "Path of cloned resource B got changed");
t.deepEqual(setPathStubB.getCall(0).args[0], "/api-1.json", "Path of cloned resource B got changed correctly");

t.deepEqual(createAdapterStub.getCall(0).args[0], {
fsBasePath: "/some/target/path",
virBasePath: "/"
}, "createAdapter called with correct arguments");

t.deepEqual(writeStub.callCount, 2, "Write got called four times");
t.deepEqual(writeStub.getCall(0).args[0].id, "resource A", "Write got called for resource A");
t.deepEqual(writeStub.getCall(1).args[0].id, "resource B", "Write got called for resource B");
});

test.serial("generateJsdoc", async (t) => {
const jsdocGeneratorStub = sinon.stub().resolves(["some resource 1", "some resource 2"]);
const jsdocGeneratorStub = sinon.stub().resolves(["resource A", "resource B"]);
mock("../../../lib/processors/jsdoc/jsdocGenerator", jsdocGeneratorStub);
const generateJsdoc = mock.reRequire("../../../lib/tasks/generateJsdoc");

Expand All @@ -118,13 +175,15 @@ test.serial("generateJsdoc", async (t) => {
tmpPath: "/some/tmp/path",
});
const writeResourcesToDirStub = sinon.stub(generateJsdoc, "_writeResourcesToDir").resolves();
const writeDependencyApisToDirStub = sinon.stub(generateJsdoc, "_writeDependencyApisToDir").resolves();

const writeStub = sinon.stub().resolves();
const workspace = {
write: writeStub
};
await generateJsdoc({
workspace,
dependencies: "dependencies",
options: {
pattern: "some pattern",
projectName: "some.project",
Expand All @@ -139,10 +198,17 @@ test.serial("generateJsdoc", async (t) => {
t.deepEqual(writeResourcesToDirStub.callCount, 1, "writeResourcesToDir got called once");
t.deepEqual(writeResourcesToDirStub.getCall(0).args[0], {
workspace,
dependencies: "dependencies",
pattern: "some pattern",
targetPath: "/some/source/path" // one's target is another one's source
}, "writeResourcesToDir got called with correct arguments");

t.deepEqual(writeDependencyApisToDirStub.callCount, 1, "writeDependencyApisToDir got called once");
t.deepEqual(writeDependencyApisToDirStub.getCall(0).args[0], {
dependencies: "dependencies",
targetPath: "/some/tmp/path/dependency-apis"
}, "writeDependencyApisToDir got called with correct arguments");

t.deepEqual(jsdocGeneratorStub.callCount, 1, "jsdocGenerator processor got called once");
t.deepEqual(jsdocGeneratorStub.getCall(0).args[0], {
sourcePath: "/some/source/path",
Expand All @@ -155,6 +221,10 @@ test.serial("generateJsdoc", async (t) => {
}
}, "jsdocGenerator got called with correct arguments");

t.deepEqual(writeStub.callCount, 2, "Write got called twice");
t.deepEqual(writeStub.getCall(0).args[0], "resource A", "Write got called with correct arguments");
t.deepEqual(writeStub.getCall(1).args[0], "resource B", "Write got called with correct arguments");

mock.stop("../../../lib/processors/jsdoc/jsdocGenerator");
});

Expand Down

0 comments on commit b93d4bd

Please sign in to comment.