* add adapter-dev, remove gulp
* add more guidance on how to call * update deps
This commit is contained in:
@@ -12,5 +12,5 @@ updates:
|
||||
interval: monthly
|
||||
time: "04:00"
|
||||
timezone: Europe/Berlin
|
||||
open-pull-requests-limit: 20
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
@@ -16,6 +16,10 @@ on:
|
||||
- "v?[0-9]+.[0-9]+.[0-9]+-**"
|
||||
pull_request: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Performs quick checks before the expensive test runs
|
||||
check-and-lint:
|
||||
@@ -25,7 +29,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
node-version: [16.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -36,7 +40,7 @@ jobs:
|
||||
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
run: npm ci
|
||||
|
||||
# - name: Perform a type check
|
||||
# run: npm run check:ts
|
||||
@@ -67,7 +71,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
run: npm ci
|
||||
|
||||
- name: Run local tests
|
||||
run: npm test
|
||||
@@ -92,7 +96,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
node-version: [16.x]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -118,7 +122,7 @@ jobs:
|
||||
echo "::set-output name=BODY::$BODY"
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
run: npm ci
|
||||
|
||||
# - name: Create a clean build
|
||||
# run: npm run build
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
/**/*
|
||||
/gulpfile.js
|
||||
gulpfile.js
|
||||
!/admin/**/*
|
||||
!/admin/*
|
||||
!/lib/**/*
|
||||
|
||||
-337
@@ -1,337 +0,0 @@
|
||||
/*!
|
||||
* ioBroker gulpfile
|
||||
* Date: 2019-01-28
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const gulp = require('gulp');
|
||||
const fs = require('fs');
|
||||
const pkg = require('./package.json');
|
||||
const iopackage = require('./io-package.json');
|
||||
const version = (pkg && pkg.version) ? pkg.version : iopackage.common.version;
|
||||
const fileName = 'words.js';
|
||||
const EMPTY = '';
|
||||
const translate = require('./lib/tools').translateText;
|
||||
const languages = {
|
||||
en: {},
|
||||
de: {},
|
||||
ru: {},
|
||||
pt: {},
|
||||
nl: {},
|
||||
fr: {},
|
||||
it: {},
|
||||
es: {},
|
||||
pl: {},
|
||||
'zh-cn': {}
|
||||
};
|
||||
|
||||
function lang2data(lang) {
|
||||
let str ='{\n';
|
||||
let count = 0;
|
||||
for (const w in lang) {
|
||||
if (lang.hasOwnProperty(w)) {
|
||||
count++;
|
||||
const key = ' "' + w.replace(/"/g, '\\"') + '": ';
|
||||
str += key + '"' + lang[w].replace(/"/g, '\\"') + '",\n';
|
||||
}
|
||||
}
|
||||
if (!count) {
|
||||
return '{\n}';
|
||||
} else {
|
||||
return str.substring(0, str.length - 2) + '\n}';
|
||||
}
|
||||
}
|
||||
|
||||
function readWordJs(src) {
|
||||
try {
|
||||
let words;
|
||||
if (fs.existsSync(src + 'js/' + fileName)) {
|
||||
words = fs.readFileSync(src + 'js/' + fileName).toString();
|
||||
} else {
|
||||
words = fs.readFileSync(src + fileName).toString();
|
||||
}
|
||||
words = words.substring(words.indexOf('{'), words.length);
|
||||
words = words.substring(0, words.lastIndexOf(';'));
|
||||
|
||||
const resultFunc = new Function('return ' + words + ';');
|
||||
|
||||
return resultFunc();
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function padRight(text, totalLength) {
|
||||
return text + (text.length < totalLength ? new Array(totalLength - text.length).join(' ') : '');
|
||||
}
|
||||
|
||||
function writeWordJs(data, src) {
|
||||
let text = '';
|
||||
text += '/*global systemDictionary:true */\n';
|
||||
text += "'use strict';\n\n";
|
||||
text += 'systemDictionary = {\n';
|
||||
for (const word in data) {
|
||||
if (data.hasOwnProperty(word)) {
|
||||
text += ' ' + padRight('"' + word.replace(/"/g, '\\"') + '": {', 50);
|
||||
let line = '';
|
||||
for (const lang in data[word]) {
|
||||
if (data[word].hasOwnProperty(lang)) {
|
||||
line += '"' + lang + '": "' + padRight(data[word][lang].replace(/"/g, '\\"') + '",', 50) + ' ';
|
||||
}
|
||||
}
|
||||
if (line) {
|
||||
line = line.trim();
|
||||
line = line.substring(0, line.length - 1);
|
||||
}
|
||||
text += line + '},\n';
|
||||
}
|
||||
}
|
||||
text += '};';
|
||||
if (fs.existsSync(src + 'js/' + fileName)) {
|
||||
fs.writeFileSync(src + 'js/' + fileName, text);
|
||||
} else {
|
||||
fs.writeFileSync(src + '' + fileName, text);
|
||||
}
|
||||
}
|
||||
|
||||
function words2languages(src) {
|
||||
const langs = Object.assign({}, languages);
|
||||
const data = readWordJs(src);
|
||||
if (data) {
|
||||
for (const word in data) {
|
||||
if (data.hasOwnProperty(word)) {
|
||||
for (const lang in data[word]) {
|
||||
if (data[word].hasOwnProperty(lang)) {
|
||||
langs[lang][word] = data[word][lang];
|
||||
// pre-fill all other languages
|
||||
for (const j in langs) {
|
||||
if (langs.hasOwnProperty(j)) {
|
||||
langs[j][word] = langs[j][word] || EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!fs.existsSync(src + 'i18n/')) {
|
||||
fs.mkdirSync(src + 'i18n/');
|
||||
}
|
||||
for (const l in langs) {
|
||||
if (!langs.hasOwnProperty(l))
|
||||
continue;
|
||||
const keys = Object.keys(langs[l]);
|
||||
keys.sort();
|
||||
const obj = {};
|
||||
for (let k = 0; k < keys.length; k++) {
|
||||
obj[keys[k]] = langs[l][keys[k]];
|
||||
}
|
||||
if (!fs.existsSync(src + 'i18n/' + l)) {
|
||||
fs.mkdirSync(src + 'i18n/' + l);
|
||||
}
|
||||
|
||||
fs.writeFileSync(src + 'i18n/' + l + '/translations.json', lang2data(obj));
|
||||
}
|
||||
} else {
|
||||
console.error('Cannot read or parse ' + fileName);
|
||||
}
|
||||
}
|
||||
|
||||
function languages2words(src) {
|
||||
const dirs = fs.readdirSync(src + 'i18n/');
|
||||
const langs = {};
|
||||
const bigOne = {};
|
||||
const order = Object.keys(languages);
|
||||
dirs.sort(function (a, b) {
|
||||
const posA = order.indexOf(a);
|
||||
const posB = order.indexOf(b);
|
||||
if (posA === -1 && posB === -1) {
|
||||
if (a > b)
|
||||
return 1;
|
||||
if (a < b)
|
||||
return -1;
|
||||
return 0;
|
||||
} else if (posA === -1) {
|
||||
return -1;
|
||||
} else if (posB === -1) {
|
||||
return 1;
|
||||
} else {
|
||||
if (posA > posB)
|
||||
return 1;
|
||||
if (posA < posB)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
for (const lang of dirs) {
|
||||
if (lang === 'flat.txt')
|
||||
continue;
|
||||
langs[lang] = fs.readFileSync(src + 'i18n/' + lang + '/translations.json').toString();
|
||||
langs[lang] = JSON.parse(langs[lang]);
|
||||
const words = langs[lang];
|
||||
for (const word in words) {
|
||||
if (words.hasOwnProperty(word)) {
|
||||
bigOne[word] = bigOne[word] || {};
|
||||
if (words[word] !== EMPTY) {
|
||||
bigOne[word][lang] = words[word];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// read actual words.js
|
||||
const aWords = readWordJs();
|
||||
|
||||
const temporaryIgnore = ['flat.txt'];
|
||||
if (aWords) {
|
||||
// Merge words together
|
||||
for (const w in aWords) {
|
||||
if (aWords.hasOwnProperty(w)) {
|
||||
if (!bigOne[w]) {
|
||||
console.warn('Take from actual words.js: ' + w);
|
||||
bigOne[w] = aWords[w];
|
||||
}
|
||||
dirs.forEach(function (lang) {
|
||||
if (temporaryIgnore.indexOf(lang) !== -1)
|
||||
return;
|
||||
if (!bigOne[w][lang]) {
|
||||
console.warn('Missing "' + lang + '": ' + w);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
writeWordJs(bigOne, src);
|
||||
}
|
||||
|
||||
async function translateNotExisting(obj, baseText, yandex) {
|
||||
let t = obj['en'];
|
||||
if (!t) {
|
||||
t = baseText;
|
||||
}
|
||||
|
||||
if (t) {
|
||||
for (let l in languages) {
|
||||
if (!obj[l]) {
|
||||
const time = new Date().getTime();
|
||||
obj[l] = await translate(t, l, yandex);
|
||||
console.log('en -> ' + l + ' ' + (new Date().getTime() - time) + ' ms');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TASKS
|
||||
|
||||
gulp.task('adminWords2languages', function (done) {
|
||||
words2languages('./admin/');
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('adminLanguages2words', function (done) {
|
||||
languages2words('./admin/');
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('updatePackages', function (done) {
|
||||
iopackage.common.version = pkg.version;
|
||||
iopackage.common.news = iopackage.common.news || {};
|
||||
if (!iopackage.common.news[pkg.version]) {
|
||||
const news = iopackage.common.news;
|
||||
const newNews = {};
|
||||
|
||||
newNews[pkg.version] = {
|
||||
en: 'news',
|
||||
de: 'neues',
|
||||
ru: 'новое',
|
||||
pt: 'novidades',
|
||||
nl: 'nieuws',
|
||||
fr: 'nouvelles',
|
||||
it: 'notizie',
|
||||
es: 'noticias',
|
||||
pl: 'nowości',
|
||||
'zh-cn': '新'
|
||||
};
|
||||
iopackage.common.news = Object.assign(newNews, news);
|
||||
}
|
||||
fs.writeFileSync('io-package.json', JSON.stringify(iopackage, null, 4));
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('updateReadme', function (done) {
|
||||
const readme = fs.readFileSync('README.md').toString();
|
||||
const pos = readme.indexOf('## Changelog\n');
|
||||
if (pos !== -1) {
|
||||
const readmeStart = readme.substring(0, pos + '## Changelog\n'.length);
|
||||
const readmeEnd = readme.substring(pos + '## Changelog\n'.length);
|
||||
|
||||
if (readme.indexOf(version) === -1) {
|
||||
const timestamp = new Date();
|
||||
const date = timestamp.getFullYear() + '-' +
|
||||
('0' + (timestamp.getMonth() + 1).toString(10)).slice(-2) + '-' +
|
||||
('0' + (timestamp.getDate()).toString(10)).slice(-2);
|
||||
|
||||
let news = '';
|
||||
if (iopackage.common.news && iopackage.common.news[pkg.version]) {
|
||||
news += '* ' + iopackage.common.news[pkg.version].en;
|
||||
}
|
||||
|
||||
fs.writeFileSync('README.md', readmeStart + '### ' + version + ' (' + date + ')\n' + (news ? news + '\n\n' : '\n') + readmeEnd);
|
||||
}
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task('translate', async function (done) {
|
||||
|
||||
let yandex;
|
||||
const i = process.argv.indexOf('--yandex');
|
||||
if (i > -1) {
|
||||
yandex = process.argv[i + 1];
|
||||
}
|
||||
|
||||
if (iopackage && iopackage.common) {
|
||||
if (iopackage.common.news) {
|
||||
console.log('Translate News');
|
||||
for (let k in iopackage.common.news) {
|
||||
console.log('News: ' + k);
|
||||
let nw = iopackage.common.news[k];
|
||||
await translateNotExisting(nw, null, yandex);
|
||||
}
|
||||
}
|
||||
if (iopackage.common.titleLang) {
|
||||
console.log('Translate Title');
|
||||
await translateNotExisting(iopackage.common.titleLang, iopackage.common.title, yandex);
|
||||
}
|
||||
if (iopackage.common.desc) {
|
||||
console.log('Translate Description');
|
||||
await translateNotExisting(iopackage.common.desc, null, yandex);
|
||||
}
|
||||
|
||||
if (fs.existsSync('./admin/i18n/en/translations.json')) {
|
||||
let enTranslations = require('./admin/i18n/en/translations.json');
|
||||
for (let l in languages) {
|
||||
console.log('Translate Text: ' + l);
|
||||
let existing = {};
|
||||
if (fs.existsSync('./admin/i18n/' + l + '/translations.json')) {
|
||||
existing = require('./admin/i18n/' + l + '/translations.json');
|
||||
}
|
||||
for (let t in enTranslations) {
|
||||
if (!existing[t]) {
|
||||
existing[t] = await translate(enTranslations[t], l, yandex);
|
||||
}
|
||||
}
|
||||
if (!fs.existsSync('./admin/i18n/' + l + '/')) {
|
||||
fs.mkdirSync('./admin/i18n/' + l + '/');
|
||||
}
|
||||
fs.writeFileSync('./admin/i18n/' + l + '/translations.json', JSON.stringify(existing, null, 4));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
fs.writeFileSync('io-package.json', JSON.stringify(iopackage, null, 4));
|
||||
});
|
||||
|
||||
gulp.task('translateAndUpdateWordsJS', gulp.series('translate', 'adminLanguages2words', 'adminWords2languages'));
|
||||
|
||||
gulp.task('default', gulp.series('updatePackages', 'updateReadme'));
|
||||
@@ -1,92 +0,0 @@
|
||||
const axios = require("axios");
|
||||
|
||||
/**
|
||||
* Tests whether the given variable is a real object and not an Array
|
||||
* @param {any} it The variable to test
|
||||
* @returns {it is Record<string, any>}
|
||||
*/
|
||||
function isObject(it) {
|
||||
// This is necessary because:
|
||||
// typeof null === 'object'
|
||||
// typeof [] === 'object'
|
||||
// [] instanceof Object === true
|
||||
return Object.prototype.toString.call(it) === "[object Object]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the given variable is really an Array
|
||||
* @param {any} it The variable to test
|
||||
* @returns {it is any[]}
|
||||
*/
|
||||
function isArray(it) {
|
||||
if (Array.isArray != null)
|
||||
return Array.isArray(it);
|
||||
return Object.prototype.toString.call(it) === "[object Array]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose the right tranalation API
|
||||
* @param {string} text The text to translate
|
||||
* @param {string} targetLang The target languate
|
||||
* @param {string} yandex api key
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async function translateText(text, targetLang, yandex) {
|
||||
if (targetLang === "en") {
|
||||
return text;
|
||||
}
|
||||
if (yandex) {
|
||||
return await translateYandex(text, targetLang, yandex);
|
||||
} else {
|
||||
return await translateGoogle(text, targetLang);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates text with Yandex API
|
||||
* @param {string} text The text to translate
|
||||
* @param {string} targetLang The target languate
|
||||
* @param {string} yandex api key
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async function translateYandex(text, targetLang, yandex) {
|
||||
if (targetLang === "zh-cn") {
|
||||
targetLang = "zh";
|
||||
}
|
||||
try {
|
||||
const url = `https://translate.yandex.net/api/v1.5/tr.json/translate?key=${yandex}&text=${encodeURIComponent(text)}&lang=en-${targetLang}`;
|
||||
const response = await axios({url, timeout: 15000});
|
||||
if (response.data && response.data['text']) {
|
||||
return response.data['text'][0];
|
||||
}
|
||||
throw new Error("Invalid response for translate request");
|
||||
} catch (e) {
|
||||
throw new Error(`Could not translate to "${targetLang}": ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates text with Google API
|
||||
* @param {string} text The text to translate
|
||||
* @param {string} targetLang The target languate
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async function translateGoogle(text, targetLang) {
|
||||
try {
|
||||
const url = `http://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}&ie=UTF-8&oe=UTF-8`;
|
||||
const response = await axios({url, timeout: 15000});
|
||||
if (isArray(response.data)) {
|
||||
// we got a valid response
|
||||
return response.data[0][0][0];
|
||||
}
|
||||
throw new Error("Invalid response for translate request");
|
||||
} catch (e) {
|
||||
throw new Error(`Could not translate to "${targetLang}": ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isArray,
|
||||
isObject,
|
||||
translateText
|
||||
};
|
||||
@@ -59,7 +59,7 @@ function startAdapter(options) {
|
||||
}
|
||||
}
|
||||
|
||||
adapter.log.debug('Prepare service call for ' + id + ' with (mapped) request parameters ' + JSON.stringify(requestFields));
|
||||
adapter.log.debug('Prepare service call for ' + id + ' with (mapped) request parameters ' + JSON.stringify(requestFields) + ' from value: ' + JSON.stringify(state.val));
|
||||
for (const field in fields) {
|
||||
if (!fields.hasOwnProperty(field)) {
|
||||
continue;
|
||||
@@ -71,11 +71,16 @@ function startAdapter(options) {
|
||||
serviceData[field] = requestFields[field];
|
||||
}
|
||||
}
|
||||
const noFields = Object.keys(serviceData).length === 0;
|
||||
serviceData.entity_id = hassObjects[id].native.entity_id
|
||||
|
||||
adapter.log.debug(`Send to HASS for service ${hassObjects[id].native.attr} with ${hassObjects[id].native.domain || hassObjects[id].native.type} and data ${JSON.stringify(serviceData)}`)
|
||||
hass.callService(hassObjects[id].native.attr, hassObjects[id].native.domain || hassObjects[id].native.type, serviceData, target, err =>
|
||||
err && adapter.log.error('Cannot control ' + id + ': ' + err));
|
||||
hass.callService(hassObjects[id].native.attr, hassObjects[id].native.domain || hassObjects[id].native.type, serviceData, target, err => {
|
||||
err && adapter.log.error('Cannot control ' + id + ': ' + err);
|
||||
if (err && noFields) {
|
||||
adapter.log.warn(`Please make sure to provide a stringified JSON as value to set relevant fields! Please refer to the Readme for details!`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+6381
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -26,15 +26,14 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"websocket": "^1.0.34",
|
||||
"ws": "^8.10.0",
|
||||
"ws": "^8.11.0",
|
||||
"@iobroker/adapter-core": "^2.6.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alcalzone/release-script": "^3.5.9",
|
||||
"@alcalzone/release-script-plugin-iobroker": "^3.5.9",
|
||||
"@alcalzone/release-script-plugin-license": "^3.5.9",
|
||||
"axios": "^1.2.0",
|
||||
"gulp": "^4.0.2",
|
||||
"@iobroker/adapter-dev": "^1.2.0",
|
||||
"mocha": "^10.1.0",
|
||||
"chai": "^4.3.7"
|
||||
},
|
||||
@@ -44,7 +43,8 @@
|
||||
"release": "release-script",
|
||||
"release-patch": "release-script patch --yes",
|
||||
"release-minor": "release-script minor --yes",
|
||||
"release-major": "release-script major --yes"
|
||||
"release-major": "release-script major --yes",
|
||||
"translate": "translate-adapter"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/ioBroker/ioBroker.hass/issues"
|
||||
|
||||
Reference in New Issue
Block a user