Skip to content

Commit a59287b

Browse files
RandomBytematz3
andauthored
[FEATURE] Add new theme-library type (#285)
Theme libraries do not require as many features as normal libraries. For example they do not need a namespace. Also many build tasks are not required. Theme libraries must use specVersion 1.1 or higher Also replace copyright strings in .less and .theme files. Co-authored-by: Matthias Oßwald <1410947+matz3@users.noreply.github.com>
1 parent c21e13e commit a59287b

File tree

12 files changed

+428
-5
lines changed

12 files changed

+428
-5
lines changed

lib/types/library/LibraryBuilder.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class LibraryBuilder extends AbstractBuilder {
4545
workspace: resourceCollections.workspace,
4646
options: {
4747
copyright: project.metadata.copyright,
48-
pattern: "/resources/**/*.{js,json,library}"
48+
pattern: "/resources/**/*.{js,library,less,theme}"
4949
}
5050
});
5151
});
@@ -56,7 +56,7 @@ class LibraryBuilder extends AbstractBuilder {
5656
workspace: resourceCollections.workspace,
5757
options: {
5858
version: project.version,
59-
pattern: "/resources/**/*.{js,json,library}"
59+
pattern: "/resources/**/*.{js,json,library,less,theme}"
6060
}
6161
});
6262
});
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
const AbstractBuilder = require("../AbstractBuilder");
2+
const tasks = { // can't require index.js due to circular dependency
3+
generateComponentPreload: require("../../tasks/bundlers/generateComponentPreload"),
4+
generateFlexChangesBundle: require("../../tasks/bundlers/generateFlexChangesBundle"),
5+
generateBundle: require("../../tasks/bundlers/generateBundle"),
6+
generateLibraryPreload: require("../../tasks/bundlers/generateLibraryPreload"),
7+
generateManifestBundle: require("../../tasks/bundlers/generateManifestBundle"),
8+
generateStandaloneAppBundle: require("../../tasks/bundlers/generateStandaloneAppBundle"),
9+
buildThemes: require("../../tasks/buildThemes"),
10+
createDebugFiles: require("../../tasks/createDebugFiles"),
11+
generateJsdoc: require("../../tasks/jsdoc/generateJsdoc"),
12+
executeJsdocSdkTransformation: require("../../tasks/jsdoc/executeJsdocSdkTransformation"),
13+
generateLibraryManifest: require("../../tasks/generateLibraryManifest"),
14+
generateVersionInfo: require("../../tasks/generateVersionInfo"),
15+
replaceCopyright: require("../../tasks/replaceCopyright"),
16+
replaceVersion: require("../../tasks/replaceVersion"),
17+
uglify: require("../../tasks/uglify")
18+
};
19+
20+
class ThemeLibraryBuilder extends AbstractBuilder {
21+
addStandardTasks({resourceCollections, project, log, buildContext}) {
22+
this.addTask("replaceCopyright", () => {
23+
const replaceCopyright = tasks.replaceCopyright;
24+
return replaceCopyright({
25+
workspace: resourceCollections.workspace,
26+
options: {
27+
copyright: project.metadata.copyright,
28+
pattern: "/resources/**/*.{less,theme}"
29+
}
30+
});
31+
});
32+
33+
this.addTask("replaceVersion", () => {
34+
const replaceVersion = tasks.replaceVersion;
35+
return replaceVersion({
36+
workspace: resourceCollections.workspace,
37+
options: {
38+
version: project.version,
39+
pattern: "/resources/**/*.{less,theme}"
40+
}
41+
});
42+
});
43+
44+
this.addTask("buildThemes", () => {
45+
const buildThemes = tasks.buildThemes;
46+
return buildThemes({
47+
workspace: resourceCollections.workspace,
48+
dependencies: resourceCollections.dependencies,
49+
options: {
50+
projectName: project.metadata.name,
51+
librariesPattern: "/resources/**/*.library",
52+
inputPattern: "/resources/**/themes/*/library.source.less"
53+
}
54+
});
55+
});
56+
}
57+
}
58+
59+
module.exports = ThemeLibraryBuilder;
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
const log = require("@ui5/logger").getLogger("types:themeLibrary:ThemeLibraryFormatter");
2+
const path = require("path");
3+
const AbstractUi5Formatter = require("../AbstractUi5Formatter");
4+
5+
6+
class ThemeLibraryFormatter extends AbstractUi5Formatter {
7+
/**
8+
* Formats and validates the project
9+
*
10+
* @returns {Promise}
11+
*/
12+
async format() {
13+
const project = this._project;
14+
await this.validate();
15+
16+
log.verbose("Formatting theme-library project %s...", project.metadata.name);
17+
project.resources.pathMappings = {
18+
"/resources/": project.resources.configuration.paths.src
19+
};
20+
21+
if (project.resources.configuration.paths.test) {
22+
// Directory 'test' is somewhat optional for theme-libraries
23+
project.resources.pathMappings["/test-resources/"] = project.resources.configuration.paths.test;
24+
} else {
25+
log.verbose(`Ignoring 'test' directory for project ${project.metadata.name}.` +
26+
"Either no setting was provided or the path not found.");
27+
}
28+
}
29+
30+
/**
31+
* Validates the project
32+
*
33+
* @returns {Promise} resolves if successfully validated
34+
* @throws {Error} if validation fails
35+
*/
36+
validate() {
37+
const project = this._project;
38+
return Promise.resolve().then(() => {
39+
if (!project) {
40+
throw new Error("Project is undefined");
41+
} else if (project.specVersion === "0.1" || project.specVersion === "1.0") {
42+
throw new Error(`theme-library type requires "specVersion" 1.1 or higher. Project "specVersion" is: ${project.specVersion}`);
43+
} else if (!project.metadata || !project.metadata.name) {
44+
throw new Error(`"metadata.name" configuration is missing for project ${project.id}`);
45+
} else if (!project.type) {
46+
throw new Error(`"type" configuration is missing for project ${project.id}`);
47+
} else if (project.version === undefined) {
48+
throw new Error(`"version" is missing for project ${project.id}`);
49+
}
50+
if (!project.resources) {
51+
project.resources = {};
52+
}
53+
if (!project.resources.configuration) {
54+
project.resources.configuration = {};
55+
}
56+
if (!project.resources.configuration.paths) {
57+
project.resources.configuration.paths = {};
58+
}
59+
if (!project.resources.configuration.paths.src) {
60+
project.resources.configuration.paths.src = "src";
61+
}
62+
if (!project.resources.configuration.paths.test) {
63+
project.resources.configuration.paths.test = "test";
64+
}
65+
66+
const absoluteSrcPath = path.join(project.path, project.resources.configuration.paths.src);
67+
const absoluteTestPath = path.join(project.path, project.resources.configuration.paths.test);
68+
return Promise.all([
69+
this.dirExists(absoluteSrcPath).then(function(bExists) {
70+
if (!bExists) {
71+
throw new Error(`Could not find source directory of project ${project.id}: ` +
72+
`${absoluteSrcPath}`);
73+
}
74+
}),
75+
this.dirExists(absoluteTestPath).then(function(bExists) {
76+
if (!bExists) {
77+
log.verbose(`Could not find (optional) test directory of project ${project.id}: ` +
78+
`${absoluteSrcPath}`);
79+
// Current signal to following consumers that "test" is not available is null
80+
project.resources.configuration.paths.test = null;
81+
}
82+
})
83+
]);
84+
});
85+
}
86+
}
87+
88+
module.exports = ThemeLibraryFormatter;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const ThemeLibraryFormatter = require("./ThemeLibraryFormatter");
2+
const ThemeLibraryBuilder = require("./ThemeLibraryBuilder");
3+
4+
module.exports = {
5+
format: function(project) {
6+
return new ThemeLibraryFormatter({project}).format();
7+
},
8+
build: function({resourceCollections, tasks, project, parentLogger, buildContext}) {
9+
return new ThemeLibraryBuilder({resourceCollections, project, parentLogger, buildContext}).build(tasks);
10+
},
11+
12+
// Export type classes for extensibility
13+
Builder: ThemeLibraryBuilder,
14+
Formatter: ThemeLibraryFormatter
15+
};

