Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Add new theme-library type #285

Merged
merged 2 commits into from
Jan 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/types/library/LibraryBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class LibraryBuilder extends AbstractBuilder {
workspace: resourceCollections.workspace,
options: {
copyright: project.metadata.copyright,
pattern: "/resources/**/*.{js,json,library}"
pattern: "/resources/**/*.{js,library,less,theme}"
}
});
});
Expand All @@ -56,7 +56,7 @@ class LibraryBuilder extends AbstractBuilder {
workspace: resourceCollections.workspace,
options: {
version: project.version,
pattern: "/resources/**/*.{js,json,library}"
pattern: "/resources/**/*.{js,json,library,less,theme}"
}
});
});
Expand Down
59 changes: 59 additions & 0 deletions lib/types/themeLibrary/ThemeLibraryBuilder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const AbstractBuilder = require("../AbstractBuilder");
const tasks = { // can't require index.js due to circular dependency
generateComponentPreload: require("../../tasks/bundlers/generateComponentPreload"),
generateFlexChangesBundle: require("../../tasks/bundlers/generateFlexChangesBundle"),
generateBundle: require("../../tasks/bundlers/generateBundle"),
generateLibraryPreload: require("../../tasks/bundlers/generateLibraryPreload"),
generateManifestBundle: require("../../tasks/bundlers/generateManifestBundle"),
generateStandaloneAppBundle: require("../../tasks/bundlers/generateStandaloneAppBundle"),
buildThemes: require("../../tasks/buildThemes"),
createDebugFiles: require("../../tasks/createDebugFiles"),
generateJsdoc: require("../../tasks/jsdoc/generateJsdoc"),
executeJsdocSdkTransformation: require("../../tasks/jsdoc/executeJsdocSdkTransformation"),
generateLibraryManifest: require("../../tasks/generateLibraryManifest"),
generateVersionInfo: require("../../tasks/generateVersionInfo"),
replaceCopyright: require("../../tasks/replaceCopyright"),
replaceVersion: require("../../tasks/replaceVersion"),
uglify: require("../../tasks/uglify")
};

class ThemeLibraryBuilder extends AbstractBuilder {
addStandardTasks({resourceCollections, project, log, buildContext}) {
this.addTask("replaceCopyright", () => {
const replaceCopyright = tasks.replaceCopyright;
return replaceCopyright({
workspace: resourceCollections.workspace,
options: {
copyright: project.metadata.copyright,
pattern: "/resources/**/*.{less,theme}"
}
});
});

this.addTask("replaceVersion", () => {
const replaceVersion = tasks.replaceVersion;
return replaceVersion({
workspace: resourceCollections.workspace,
options: {
version: project.version,
pattern: "/resources/**/*.{less,theme}"
}
});
});

this.addTask("buildThemes", () => {
const buildThemes = tasks.buildThemes;
return buildThemes({
workspace: resourceCollections.workspace,
dependencies: resourceCollections.dependencies,
options: {
projectName: project.metadata.name,
librariesPattern: "/resources/**/*.library",
inputPattern: "/resources/**/themes/*/library.source.less"
}
});
});
}
}

module.exports = ThemeLibraryBuilder;
88 changes: 88 additions & 0 deletions lib/types/themeLibrary/ThemeLibraryFormatter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
const log = require("@ui5/logger").getLogger("types:themeLibrary:ThemeLibraryFormatter");
const path = require("path");
const AbstractUi5Formatter = require("../AbstractUi5Formatter");


