├── .gitattributes
├── .travis.yml
├── .gitignore
├── docs
├── ui5-schemas.png
└── xml-code-completion.gif
├── templates
└── misc.xml
├── .eslintrc.js
├── .editorconfig
├── lib
├── Util.js
├── main.js
├── download.js
├── link.js
├── Options.js
└── upgrade.js
├── LICENSE
├── package.json
├── bin
└── index.js
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - "8.10"
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | dist
3 | node_modules
4 | .tmp
5 | .idea
6 | npm-debug.log
7 | *.iml
8 |
--------------------------------------------------------------------------------
/docs/ui5-schemas.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ui5experts/ui5-schemas/HEAD/docs/ui5-schemas.png
--------------------------------------------------------------------------------
/templates/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/xml-code-completion.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ui5experts/ui5-schemas/HEAD/docs/xml-code-completion.gif
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | 'extends': 'airbnb-base',
3 | 'rules': {
4 | 'linebreak-style': 0
5 | }
6 | };
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [*.md]
11 | trim_trailing_whitespace = false
12 |
--------------------------------------------------------------------------------
/lib/Util.js:
--------------------------------------------------------------------------------
1 | const os = require('os');
2 | const path = require('path');
3 |
4 | class Util {
5 | static getAppDataDir() {
6 | let appDataPath = process.env.APPDATA;
7 | if (!appDataPath) {
8 | if (process.platform === 'darwin') {
9 | appDataPath = path.join(os.homedir(), 'Library/Application Support');
10 | } else if (process.platform === 'linux') {
11 | appDataPath = path.join(os.homedir(), '.local/share');
12 | }
13 | }
14 | return appDataPath;
15 | }
16 | }
17 |
18 | module.exports = Util;
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017-2018 UI5 Experts
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ui5-schemas",
3 | "version": "0.5.0",
4 | "description": "UI5 Schemas allows you to develop SAPUI5/OpenUI5 XML at a maximum convenience. It downloads, upgrades and sets up SAPUI5/OpenUI5 XML schemas for a better development experience in your favorite IDE (if it is WebStorm ;).",
5 | "author": {
6 | "name": "Christian Schuff",
7 | "email": "christian.schuff@ui5experts.com",
8 | "url": "http://www.ui5experts.com"
9 | },
10 | "bin": "bin/index.js",
11 | "scripts": {
12 | "release": "np",
13 | "test": "npm run -s eslint",
14 | "eslint": "eslint 'bin/**/*.js' 'lib/**/*.js'"
15 | },
16 | "repository": {
17 | "type": "git",
18 | "url": "git@github.com:ui5experts/ui5-schemas.git"
19 | },
20 | "keywords": [
21 | "SAPUI5",
22 | "OpenUI5",
23 | "UI5",
24 | "SAP",
25 | "XML",
26 | "XMLView",
27 | "XML-Schema",
28 | "XSD",
29 | "WebStorm",
30 | "Eclipse",
31 | "Code Completion",
32 | "Development",
33 | "Intellisense"
34 | ],
35 | "license": "MIT",
36 | "engines": {
37 | "node": "^8.10.0"
38 | },
39 | "dependencies": {
40 | "fs-extra": "8.1.0",
41 | "minilog": "3.1.0",
42 | "request": "2.88.0",
43 | "request-promise": "4.2.4",
44 | "xml2js": "0.4.22",
45 | "yargs": "14.0.0"
46 | },
47 | "devDependencies": {
48 | "eslint": "5.16.0",
49 | "eslint-config-airbnb-base": "13.2.0",
50 | "eslint-plugin-import": "2.18.2",
51 | "np": "5.0.3"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/main.js:
--------------------------------------------------------------------------------
1 | const Minilog = require('minilog');
2 |
3 | const download = require('./download');
4 | const upgrade = require('./upgrade');
5 | const link = require('./link');
6 |
7 | const log = Minilog('ui5-schemas');
8 |
9 | function createLogger(debug) {
10 | const myFilter = new Minilog.Filter();
11 | myFilter.clear().deny('ui5-schemas', debug ? '*' : 'debug');
12 | Minilog.pipe(myFilter)
13 | .pipe(Minilog.backends.console.formatMinilog)
14 | .pipe(Minilog.backends.console);
15 | }
16 |
17 |
18 | // TODO: Return Promise
19 | const main = async function main(options) {
20 | createLogger(options.debug);
21 |
22 | await options.initialize();
23 |
24 | log.info(`Preparing '${options.sdk}' schemas in version '${options.version || 'latest'}'...`);
25 |
26 | let allLibs = {};
27 |
28 | // do the downloading and encapsulate in Promise
29 | const dlPromise = new Promise((resolve, reject) => {
30 | download.allLibsFile(options)
31 | .then((allLibsJSON) => {
32 | allLibs = allLibsJSON;
33 | download.schemas(options, allLibs)
34 | .then((values) => {
35 | resolve(values);
36 | })
37 | .catch((e) => {
38 | reject(e);
39 | });
40 | })
41 | .catch((e) => {
42 | reject(e);
43 | });
44 | });
45 |
46 |
47 | dlPromise.then(() => {
48 | log.info('Yay, all schema files were successfully downloaded!');
49 | if (options.upgrade) {
50 | upgrade(options, allLibs);
51 | }
52 | if (options.link) {
53 | link(options, allLibs);
54 | }
55 | }, (e) => {
56 | log.error('Damn... Something went all wrong while downloading the schema files!');
57 | log.error(`Are you sure the version '${options.version}' is still available on '${options.sdk}' download pages?`);
58 | log.error(e);
59 | });
60 | };
61 |
62 |
63 | module.exports = main;
64 |
--------------------------------------------------------------------------------
/lib/download.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const request = require('request');
3 | const fs = require('fs-extra');
4 | const Minilog = require('minilog');
5 |
6 | const log = Minilog('ui5-schemas');
7 |
8 | const schemaSuffix = '.xsd';
9 |
10 |
11 | module.exports = {
12 | allLibsFile: function allLibsFile(options) {
13 | log.debug('[download]', `Downloading all libraries metafile from '${options.allLibsUrl}'`);
14 | return new Promise((resolve, reject) => {
15 | request(options.allLibsUrl, (err, res, body) => {
16 | if (err) {
17 | reject(err);
18 | return;
19 | }
20 | try {
21 | const allLibs = JSON.parse(body);
22 | resolve(allLibs);
23 | } catch (e) {
24 | reject(e);
25 | }
26 | });
27 | });
28 | },
29 |
30 | schemas: function schemas(options, allLibs) {
31 | const allLibsRegistry = allLibs.all_libs;
32 | const downloadPromises = [];
33 |
34 | for (let i = 0; i < allLibsRegistry.length; i += 1) {
35 | const schemaFileName = allLibsRegistry[i].entry.replace(/\//g, '.') + schemaSuffix;
36 | const schemaFileURL = `${options.schemaBaseUrl}/${schemaFileName}`;
37 |
38 | downloadPromises.push(new Promise((resolve, reject) => {
39 | log.debug('[download]', `Downloading library schema from '${schemaFileURL}'`);
40 | request(schemaFileURL, (err, res, body) => {
41 | if (err) {
42 | reject(err);
43 | return;
44 | }
45 |
46 | const targetFile = path.join(options.schemaTargetBasePath, schemaFileName);
47 | allLibsRegistry[i].location = targetFile;
48 | log.debug('[download]', `Writing library schema file to '${targetFile}'`);
49 | fs.outputFile(targetFile, body)
50 | .then((data) => {
51 | resolve(data);
52 | })
53 | .catch((fileErr) => {
54 | reject(fileErr);
55 | });
56 | });
57 | }));
58 | }
59 |
60 | return Promise.all(downloadPromises);
61 | },
62 | };
63 |
--------------------------------------------------------------------------------
/bin/index.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | const yargs = require('yargs');
3 |
4 | const ui5Schemas = require('../lib/main');
5 | const Options = require('../lib/Options');
6 |
7 |
8 | const { argv } = yargs.usage('Usage: ui5-schemas [options]')
9 | .example('ui5-schemas --sdk openui5 --version 1.28.15', 'Setup with openui5 schemas in version 1.28.15')
10 | .example('ui5-schemas --sdk openui5nightly', 'Setup with openui5nightly')
11 | .example('ui5-schemas --origin \'/Users/cschuff/Downloads/sapui5-sdk-1.65.1\'', 'Setup schemas from local sdk download')
12 | .example('ui5-schemas --origin \'https://my.abap.system/sap/public/bc/ui5_ui5\'', 'Setup schemas from sdk on an ABAP system')
13 | .example('ui5-schemas --no-upgrade', 'Setup schemas without schema enhancement')
14 | .example('npx ui5-schemas --sdk openui5 --version 1.28.15', 'NPM5')
15 |
16 | .option('origin', {
17 | describe: 'The src url (sdk base url) or path (sdk root dir) to be used for schema loading.',
18 | type: 'string',
19 | })
20 |
21 | .option('sdk', {
22 | demandOption: true,
23 | default: 'sapui5',
24 | describe: 'The sdk to be used.',
25 | choices: ['sapui5', 'openui5', 'openui5nightly'],
26 | type: 'string',
27 | })
28 |
29 | .version(false)
30 | .option('version', {
31 | alias: 'v',
32 | demandOption: true,
33 | default: '',
34 | describe: 'The UI5 version to be used, defaults to \'\' which means latest.',
35 | type: 'string',
36 | })
37 |
38 | // .describe('libs', 'Comma-separated list of UI5 libraries that should be downloaded (and linked'
39 | // + ' to your project), e.g. "sap.ui.core, sap.m" .')
40 |
41 | .option('upgrade', {
42 | demandOption: true,
43 | default: true,
44 | describe: 'Whether to upgrade UI5 schemas for a better development experience or leave them untouched.',
45 | type: 'boolean',
46 | })
47 |
48 | .option('link', {
49 | demandOption: true,
50 | default: true,
51 | describe: 'Whether to auto-link UI5 schemas with your favorite IDE (if it is WebStorm ;).',
52 | type: 'boolean',
53 | })
54 |
55 | .option('debug', {
56 | demandOption: true,
57 | default: process.env.SYSTEM_DEBUG === 'true',
58 | describe: 'Whether to show debug output',
59 | type: 'boolean',
60 | })
61 |
62 | .help('h')
63 | .alias('h', 'help');
64 |
65 |
66 | const options = new Options(argv);
67 | ui5Schemas(options);
68 |
--------------------------------------------------------------------------------
/lib/link.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const fs = require('fs-extra');
3 | const xml2js = require('xml2js');
4 | const Minilog = require('minilog');
5 |
6 | const parser = new xml2js.Parser();
7 | const builder = new xml2js.Builder();
8 | const log = Minilog('ui5-schemas');
9 |
10 |
11 | const idePaths = {
12 | idea: {
13 | base: path.join(process.cwd(), '.idea'),
14 | schemaRegistry: path.join(process.cwd(), '.idea/misc.xml'),
15 | template: path.join(__dirname, '../templates/misc.xml'),
16 | },
17 | eclipse: '',
18 | };
19 |
20 |
21 | function createIdeaRegEntry(url, location) {
22 | return {
23 | $: {
24 | url,
25 | location: `${location}`,
26 | },
27 | };
28 | }
29 |
30 |
31 | function registerLibs(data, allLibs) {
32 | try {
33 | parser.parseString(data, (err, result) => {
34 | if (err) {
35 | log.error('[link]', err);
36 | return;
37 | }
38 |
39 | const projectResourcesElement = {
40 | $: {
41 | name: 'ProjectResources',
42 | },
43 | resource: [],
44 | };
45 |
46 | // ensure target element exists
47 | const misc = result;
48 | misc.project = misc.project || {};
49 | misc.project.component = misc.project.component || [projectResourcesElement];
50 |
51 | let projectResourcesObj = misc.project.component.find(element => element.$.name === 'ProjectResources');
52 | if (!projectResourcesObj) {
53 | projectResourcesObj = projectResourcesElement;
54 | misc.project.component.push(projectResourcesObj);
55 | }
56 |
57 | const projectResources = projectResourcesObj.resource;
58 | const allLibsRegistry = allLibs.all_libs;
59 | for (let i = 0; i < allLibsRegistry.length; i += 1) {
60 | const lib = allLibsRegistry[i];
61 | const schemaURL = lib.entry.replace(/\//g, '.');
62 |
63 | let libRegEntry = projectResources.filter(item => item.$.url === schemaURL);
64 | if (libRegEntry.length) {
65 | log.debug('[link]', `Updating schema location of lib '${schemaURL}' ...`);
66 | libRegEntry[0].$.location = lib.location;
67 | } else {
68 | log.debug('[link]', `Creating new schema entry for lib '${schemaURL}' ...`);
69 | libRegEntry = createIdeaRegEntry(schemaURL, lib.location);
70 | projectResources.push(libRegEntry);
71 | }
72 | }
73 |
74 | fs.outputFile(idePaths.idea.schemaRegistry, builder.buildObject(misc))
75 | .then(() => {
76 | log.info('[link]', 'Schemas successfully registered!');
77 | })
78 | .catch(() => {
79 | log.error('[link]', 'Ough... Problem occured during schema registration!');
80 | });
81 | });
82 | } catch (e) {
83 | log.error(e);
84 | }
85 | }
86 |
87 |
88 | function idea(options, allLibs) {
89 | fs.pathExists(idePaths.idea.base)
90 | .then((exists) => {
91 | if (!exists) {
92 | return;
93 | }
94 | log.info('[link]', 'Discovered an .idea project! Registering schemas...');
95 |
96 | fs.readFile(idePaths.idea.schemaRegistry)
97 | .then((data) => {
98 | registerLibs(data, allLibs);
99 | })
100 | .catch((err) => {
101 | log.debug('[link]', err);
102 | log.warn('[link]', `'${idePaths.idea.schemaRegistry}' doesn't exist. Creating...`);
103 | fs.copy(idePaths.idea.template, idePaths.idea.schemaRegistry)
104 | .then(() => {
105 | // recurse and start again from scratch
106 | idea(options, allLibs);
107 | })
108 | .catch((copyErr) => {
109 | log.error('[link]', copyErr);
110 | });
111 | });
112 | });
113 | }
114 |
115 |
116 | module.exports = function link(options, allLibs) {
117 | idea(options, allLibs);
118 | };
119 |
--------------------------------------------------------------------------------
/lib/Options.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable class-methods-use-this */
2 | const path = require('path');
3 | const Minilog = require('minilog');
4 | const request = require('request-promise');
5 | const fs = require('fs-extra');
6 |
7 | const Util = require('./Util');
8 |
9 | const log = Minilog('ui5-schemas');
10 |
11 | class Options {
12 | constructor(options) {
13 | this.options = options;
14 |
15 | if (this.options.origin) {
16 | // ignore sdk/version if origin is provided
17 | delete this.options.version;
18 | delete this.options.sdk;
19 | } else if (this.options.sdk === 'openui5nightly') {
20 | // ignore version if openui5nightly
21 | delete this.options.version;
22 | }
23 | }
24 |
25 | async initialize() {
26 | await this.determineVersion();
27 | }
28 |
29 | async determineVersion() {
30 | if (!this.options.origin && this.version) {
31 | return;
32 | }
33 |
34 | let versionOrigin;
35 | if (this.options.origin) {
36 | log.info(`Determining version from origin '${this.options.origin}' ...`);
37 | versionOrigin = `${this.options.origin}/resources/sap-ui-version.json`;
38 | } else if (!this.version) {
39 | log.info(`Attempting to download latest version of '${this.sdk}'. Determining latest version...`);
40 | versionOrigin = `${this.sdkBaseURI}/resources/sap-ui-version.json`;
41 | }
42 |
43 | const sapUiVersion = await Options.loadVersion(versionOrigin);
44 | this.version = sapUiVersion.version;
45 |
46 | // also determine sdk from download if using origin
47 | if (this.options.origin) {
48 | this.sdk = sapUiVersion.name.toLowerCase().indexOf('sapui5') !== -1 ? 'sapui5' : 'openui5';
49 | }
50 |
51 | log.info(`Detected version of sdk '${this.sdk}' is '${this.version}'`);
52 | }
53 |
54 | static async loadVersion(versionOrigin) {
55 | log.info(versionOrigin);
56 | if (versionOrigin.startsWith('http')) {
57 | return JSON.parse(await request(versionOrigin));
58 | }
59 | return fs.readJSON(versionOrigin);
60 | }
61 |
62 | get origin() {
63 | return this.options.version;
64 | }
65 |
66 | set origin(version) {
67 | this.options.version = version;
68 | }
69 |
70 | get version() {
71 | return this.options.version;
72 | }
73 |
74 | set version(version) {
75 | this.options.version = version;
76 | }
77 |
78 | isSnapshotVersion() {
79 | return this.options.version.endsWith('-SNAPSHOT');
80 | }
81 |
82 | set sdk(sdk) {
83 | this.options.sdk = sdk;
84 | }
85 |
86 | get sdk() {
87 | return this.options.sdk;
88 | }
89 |
90 | get upgrade() {
91 | return this.options.upgrade;
92 | }
93 |
94 | get link() {
95 | return this.options.link;
96 | }
97 |
98 | get debug() {
99 | return this.options.debug;
100 | }
101 |
102 | get schemaDir() {
103 | return 'downloads/schemas';
104 | }
105 |
106 | get schemaBaseUrl() {
107 | const schemaPath = this.isSnapshotVersion()
108 | ? this.schemaDir : path.posix.join(this.options.version, this.schemaDir);
109 | return `${this.sdkBaseURI}/${schemaPath}`;
110 | }
111 |
112 | get schemaTargetBasePath() {
113 | const sdk = this.sdk === 'openui5nightly' ? 'openui5' : this.sdk;
114 | return path.join(this.ui5SchemasBaseDir, sdk, this.version);
115 | }
116 |
117 | get ui5SchemasBaseDir() {
118 | return path.join(Util.getAppDataDir(), 'ui5experts', 'ui5-schemas');
119 | }
120 |
121 | get allLibsPath() {
122 | if (this.isSnapshotVersion()) {
123 | path.join(this.ui5SchemasBaseDir, this.sdk, 'all_libs');
124 | }
125 | return path.join(this.ui5SchemasBaseDir, this.sdk, this.version, 'all_libs');
126 | }
127 |
128 | get allLibsUrl() {
129 | let allLibsPath;
130 | if (this.isSnapshotVersion()) {
131 | allLibsPath = this.allLibsMetafile;
132 | } else {
133 | allLibsPath = path.posix.join(this.options.version, this.allLibsMetafile);
134 | }
135 | return `${this.sdkBaseURI}/${allLibsPath}`;
136 | }
137 |
138 | get allLibsMetafile() {
139 | return 'discovery/all_libs';
140 | }
141 |
142 | get sdkBaseURI() {
143 | if (this.options.sdk === 'sapui5') {
144 | return 'https://sapui5.hana.ondemand.com';
145 | } if (this.options.sdk === 'openui5nightly') {
146 | return 'https://openui5nightly.hana.ondemand.com';
147 | }
148 | return 'https://openui5.hana.ondemand.com';
149 | }
150 | }
151 |
152 | module.exports = Options;
153 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | [](https://www.npmjs.com/package/ui5-schemas)
4 | [](https://travis-ci.org/ui5experts/ui5-schemas)
5 | [](https://www.bithound.io/github/ui5experts/ui5-schemas)
6 | []()
7 |
8 |
9 | ## ⚠️ NOTE
10 |
11 | As [SAP sunsetted the support for the SAPUI5 Tools for Eclipse](https://blogs.sap.com/2019/11/26/sapui5-tools-for-eclipse-now-is-the-time-to-look-for-alternatives/) they also removed the XSD schemas from the project. ui5-schemas obviously can not work without those schemas. If you want to continue using ui5-schemas keep using the latest available version of SAPUI5/OpenUI5 that includes schemas which is *1.71*.
12 |
13 | I'm working together with the SAP colleagues to potentially find an alternative solution to keep this project alive. Stay tuned!
14 |
15 | More detailed information on the issue in [sap/openui5#2751](https://github.com/SAP/openui5/issues/2751) resp. [ui5experts/ui5-schemas#47](https://github.com/ui5experts/ui5-schemas/issues/47)
16 |
17 | ## What is UI5 Schemas?
18 |
19 | UI5 Schemas allows you to develop SAPUI5/OpenUI5 XML at a maximum convenience. It downloads, upgrades and sets
20 | up SAPUI5/OpenUI5 XML schemas for a better development experience in your favorite IDE (if it is WebStorm ;).
21 |
22 | 
23 |
24 |
25 | ## Getting Started
26 |
27 | ```sh
28 | $ npm install -g ui5-schemas
29 | ```
30 |
31 | ```sh
32 | $ ui5-schemas
33 | ```
34 |
35 | npm 5:
36 | ```sh
37 | $ npx ui5-schemas
38 | ````
39 |
40 | Use cli option ``--help`` for more details
41 |
42 | ```sh
43 | $ ui5-schemas --help
44 |
45 | Usage: ui5-schemas [options]
46 |
47 | Options:
48 | --origin The src url (sdk base url) or path (sdk root dir) to be used
49 | for schema loading. [string]
50 | --sdk The sdk to be used.
51 | [string] [choices: "sapui5", "openui5", "openui5nightly"] [default: "sapui5"]
52 | --version, -v The UI5 version to be used, defaults to '' which means latest.
53 | [string] [default: ""]
54 | --upgrade Whether to upgrade UI5 schemas for a better development
55 | experience or leave them untouched.
56 | [boolean] [default: true]
57 | --link Whether to auto-link UI5 schemas with your favorite IDE (if it
58 | is WebStorm ;). [boolean] [default: true]
59 | --debug Whether to show debug output
60 | [boolean] [default: false]
61 | -h, --help Show help
62 |
63 | Examples:
64 | ui5-schemas --sdk openui5 --version 1.28.15 Setup with openui5 schemas in version 1.28.15
65 | ui5-schemas --sdk openui5nightly Setup with openui5nightly
66 | ui5-schemas --origin '/Users/cschuff/Downloads/sapui5-sdk-1.65.1'
67 | Setup schemas from local sdk download
68 | ui5-schemas --origin 'https://my.abap.system/sap/public/bc/ui5_ui5'
69 | Setup schemas from sdk on an ABAP system
70 | ui5-schemas --no-upgrade Setup schemas without schema enhancement
71 | npx ui5-schemas --sdk openui5 --version 1.28.15 NPM5
72 | ```
73 |
74 |
75 | ## Features
76 |
77 | ### Custom Origin
78 | Install schemas from any origin: Use the CDN, a downloaded SDK or even your own remote system.
79 |
80 | ### Multi-SDK Support
81 | Use the 'OpenUI5', 'OpenUI5 Nightly' or 'SAPUI5' SDK for your project.
82 |
83 | ### Multi-Version Support
84 | Use any available OpenUI5/SAPUI5 version in your project. Switch versions with ease!
85 |
86 |
87 | ## Known Limitations
88 |
89 | The xml schema files provided by SAP come with some limitations that this module does not fix (yet):
90 | * Binding syntax is not supported ([#3](https://github.com/ui5experts/ui5-schemas/issues/3))
91 | * Aggregation Bindings that can be written as properties ([#29](https://github.com/ui5experts/ui5-schemas/issues/29))
92 | * ...
93 |
94 |
95 | ## Usage behind Proxies
96 |
97 | Proxies used according to [npm module request](https://www.npmjs.com/package/request#proxies). Make sure to have set the following env vars:
98 | * HTTP_PROXY / http_proxy
99 | * HTTPS_PROXY / https_proxy
100 | * NO_PROXY / no_proxy
101 |
102 | If you are behind a corporate proxy and experience 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY' it is most probably due to an invalid proxy certificate. You can still run ui5-schemas like this at your own risk:
103 | ```sh
104 | NODE_TLS_REJECT_UNAUTHORIZED=0 ui5-schemas
105 | # windows
106 | set NODE_TLS_REJECT_UNAUTHORIZED=0
107 | ui5-schemas
108 | ```
109 |
110 | If none of this works just download a SAPUI5/OpenUI5 SDK and install schemas from the filesystem:
111 | ```sh
112 | $ ui5-schemas --origin '/Users/cschuff/Downloads/sapui5-sdk-1.65.1'
113 | ```
114 |
115 |
116 | ## What is yet to come?
117 |
118 | * Eclipse support
119 | * Feel free to [open an issue](https://github.com/ui5experts/ui5-schemas/issues/new) if you are missing something else!
120 |
--------------------------------------------------------------------------------
/lib/upgrade.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs-extra');
2 | const xml2js = require('xml2js');
3 | const Minilog = require('minilog');
4 |
5 | const parser = new xml2js.Parser();
6 | const builder = new xml2js.Builder();
7 | const log = Minilog('ui5-schemas');
8 |
9 | // Regex Aggregation Binding, simple binding: {(.*\n)*.*}
10 | // no need to change xsd:string
11 |
12 | function createAttributeJSON(name, type, docs) {
13 | return {
14 | $: {
15 | name,
16 | type,
17 | },
18 | 'xsd:annotation': [
19 | {
20 | 'xsd:documentation': [docs],
21 | },
22 | ],
23 | };
24 | }
25 |
26 | // TODO: Add support for 'binding' and 'objectBindings' (see https://github.com/SAP/openui5/blob/bbc8652c94512f237c55014cdb928fb56fa6aafa/src/sap.ui.core/src/sap/ui/core/XMLTemplateProcessor.js)
27 | function sapUiCoreView(data) {
28 | log.debug('[enhance]', 'Improving sap.ui.core.View');
29 | const view = data['xsd:schema']['xsd:complexType'].find(element => element.$.name === '_ViewType');
30 | const viewAttributes = view['xsd:complexContent'][0]['xsd:extension'][0]['xsd:attribute'];
31 | if (viewAttributes.filter(attr => attr.$.name === 'controllerName').length === 0) {
32 | viewAttributes.push(createAttributeJSON('controllerName', 'xsd:string',
33 | 'Name of the controller class to use for this view.'));
34 | }
35 | if (viewAttributes.filter(attr => attr.$.name === 'resourceBundleName').length === 0) {
36 | viewAttributes.push(createAttributeJSON('resourceBundleName', 'xsd:string',
37 | '(module) Name of a resource bundle that should be loaded for this view'));
38 | }
39 | if (viewAttributes.filter(attr => attr.$.name === 'resourceBundleUrl').length === 0) {
40 | viewAttributes.push(createAttributeJSON('resourceBundleUrl', 'xsd:string',
41 | 'URL of a resource bundle that should be loaded for this view'));
42 | }
43 | if (viewAttributes.filter(attr => attr.$.name === 'resourceBundleLocale').length === 0) {
44 | viewAttributes.push(createAttributeJSON('resourceBundleLocale', 'xsd:string',
45 | 'Locale that should be used to load a resource bundle for this view'));
46 | }
47 | if (viewAttributes.filter(attr => attr.$.name === 'resourceBundleAlias').length === 0) {
48 | viewAttributes.push(createAttributeJSON('resourceBundleAlias', 'xsd:string',
49 | 'Model name under which the resource bundle should be stored.'));
50 | }
51 | }
52 |
53 |
54 | function sapUiCoreControl(data) {
55 | log.debug('[enhance]', 'Improving sap.ui.core.Control');
56 |
57 | // add binding type:
58 | //
59 | //
60 | //
61 | //
62 | //
63 | data['xsd:schema']['xsd:simpleType'].push({
64 | $: {
65 | name: '_UI5ExpertsSimpleBindingType',
66 | },
67 | 'xsd:restriction': [{
68 | $: {
69 | base: 'xsd:string',
70 | },
71 | 'xsd:pattern': [{
72 | $: {
73 | value: '{.*}',
74 | },
75 | }],
76 | }],
77 | });
78 |
79 | const control = data['xsd:schema']['xsd:complexType']
80 | .find(element => element.$.name === '_ControlType');
81 | const controlAttributes = control['xsd:complexContent'][0]['xsd:extension'][0]['xsd:attribute'];
82 | if (controlAttributes.filter(attr => attr.$.name === 'class').length === 0) {
83 | controlAttributes.push(createAttributeJSON('class', 'xsd:string', 'A string that will be added '
84 | + 'to the "class" attribute of this control\'s root HTML element.'));
85 | }
86 | if (controlAttributes.filter(attr => attr.$.name === 'binding').length === 0) {
87 | controlAttributes.push(createAttributeJSON('binding', 'xsd:string', 'Bind the object to the '
88 | + 'referenced entity in the model, which is used as the binding context to resolve bound '
89 | + 'properties or aggregations of the object itself and all of its children relatively to the '
90 | + 'given path.'));
91 | }
92 | }
93 |
94 |
95 | module.exports = function upgrade(options, allLibs) {
96 | const allLibsRegistry = allLibs.all_libs;
97 | log.info('[enhance]', 'Making schemas even cooler...');
98 |
99 | const sapUiCore = allLibsRegistry.find(element => element.entry === 'sap/ui/core');
100 |
101 | fs.readFile(sapUiCore.location, 'utf-8')
102 | .then((data) => {
103 | parser.parseString(data, (err, result) => {
104 | if (err) {
105 | log.error('[enhance]', err);
106 | return;
107 | }
108 | sapUiCoreView(result);
109 | sapUiCoreControl(result);
110 |
111 | fs.outputFile(sapUiCore.location, builder.buildObject(result))
112 | .then(() => {
113 | log.info('[enhance]', 'Enhancing done!');
114 | })
115 | .catch(() => {
116 | });
117 | });
118 | })
119 | .catch((err) => {
120 | log.error('[enhance]', err);
121 | });
122 |
123 |
124 | // TODO: add aggregations as string properties (to allow for bindings)
125 | // TODO: add type string to any non-string property (to allow for bindings)
126 | // TODO: create a 'binding type'
127 | // TODO: add core:FragmentDefinition
128 | // TODO: add tooltip string property
129 | // TODO: Split up libs in separate sub-package schemas
130 | // https://regex101.com/r/9dtZZG/1
131 |
132 | //
133 | //
134 | //
135 | //
136 | //
137 |
138 | //
139 | // https://github.com/SAP/openui5/blob/e4416cb9e2bbc05ac76a64d79ea49b1fb5ca56a3/src/sap.ui.core/src/sap/ui/core/XMLTemplateProcessor.js
140 | // https://github.com/SAP/openui5/blob/e4416cb9e2bbc05ac76a64d79ea49b1fb5ca56a3/src/sap.ui.core/src/sap/ui/base/BindingParser.js
141 | // https://github.com/SAP/openui5/blob/e4416cb9e2bbc05ac76a64d79ea49b1fb5ca56a3/src/sap.ui.core/src/sap/ui/base/ExpressionParser.js
142 | };
143 |
--------------------------------------------------------------------------------