mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat: #7743 plugins/data
This commit is contained in:
14
src/file.js
14
src/file.js
@@ -218,41 +218,41 @@ file.typeToExtension = function (type) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Adapted from http://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search
|
// Adapted from http://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search
|
||||||
file.walk = function (dir, done) {
|
file.walk = function (dir, callback) {
|
||||||
var results = [];
|
var results = [];
|
||||||
|
|
||||||
fs.readdir(dir, function (err, list) {
|
fs.readdir(dir, function (err, list) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
var pending = list.length;
|
var pending = list.length;
|
||||||
if (!pending) {
|
if (!pending) {
|
||||||
return done(null, results);
|
return callback(null, results);
|
||||||
}
|
}
|
||||||
list.forEach(function (filename) {
|
list.forEach(function (filename) {
|
||||||
filename = dir + '/' + filename;
|
filename = dir + '/' + filename;
|
||||||
fs.stat(filename, function (err, stat) {
|
fs.stat(filename, function (err, stat) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stat && stat.isDirectory()) {
|
if (stat && stat.isDirectory()) {
|
||||||
file.walk(filename, function (err, res) {
|
file.walk(filename, function (err, res) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
results = results.concat(res);
|
results = results.concat(res);
|
||||||
pending -= 1;
|
pending -= 1;
|
||||||
if (!pending) {
|
if (!pending) {
|
||||||
done(null, results);
|
callback(null, results);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
results.push(filename);
|
results.push(filename);
|
||||||
pending -= 1;
|
pending -= 1;
|
||||||
if (!pending) {
|
if (!pending) {
|
||||||
done(null, results);
|
callback(null, results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,231 +1,193 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var fs = require('fs');
|
const fs = require('fs');
|
||||||
var path = require('path');
|
const util = require('util');
|
||||||
var async = require('async');
|
const path = require('path');
|
||||||
var winston = require('winston');
|
const winston = require('winston');
|
||||||
|
|
||||||
var db = require('../database');
|
const db = require('../database');
|
||||||
var file = require('../file');
|
const file = require('../file');
|
||||||
|
|
||||||
var Data = module.exports;
|
const Data = module.exports;
|
||||||
|
|
||||||
var basePath = path.join(__dirname, '../../');
|
const basePath = path.join(__dirname, '../../');
|
||||||
|
|
||||||
function getPluginPaths(callback) {
|
const readFileAsync = util.promisify(fs.readFile);
|
||||||
async.waterfall([
|
const statAsync = util.promisify(fs.stat);
|
||||||
function (next) {
|
|
||||||
db.getSortedSetRange('plugins:active', 0, -1, next);
|
|
||||||
},
|
|
||||||
function (plugins, next) {
|
|
||||||
plugins = plugins.filter(function (plugin) {
|
|
||||||
return plugin && typeof plugin === 'string';
|
|
||||||
}).map(function (plugin) {
|
|
||||||
return path.join(__dirname, '../../node_modules/', plugin);
|
|
||||||
});
|
|
||||||
|
|
||||||
async.filter(plugins, file.exists, next);
|
Data.getPluginPaths = async function () {
|
||||||
},
|
let plugins = await db.getSortedSetRange('plugins:active', 0, -1);
|
||||||
], callback);
|
plugins = plugins.filter(plugin => plugin && typeof plugin === 'string')
|
||||||
|
.map(plugin => path.join(__dirname, '../../node_modules/', plugin));
|
||||||
|
|
||||||
|
const exists = await Promise.all(plugins.map(p => file.exists(p)));
|
||||||
|
return plugins.filter((p, i) => exists[i]);
|
||||||
|
};
|
||||||
|
|
||||||
|
Data.loadPluginInfo = async function (pluginPath) {
|
||||||
|
const [packageJson, pluginJson] = await Promise.all([
|
||||||
|
readFileAsync(path.join(pluginPath, 'package.json'), 'utf8'),
|
||||||
|
readFileAsync(path.join(pluginPath, 'plugin.json'), 'utf8'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let pluginData;
|
||||||
|
let packageData;
|
||||||
|
try {
|
||||||
|
pluginData = JSON.parse(pluginJson);
|
||||||
|
packageData = JSON.parse(packageJson);
|
||||||
|
|
||||||
|
pluginData.license = parseLicense(packageData);
|
||||||
|
|
||||||
|
pluginData.id = packageData.name;
|
||||||
|
pluginData.name = packageData.name;
|
||||||
|
pluginData.description = packageData.description;
|
||||||
|
pluginData.version = packageData.version;
|
||||||
|
pluginData.repository = packageData.repository;
|
||||||
|
pluginData.nbbpm = packageData.nbbpm;
|
||||||
|
pluginData.path = pluginPath;
|
||||||
|
} catch (err) {
|
||||||
|
var pluginDir = path.basename(pluginPath);
|
||||||
|
|
||||||
|
winston.error('[plugins/' + pluginDir + '] Error in plugin.json or package.json!', err);
|
||||||
|
throw new Error('[[error:parse-error]]');
|
||||||
|
}
|
||||||
|
return pluginData;
|
||||||
|
};
|
||||||
|
|
||||||
|
function parseLicense(packageData) {
|
||||||
|
try {
|
||||||
|
const licenseData = require('spdx-license-list/licenses/' + packageData.license);
|
||||||
|
return {
|
||||||
|
name: licenseData.name,
|
||||||
|
text: licenseData.licenseText,
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
// No license matched
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Data.getPluginPaths = getPluginPaths;
|
|
||||||
|
|
||||||
function loadPluginInfo(pluginPath, callback) {
|
Data.getActive = async function () {
|
||||||
async.parallel({
|
const pluginPaths = await Data.getPluginPaths();
|
||||||
package: function (next) {
|
return await Promise.all(pluginPaths.map(p => Data.loadPluginInfo(p)));
|
||||||
fs.readFile(path.join(pluginPath, 'package.json'), 'utf8', next);
|
};
|
||||||
},
|
|
||||||
plugin: function (next) {
|
|
||||||
fs.readFile(path.join(pluginPath, 'plugin.json'), 'utf8', next);
|
|
||||||
},
|
|
||||||
}, function (err, results) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
var pluginData;
|
|
||||||
var packageData;
|
|
||||||
var licenseData;
|
|
||||||
try {
|
|
||||||
pluginData = JSON.parse(results.plugin);
|
|
||||||
packageData = JSON.parse(results.package);
|
|
||||||
try {
|
|
||||||
licenseData = require('spdx-license-list/licenses/' + packageData.license);
|
|
||||||
pluginData.license = {
|
|
||||||
name: licenseData.name,
|
|
||||||
text: licenseData.licenseText,
|
|
||||||
};
|
|
||||||
} catch (e) {
|
|
||||||
// No license matched
|
|
||||||
pluginData.license = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
pluginData.id = packageData.name;
|
|
||||||
pluginData.name = packageData.name;
|
|
||||||
pluginData.description = packageData.description;
|
|
||||||
pluginData.version = packageData.version;
|
|
||||||
pluginData.repository = packageData.repository;
|
|
||||||
pluginData.nbbpm = packageData.nbbpm;
|
|
||||||
pluginData.path = pluginPath;
|
|
||||||
} catch (err) {
|
|
||||||
var pluginDir = path.basename(pluginPath);
|
|
||||||
|
|
||||||
winston.error('[plugins/' + pluginDir + '] Error in plugin.json or package.json!', err);
|
Data.getStaticDirectories = async function (pluginData) {
|
||||||
return callback(new Error('[[error:parse-error]]'));
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(null, pluginData);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Data.loadPluginInfo = loadPluginInfo;
|
|
||||||
|
|
||||||
function getAllPluginData(callback) {
|
|
||||||
async.waterfall([
|
|
||||||
function (next) {
|
|
||||||
getPluginPaths(next);
|
|
||||||
},
|
|
||||||
function (pluginPaths, next) {
|
|
||||||
async.map(pluginPaths, loadPluginInfo, next);
|
|
||||||
},
|
|
||||||
], callback);
|
|
||||||
}
|
|
||||||
Data.getActive = getAllPluginData;
|
|
||||||
|
|
||||||
function getStaticDirectories(pluginData, callback) {
|
|
||||||
var validMappedPath = /^[\w\-_]+$/;
|
var validMappedPath = /^[\w\-_]+$/;
|
||||||
|
|
||||||
if (!pluginData.staticDirs) {
|
if (!pluginData.staticDirs) {
|
||||||
return callback();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var dirs = Object.keys(pluginData.staticDirs);
|
const dirs = Object.keys(pluginData.staticDirs);
|
||||||
if (!dirs.length) {
|
if (!dirs.length) {
|
||||||
return callback();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var staticDirs = {};
|
const staticDirs = {};
|
||||||
|
|
||||||
async.each(dirs, function (route, next) {
|
async function processDir(route) {
|
||||||
if (!validMappedPath.test(route)) {
|
if (!validMappedPath.test(route)) {
|
||||||
winston.warn('[plugins/' + pluginData.id + '] Invalid mapped path specified: ' +
|
winston.warn('[plugins/' + pluginData.id + '] Invalid mapped path specified: ' +
|
||||||
route + '. Path must adhere to: ' + validMappedPath.toString());
|
route + '. Path must adhere to: ' + validMappedPath.toString());
|
||||||
return next();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var dirPath = path.join(pluginData.path, pluginData.staticDirs[route]);
|
const dirPath = path.join(pluginData.path, pluginData.staticDirs[route]);
|
||||||
fs.stat(dirPath, function (err, stats) {
|
try {
|
||||||
if (err && err.code === 'ENOENT') {
|
const stats = await statAsync(dirPath);
|
||||||
winston.warn('[plugins/' + pluginData.id + '] Mapped path \'' +
|
|
||||||
route + ' => ' + dirPath + '\' not found.');
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
if (err) {
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stats.isDirectory()) {
|
if (!stats.isDirectory()) {
|
||||||
winston.warn('[plugins/' + pluginData.id + '] Mapped path \'' +
|
winston.warn('[plugins/' + pluginData.id + '] Mapped path \'' +
|
||||||
route + ' => ' + dirPath + '\' is not a directory.');
|
route + ' => ' + dirPath + '\' is not a directory.');
|
||||||
return next();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
staticDirs[pluginData.id + '/' + route] = dirPath;
|
staticDirs[pluginData.id + '/' + route] = dirPath;
|
||||||
next();
|
} catch (err) {
|
||||||
});
|
if (err.code === 'ENOENT') {
|
||||||
}, function (err) {
|
winston.warn('[plugins/' + pluginData.id + '] Mapped path \'' +
|
||||||
if (err) {
|
route + ' => ' + dirPath + '\' not found.');
|
||||||
return callback(err);
|
return;
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
winston.verbose('[plugins] found ' + Object.keys(staticDirs).length +
|
}
|
||||||
' static directories for ' + pluginData.id);
|
|
||||||
callback(null, staticDirs);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Data.getStaticDirectories = getStaticDirectories;
|
|
||||||
|
|
||||||
function getFiles(pluginData, type, callback) {
|
await Promise.all(dirs.map(route => processDir(route)));
|
||||||
|
winston.verbose('[plugins] found ' + Object.keys(staticDirs).length +
|
||||||
|
' static directories for ' + pluginData.id);
|
||||||
|
return staticDirs;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Data.getFiles = async function (pluginData, type) {
|
||||||
if (!Array.isArray(pluginData[type]) || !pluginData[type].length) {
|
if (!Array.isArray(pluginData[type]) || !pluginData[type].length) {
|
||||||
return callback();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
winston.verbose('[plugins] Found ' + pluginData[type].length + ' ' + type + ' file(s) for plugin ' + pluginData.id);
|
winston.verbose('[plugins] Found ' + pluginData[type].length + ' ' + type + ' file(s) for plugin ' + pluginData.id);
|
||||||
|
|
||||||
var files = pluginData[type].map(function (file) {
|
return pluginData[type].map(file => path.join(pluginData.id, file));
|
||||||
return path.join(pluginData.id, file);
|
};
|
||||||
});
|
|
||||||
|
|
||||||
callback(null, files);
|
|
||||||
}
|
|
||||||
Data.getFiles = getFiles;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* With npm@3, dependencies can become flattened, and appear at the root level.
|
* With npm@3, dependencies can become flattened, and appear at the root level.
|
||||||
* This method resolves these differences if it can.
|
* This method resolves these differences if it can.
|
||||||
*/
|
*/
|
||||||
function resolveModulePath(basePath, modulePath, callback) {
|
async function resolveModulePath(basePath, modulePath) {
|
||||||
var isNodeModule = /node_modules/;
|
const isNodeModule = /node_modules/;
|
||||||
|
|
||||||
var currentPath = path.join(basePath, modulePath);
|
const currentPath = path.join(basePath, modulePath);
|
||||||
file.exists(currentPath, function (err, exists) {
|
const exists = await file.exists(currentPath);
|
||||||
if (err) {
|
if (exists) {
|
||||||
return callback(err);
|
return currentPath;
|
||||||
}
|
}
|
||||||
if (exists) {
|
if (!isNodeModule.test(modulePath)) {
|
||||||
return callback(null, currentPath);
|
winston.warn('[plugins] File not found: ' + currentPath + ' (Ignoring)');
|
||||||
}
|
return;
|
||||||
if (!isNodeModule.test(modulePath)) {
|
}
|
||||||
winston.warn('[plugins] File not found: ' + currentPath + ' (Ignoring)');
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
var dirPath = path.dirname(basePath);
|
const dirPath = path.dirname(basePath);
|
||||||
if (dirPath === basePath) {
|
if (dirPath === basePath) {
|
||||||
winston.warn('[plugins] File not found: ' + currentPath + ' (Ignoring)');
|
winston.warn('[plugins] File not found: ' + currentPath + ' (Ignoring)');
|
||||||
return callback();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveModulePath(dirPath, modulePath, callback);
|
return await resolveModulePath(dirPath, modulePath);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getScripts(pluginData, target, callback) {
|
|
||||||
|
Data.getScripts = async function getScripts(pluginData, target) {
|
||||||
target = (target === 'client') ? 'scripts' : 'acpScripts';
|
target = (target === 'client') ? 'scripts' : 'acpScripts';
|
||||||
|
|
||||||
var input = pluginData[target];
|
const input = pluginData[target];
|
||||||
if (!Array.isArray(input) || !input.length) {
|
if (!Array.isArray(input) || !input.length) {
|
||||||
return callback();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var scripts = [];
|
const scripts = [];
|
||||||
async.eachSeries(input, function (filePath, next) {
|
|
||||||
resolveModulePath(pluginData.path, filePath, function (err, modulePath) {
|
|
||||||
if (err) {
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (modulePath) {
|
for (const filePath of input) {
|
||||||
scripts.push(modulePath);
|
/* eslint-disable no-await-in-loop */
|
||||||
}
|
const modulePath = await resolveModulePath(pluginData.path, filePath);
|
||||||
next();
|
if (modulePath) {
|
||||||
});
|
scripts.push(modulePath);
|
||||||
}, function (err) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (scripts.length) {
|
||||||
|
winston.verbose('[plugins] Found ' + scripts.length + ' js file(s) for plugin ' + pluginData.id);
|
||||||
|
}
|
||||||
|
return scripts;
|
||||||
|
};
|
||||||
|
|
||||||
if (scripts.length) {
|
|
||||||
winston.verbose('[plugins] Found ' + scripts.length + ' js file(s) for plugin ' + pluginData.id);
|
|
||||||
}
|
|
||||||
callback(err, scripts);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Data.getScripts = getScripts;
|
|
||||||
|
|
||||||
function getModules(pluginData, callback) {
|
Data.getModules = async function getModules(pluginData) {
|
||||||
if (!pluginData.modules || !pluginData.hasOwnProperty('modules')) {
|
if (!pluginData.modules || !pluginData.hasOwnProperty('modules')) {
|
||||||
return callback();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pluginModules = pluginData.modules;
|
let pluginModules = pluginData.modules;
|
||||||
|
|
||||||
if (Array.isArray(pluginModules)) {
|
if (Array.isArray(pluginModules)) {
|
||||||
var strip = parseInt(pluginData.modulesStrip, 10) || 0;
|
var strip = parseInt(pluginData.modulesStrip, 10) || 0;
|
||||||
@@ -243,35 +205,25 @@ function getModules(pluginData, callback) {
|
|||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
var modules = {};
|
const modules = {};
|
||||||
async.each(Object.keys(pluginModules), function (key, next) {
|
async function processModule(key) {
|
||||||
resolveModulePath(pluginData.path, pluginModules[key], function (err, modulePath) {
|
const modulePath = await resolveModulePath(pluginData.path, pluginModules[key]);
|
||||||
if (err) {
|
if (modulePath) {
|
||||||
return next(err);
|
modules[key] = path.relative(basePath, modulePath);
|
||||||
}
|
|
||||||
|
|
||||||
if (modulePath) {
|
|
||||||
modules[key] = path.relative(basePath, modulePath);
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
}, function (err) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var len = Object.keys(modules).length;
|
await Promise.all(Object.keys(pluginModules).map(key => processModule(key)));
|
||||||
winston.verbose('[plugins] Found ' + len + ' AMD-style module(s) for plugin ' + pluginData.id);
|
|
||||||
|
|
||||||
callback(null, modules);
|
const len = Object.keys(modules).length;
|
||||||
});
|
winston.info('[plugins] Found ' + len + ' AMD-style module(s) for plugin ' + pluginData.id);
|
||||||
}
|
return modules;
|
||||||
Data.getModules = getModules;
|
};
|
||||||
|
|
||||||
function getSoundpack(pluginData, callback) {
|
Data.getSoundpack = async function getSoundpack(pluginData) {
|
||||||
var spack = pluginData.soundpack;
|
var spack = pluginData.soundpack;
|
||||||
if (!spack || !spack.dir || !spack.sounds) {
|
if (!spack || !spack.dir || !spack.sounds) {
|
||||||
return callback();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var soundpack = {};
|
var soundpack = {};
|
||||||
@@ -280,64 +232,49 @@ function getSoundpack(pluginData, callback) {
|
|||||||
soundpack.dir = path.join(pluginData.path, spack.dir);
|
soundpack.dir = path.join(pluginData.path, spack.dir);
|
||||||
soundpack.sounds = {};
|
soundpack.sounds = {};
|
||||||
|
|
||||||
async.each(Object.keys(spack.sounds), function (name, next) {
|
async function processSoundPack(name) {
|
||||||
var soundFile = spack.sounds[name];
|
const soundFile = spack.sounds[name];
|
||||||
file.exists(path.join(soundpack.dir, soundFile), function (err, exists) {
|
const exists = await file.exists(path.join(soundpack.dir, soundFile));
|
||||||
if (err) {
|
if (!exists) {
|
||||||
return next(err);
|
winston.warn('[plugins] Sound file not found: ' + soundFile);
|
||||||
}
|
return;
|
||||||
if (!exists) {
|
|
||||||
winston.warn('[plugins] Sound file not found: ' + soundFile);
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
soundpack.sounds[name] = soundFile;
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
}, function (err) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
}
|
||||||
|
soundpack.sounds[name] = soundFile;
|
||||||
var len = Object.keys(soundpack.sounds).length;
|
|
||||||
winston.verbose('[plugins] Found ' + len + ' sound file(s) for plugin ' + pluginData.id);
|
|
||||||
|
|
||||||
callback(null, soundpack);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Data.getSoundpack = getSoundpack;
|
|
||||||
|
|
||||||
function getLanguageData(pluginData, callback) {
|
|
||||||
if (typeof pluginData.languages !== 'string') {
|
|
||||||
return callback();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var pathToFolder = path.join(__dirname, '../../node_modules/', pluginData.id, pluginData.languages);
|
await Promise.all(Object.keys(spack.sounds).map(key => processSoundPack(key)));
|
||||||
file.walk(pathToFolder, function (err, paths) {
|
|
||||||
if (err) {
|
const len = Object.keys(soundpack.sounds).length;
|
||||||
return callback(err);
|
winston.verbose('[plugins] Found ' + len + ' sound file(s) for plugin ' + pluginData.id);
|
||||||
|
return soundpack;
|
||||||
|
};
|
||||||
|
|
||||||
|
Data.getLanguageData = async function getLanguageData(pluginData) {
|
||||||
|
if (typeof pluginData.languages !== 'string') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pathToFolder = path.join(__dirname, '../../node_modules/', pluginData.id, pluginData.languages);
|
||||||
|
const paths = await file.walk(pathToFolder);
|
||||||
|
|
||||||
|
const namespaces = [];
|
||||||
|
const languages = [];
|
||||||
|
|
||||||
|
paths.forEach(function (p) {
|
||||||
|
const rel = path.relative(pathToFolder, p).split(/[/\\]/);
|
||||||
|
const language = rel.shift().replace('_', '-').replace('@', '-x-');
|
||||||
|
const namespace = rel.join('/').replace(/\.json$/, '');
|
||||||
|
|
||||||
|
if (!language || !namespace) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var namespaces = [];
|
languages.push(language);
|
||||||
var languages = [];
|
namespaces.push(namespace);
|
||||||
|
|
||||||
paths.forEach(function (p) {
|
|
||||||
var rel = path.relative(pathToFolder, p).split(/[/\\]/);
|
|
||||||
var language = rel.shift().replace('_', '-').replace('@', '-x-');
|
|
||||||
var namespace = rel.join('/').replace(/\.json$/, '');
|
|
||||||
|
|
||||||
if (!language || !namespace) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
languages.push(language);
|
|
||||||
namespaces.push(namespace);
|
|
||||||
});
|
|
||||||
|
|
||||||
callback(null, {
|
|
||||||
languages: languages,
|
|
||||||
namespaces: namespaces,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
Data.getLanguageData = getLanguageData;
|
return {
|
||||||
|
languages: languages,
|
||||||
|
namespaces: namespaces,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user