class ThemeLibraryFormatter extends AbstractUi5Formatter {
/**
* Formats and validates the project
*
* @returns {Promise}
*/
async format() {
const project = this._project;
await this.validate();

log.verbose("Formatting theme-library project %s...", project.metadata.name);
project.resources.pathMappings = {
"/resources/": project.resources.configuration.paths.src
};

if (project.resources.configuration.paths.test) {
// Directory 'test' is somewhat optional for theme-libraries
project.resources.pathMappings["/test-resources/"] = project.resources.configuration.paths.test;
} else {
log.verbose(`Ignoring 'test' directory for project ${project.metadata.name}.` +
"Either no setting was provided or the path not found.");
}
}

/**
* Validates the project
*
* @returns {Promise} resolves if successfully validated
* @throws {Error} if validation fails
*/
validate() {
const project = this._project;
return Promise.resolve().then(() => {
if (!project) {
throw new Error("Project is undefined");
} else if (project.specVersion === "0.1" || project.specVersion === "1.0") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RandomByte do you think this simple check is okay? With this we rely on the general specVersion check within ui5-project to be executed, otherwise also other specVersions would be allowed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for the time being

throw new Error(`theme-library type requires "specVersion" 1.1 or higher. Project "specVersion" is: ${project.specVersion}`);
} else if (!project.metadata || !project.metadata.name) {
matz3 marked this conversation as resolved.
Show resolved Hide resolved
throw new Error(`"metadata.name" configuration is missing for project ${project.id}`);
} else if (!project.type) {
throw new Error(`"type" configuration is missing for project ${project.id}`);
} else if (project.version === undefined) {
throw new Error(`"version" is missing for project ${project.id}`);
}
if (!project.resources) {
project.resources = {};
}
if (!project.resources.configuration) {
project.resources.configuration = {};
}
if (!project.resources.configuration.paths) {
project.resources.configuration.paths = {};
}
if (!project.resources.configuration.paths.src) {
project.resources.configuration.paths.src = "src";
}
if (!project.resources.configuration.paths.test) {
project.resources.configuration.paths.test = "test";
}

const absoluteSrcPath = path.join(project.path, project.resources.configuration.paths.src);
const absoluteTestPath = path.join(project.path, project.resources.configuration.paths.test);
return Promise.all([
this.dirExists(absoluteSrcPath).then(function(bExists) {
if (!bExists) {
throw new Error(`Could not find source directory of project ${project.id}: ` +
`${absoluteSrcPath}`);
}
}),
this.dirExists(absoluteTestPath).then(function(bExists) {
if (!bExists) {
log.verbose(`Could not find (optional) test directory of project ${project.id}: ` +
`${absoluteSrcPath}`);
// Current signal to following consumers that "test" is not available is null
project.resources.configuration.paths.test = null;
}
})
]);
});
}
}

module.exports = ThemeLibraryFormatter;
15 changes: 15 additions & 0 deletions lib/types/themeLibrary/themeLibraryType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const ThemeLibraryFormatter = require("./ThemeLibraryFormatter");
const ThemeLibraryBuilder = require("./ThemeLibraryBuilder");

module.exports = {
format: function(project) {
return new ThemeLibraryFormatter({project}).format();
},
build: function({resourceCollections, tasks, project, parentLogger, buildContext}) {
return new ThemeLibraryBuilder({resourceCollections, project, parentLogger, buildContext}).build(tasks);
},

// Export type classes for extensibility
Builder: ThemeLibraryBuilder,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does "for extensibility" only mean that consumers can extend those classes or does it also mean that they can inject own implementations here via these two names? If so, the new expressions above should use the properties of the export, not the import names.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, subclassing

Formatter: ThemeLibraryFormatter
};
8 changes: 5 additions & 3 deletions lib/types/typeRepository.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
const applicationType = require("./application/applicationType");
const libraryType = require("./library/libraryType");
const themeLibraryType = require("./themeLibrary/themeLibraryType");
const moduleType = require("./module/moduleType");

const types = {
application: applicationType,
library: libraryType,
module: moduleType
"application": applicationType,
"library": libraryType,
"theme-library": themeLibraryType,
"module": moduleType
};

/**
Expand Down
10 changes: 10 additions & 0 deletions test/fixtures/theme.library.e/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "theme.library.e",
"version": "1.0.0",
"description": "Simple SAPUI5 based library - test for dev dependencies",
"devDependencies": {
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
<theme xmlns="http://www.sap.com/sap.ui.library.xsd" >

<name>my_theme</name>
<vendor>me</vendor>
<copyright>${copyright}</copyright>
<version>${version}</version>

</theme>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"sEntity": "Theme",
"sId": "sap_belize",
"oExtends": "base",
"sVendor": "SAP",
"aBundled": ["sap_belize_plus"],
"mCssScopes": {
"library": {
"sBaseFile": "library",
"sEmbeddingMethod": "APPEND",
"aScopes": [
{
"sLabel": "Contrast",
"sSelector": "sapContrast",
"sEmbeddedFile": "sap_belize_plus.library",
"sEmbeddedCompareFile": "library",
"sThemeIdSuffix": "Contrast",
"sThemability": "PUBLIC",
"aThemabilityFilter": [
"Color"
],
"rExcludeSelector": "\\.sapContrastPlus\\W"
}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*!
* ${copyright}
*/

* {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-touch-callout: none;
-webkit-text-size-adjust: none;
-ms-text-size-adjust: none;
}

.sapUiBody {
width: 100%;
height: 100%;
margin: 0;
font-family: @sapUiFontFamily;
font-size: 1rem;
}
Empty file.
9 changes: 9 additions & 0 deletions test/fixtures/theme.library.e/ui5.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
specVersion: "1.1"
type: theme-library
metadata:
name: theme.library.e
copyright: |-
UI development toolkit for HTML5 (OpenUI5)
* (c) Copyright 2009-xxx SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
Loading