lib/types/typeRepository.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
const applicationType = require("./application/applicationType");
22
const libraryType = require("./library/libraryType");
3+
const themeLibraryType = require("./themeLibrary/themeLibraryType");
34
const moduleType = require("./module/moduleType");
45

56
const types = {
6-
application: applicationType,
7-
library: libraryType,
8-
module: moduleType
7+
"application": applicationType,
8+
"library": libraryType,
9+
"theme-library": themeLibraryType,
10+
"module": moduleType
911
};
1012

1113
/**
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "theme.library.e",
3+
"version": "1.0.0",
4+
"description": "Simple SAPUI5 based library - test for dev dependencies",
5+
"devDependencies": {
6+
},
7+
"scripts": {
8+
"test": "echo \"Error: no test specified\" && exit 1"
9+
}
10+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<theme xmlns="http://www.sap.com/sap.ui.library.xsd" >
3+
4+
<name>my_theme</name>
5+
<vendor>me</vendor>
6+
<copyright>${copyright}</copyright>
7+
<version>${version}</version>
8+
9+
</theme>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"sEntity": "Theme",
3+
"sId": "sap_belize",
4+
"oExtends": "base",
5+
"sVendor": "SAP",
6+
"aBundled": ["sap_belize_plus"],
7+
"mCssScopes": {
8+
"library": {
9+
"sBaseFile": "library",
10+
"sEmbeddingMethod": "APPEND",
11+
"aScopes": [
12+
{
13+
"sLabel": "Contrast",
14+
"sSelector": "sapContrast",
15+
"sEmbeddedFile": "sap_belize_plus.library",
16+
"sEmbeddedCompareFile": "library",
17+
"sThemeIdSuffix": "Contrast",
18+
"sThemability": "PUBLIC",
19+
"aThemabilityFilter": [
20+
"Color"
21+
],
22+
"rExcludeSelector": "\\.sapContrastPlus\\W"
23+
}
24+
]
25+
}
26+
}
27+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*!
2+
* ${copyright}
3+
*/
4+
5+
* {
6+
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
7+
-webkit-touch-callout: none;
8+
-webkit-text-size-adjust: none;
9+
-ms-text-size-adjust: none;
10+
}
11+
12+
.sapUiBody {
13+
width: 100%;
14+
height: 100%;
15+
margin: 0;
16+
font-family: @sapUiFontFamily;
17+
font-size: 1rem;
18+
}

test/fixtures/theme.library.e/test/theme/library/e/Test.html

Whitespace-only changes.

0 commit comments

Comments
 (0)