lincd-cli
Version:
Command line tools for the lincd.js library
1,073 lines (1,071 loc) • 98.8 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.removeOldFiles = exports.executeCommandForPackage = exports.addCapacitor = exports.addLinesToFile = exports.executeCommandForEachPackage = exports.buildUpdated = exports.publishPackage = exports.publishUpdated = exports.compilePackageCJS = exports.compilePackageESM = exports.compilePackage = exports.buildPackage = exports.register = exports.createPackage = exports.upgradePackages = exports.buildApp = exports.startServer = exports.ensureEnvironmentLoaded = exports.depCheck = exports.depCheckStaged = exports.checkImports = exports.createComponent = exports.createSetComponent = exports.createShape = exports.getScriptDir = exports.setNameVariables = exports.createOntology = exports.createApp = void 0;
exports.warn = warn;
exports.developPackage = developPackage;
exports.buildAll = buildAll;
exports.getLincdPackages = getLincdPackages;
const chalk_1 = __importDefault(require("chalk"));
const child_process_1 = require("child_process");
const depcheck_1 = __importDefault(require("depcheck"));
const get_env_vars_js_1 = require("env-cmd/dist/get-env-vars.js");
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importStar(require("path"));
const utils_js_1 = require("./utils.js");
const fs_1 = require("fs");
const find_nearest_package_json_1 = require("find-nearest-package-json");
const LinkedFileStorage_1 = require("lincd/utils/LinkedFileStorage");
// import pkg from 'lincd/utils/LinkedFileStorage';
// const { LinkedFileStorage } = pkg;
// const config = require('lincd-server/site.webpack.config');
const glob_1 = require("glob");
const webpack_1 = __importDefault(require("webpack"));
const staged_git_files_1 = __importDefault(require("staged-git-files"));
const ora_1 = __importDefault(require("ora"));
//@ts-ignore
let dirname__ = typeof __dirname !== 'undefined' ? __dirname : (0, path_1.dirname)(import.meta.url).replace('file:/', '');
var variables = {};
const createApp = async (name, basePath = process.cwd()) => {
if (!name) {
console.warn('Please provide a name as the first argument');
}
let { hyphenName, camelCaseName, underscoreName } = (0, exports.setNameVariables)(name);
let targetFolder = path_1.default.join(basePath, hyphenName);
if (!fs_extra_1.default.existsSync(targetFolder)) {
fs_extra_1.default.mkdirSync(targetFolder);
}
fs_extra_1.default.copySync(path_1.default.join(dirname__, '..', '..', 'defaults', 'app-with-backend'), targetFolder);
//make sure the data folder exists (even though its empty).. copying empty folders does not work with fs.copySync
fs_extra_1.default.mkdirSync(path_1.default.join(targetFolder, 'data'), { recursive: true });
fs_extra_1.default.mkdirSync(path_1.default.join(targetFolder, 'data/uploads/resized'), {
recursive: true,
});
fs_extra_1.default.renameSync(path_1.default.join(targetFolder, 'gitignore.template'), path_1.default.join(targetFolder, '.gitignore'));
fs_extra_1.default.renameSync(path_1.default.join(targetFolder, 'yarnrc.yml.template'), path_1.default.join(targetFolder, '.yarnrc.yml'));
// fs.copySync(path.join(__dirname, '..', 'defaults', 'app'), targetFolder);
log('Creating new LINCD application \'' + name + '\'');
//replace variables in some copied files
await replaceVariablesInFolder(targetFolder);
let hasYarn = await hasYarnInstalled();
let installCommand = hasYarn
? 'export NODE_OPTIONS="--no-network-family-autoselection" && yarn install'
: 'npm install';
await (0, utils_js_1.execp)(`cd ${hyphenName} && ${installCommand}`, true).catch((err) => {
console.warn('Could not install dependencies or start application');
});
log(`Your LINCD App is ready at ${chalk_1.default.blueBright(targetFolder)}`, `To start, run\n${chalk_1.default.blueBright(`cd ${hyphenName}`)} and then ${chalk_1.default.blueBright((hasYarn ? 'yarn' : 'npm') + ' start')}`);
};
exports.createApp = createApp;
function logHelp() {
(0, utils_js_1.execp)('yarn exec lincd help');
}
function log(...messages) {
messages.forEach((message) => {
console.log(chalk_1.default.cyan('Info: ') + message);
});
}
function progressUpdate(message) {
process.stdout.write(' \r');
process.stdout.write(message + '\r');
}
function warn(...messages) {
messages.forEach((message) => {
console.log(chalk_1.default.redBright('Warning: ') + message);
// console.log(chalk.red(message));
});
}
function developPackage(target, mode) {
if (!target)
target = 'es6';
if (mode !== 'production')
mode = '';
else if (target !== 'es6')
log('target must be es6 when developing for production');
if (target == 'es5' || target == 'es6') {
// log('> Starting continuous development build for '+target+' target')
log('starting continuous development build');
log('grunt dev' +
(target ? '-' + target : '') +
(mode ? '-' + mode : '') +
' --color');
var command = (0, child_process_1.exec)('grunt dev' +
(target ? '-' + target : '') +
(mode ? '-' + mode : '') +
' --color');
command.stdout.pipe(process.stdout);
command.stderr.pipe(process.stderr);
}
else {
console.warn('unknown build target. Use es5 or es6');
}
}
function checkWorkspaces(rootPath, workspaces, res) {
// console.log('checking workspaces at '+rootPath+": "+workspaces.toString());
if (workspaces.packages) {
workspaces = workspaces.packages;
}
workspaces.forEach((workspace) => {
let workspacePath = path_1.default.join(rootPath, workspace.replace('/*', ''));
if (workspace.indexOf('/*') !== -1) {
// console.log(workspacePath);
if (fs_extra_1.default.existsSync(workspacePath)) {
let folders = fs_extra_1.default.readdirSync(workspacePath);
folders.forEach((folder) => {
if (folder !== './' && folder !== '../') {
checkPackagePath(rootPath, path_1.default.join(workspacePath, folder), res);
}
});
}
}
else {
checkPackagePath(rootPath, workspacePath, res);
}
});
}
function checkPackagePath(rootPath, packagePath, res) {
let packageJsonPath = path_1.default.join(packagePath, 'package.json');
// console.log('checking '+packagePath);
if (fs_extra_1.default.existsSync(packageJsonPath)) {
var pack = JSON.parse(fs_extra_1.default.readFileSync(packageJsonPath, 'utf8'));
//some packages are not true lincd packages, but we still want them to be re-built automatically. This is what lincd_util is for
if (pack && pack.workspaces) {
checkWorkspaces(packagePath, pack.workspaces, res);
}
else if (pack && pack.lincd === true) {
res.push({
path: packagePath,
packageName: pack.name,
});
}
}
}
function runOnPackagesGroupedByDependencies(lincdPackages, onBuildStack, onStackEnd, sync = false) {
let dependencies = new Map();
//get dependencies of each package
let leastDependentPackage;
lincdPackages.forEach((pkg) => {
var pack = (0, utils_js_1.getPackageJSON)(pkg.path);
if (pack) {
//get lincd related dependencies and get the actual package details from the package map by removing '@dacore/' from the package name
let packageDependencies = Object.keys(pack.dependencies)
.filter((dependency) => lincdPackages.has(dependency))
.map((dependency) => {
return lincdPackages.has(dependency)
? lincdPackages.get(dependency)
: dependency;
});
// console.log(package.packageName,packageDependencies.map())
dependencies.set(pkg, packageDependencies);
}
});
dependencies.forEach((PackageDependencies, pkg) => {
if (!PackageDependencies.some((dependency) => {
return (typeof dependency !== 'string' &&
lincdPackages.has(dependency.packageName));
})) {
leastDependentPackage = pkg;
}
});
let startStack = [leastDependentPackage];
const runPackage = (runFunction, pck) => {
return runFunction(pck)
.catch((errorObj) => {
if (errorObj.error) {
let { error, stdout, stderr } = errorObj;
warn('Uncaught exception whilst running parallel function on ' +
pck.packageName, (error === null || error === void 0 ? void 0 : error.message) ? error.message : error === null || error === void 0 ? void 0 : error.toString());
}
else {
warn('Uncaught exception whilst running parallel function on ' +
pck.packageName, errorObj === null || errorObj === void 0 ? void 0 : errorObj.toString());
process.exit();
}
// warn(chalk.red(pck.packageName+' failed:'));
// console.log(stdout);
})
.then((res) => {
done.add(pck);
return res;
});
};
let done = new Set();
let results = [];
let runStack = async (stack) => {
let runFunction = onBuildStack(stack, dependencies);
let stackPromise;
if (sync) {
//build the stack in parallel
stackPromise = Promise.resolve(true);
stack.forEach((pck) => {
stackPromise = stackPromise.then(() => {
return runPackage(runFunction, pck);
});
});
}
else {
//build the stack in parallel
stackPromise = Promise.all(stack.map((pck) => {
return runPackage(runFunction, pck);
}));
}
//wait till stack is completed
let stackResults = await stackPromise;
results = results.concat(stackResults);
//clear stack for next round
stack = [];
//find those packages who have all their dependencies already built and add them to the stack
lincdPackages.forEach((pkg) => {
let deps = dependencies.get(pkg);
//if the package is not done yet
//but every dependency is now done OR was not something we can build (some @dacore dependencies may not be local)
if (!done.has(pkg) &&
deps.every((dependency) => {
return (typeof dependency !== 'string' &&
(done.has(dependency) || !lincdPackages.has(dependency.packageName)));
})) {
stack.push(pkg);
}
});
if (stack.length <= 0 && done.size < lincdPackages.size) {
console.log(chalk_1.default.red('Only ' +
done.size +
' out of ' +
lincdPackages.size +
' packages have been built'));
console.log('ALL remaining packages have dependencies that have not been met. This may point to ' +
chalk_1.default.red('circular dependencies.'));
console.log('Already built: ' +
Array.from(done)
.map((p) => chalk_1.default.green(p.packageName))
.join(', '));
console.log(chalk_1.default.blue('\nTo solve this issue') +
': find the circular dependencies below and fix the dependencies:\n\n');
//TODO: actually find and name the packages that have circular dependencies
// let circular = [];
// lincdPackages.forEach((pkg) => {
// if (!done.has(pkg))
// {
// let deps = dependencies.get(pkg);
// if (deps.some(dependency => {
// //return true if this dependency (indirectly) depends on the package whos' dependency it is
// return hasDependency(dependency,pkg,dependencies)
// }))
// {
// circular.push(pkg);
// }
// process.exit();
// }
// });
lincdPackages.forEach((pkg) => {
let deps = dependencies.get(pkg);
if (!done.has(pkg)) {
console.log(chalk_1.default.red(pkg.packageName) +
' has not been built yet. Unbuilt dependencies:\n' +
deps
.filter((dependency) => {
return !Array.from(done).some((p) => {
// console.log(p.packageName,dependency.packageName,p===dependency)
return p === dependency;
});
})
.map((p) => chalk_1.default.red('\t- ' +
((p === null || p === void 0 ? void 0 : p.packageName) ? p.packageName : p.toString()) +
'\n'))
.join(' '));
// console.log(chalk.red(pkg.packageName)+' has not been built yet. Built dependencies:\n' + deps.filter(dependency => {
// return Array.from(done).some(p => p.packageName === pkg.packageName)
// }).map(p => chalk.green('\t- '+p.packageName+'\n')).join(" "))
// console.log(chalk.red(pkg.packageName)+' has not been built yet. Built dependencies:\n' + deps.filter(dependency => done.has(pkg)).map(p => chalk.green('\t- '+p.packageName+'\n')).join(" "))
}
});
}
//if more to be built, iterate
if (stack.length > 0) {
return runStack(stack);
}
else {
onStackEnd(dependencies, results.filter(Boolean));
}
};
//starts the process
runStack(startStack);
}
function hasDependency(pkg, childPkg, dependencies, depth = 1) {
console.log('Does ' + pkg.packageName + ' have dep ' + childPkg.packageName + ' ?');
let deps = dependencies.get(pkg);
if (deps.some((dependency) => {
console.log(dependency.packageName, childPkg.packageName, dependency === childPkg);
if (depth === 2)
return false;
// return dependency === childPkg;
return (dependency === childPkg ||
hasDependency(dependency, childPkg, dependencies, depth++));
})) {
console.log('##YES');
return true;
}
console.log('going up');
return false;
}
function buildAll(options) {
console.log('Building all LINCD packages of this repository in order of dependencies');
let lincdPackages = getLocalLincdPackageMap();
let startFrom;
//by default start building
let building = true;
let from = options === null || options === void 0 ? void 0 : options.from;
let sync = (options === null || options === void 0 ? void 0 : options.sync) || false;
// console.log('from', from);
// console.log('sync', sync);
// process.exit();
//option to start from a specific package in the stack
if (from) {
startFrom = from;
//if we have a startFrom, then we havnt started the build process yet
building = startFrom ? false : true;
//clear targets
// target = '';
// target2 = '';
console.log(chalk_1.default.blue('Will skip builds until ' + startFrom));
// return async (pkg) => {};
}
// if (target2 == 'from') {
// startFrom = target3;
// //if we have a startFrom, then we havnt started the build process yet
// building = startFrom ? false : true;
//
// //clear targets
// target2 = '';
// target3 = '';
// console.log(chalk.blue('Will skip builds until ' + startFrom));
//
// // return async (pkg) => {};
// }
let done = new Set();
let failedModules = [];
progressUpdate(lincdPackages.size + ' packages left');
let packagesLeft = lincdPackages.size;
// let packagesLeft = lincdPackages.size - done.size;
runOnPackagesGroupedByDependencies(lincdPackages, (packageGroup, dependencies) => {
if (done.size > 0) {
(0, utils_js_1.debugInfo)(chalk_1.default.magenta('\n-------\nThese packages are next, since all their dependencies have now been build:'));
// log(stack);
}
(0, utils_js_1.debugInfo)('Now building: ' + chalk_1.default.blue(packageGroup.map((i) => i.packageName)));
return async (pkg) => {
let command;
let skipping = false;
//if we're skipping builds until a certain package
if (!building) {
//if the package name matches the package we're supposed to start from then start building packages
if (pkg.packageName == startFrom || pkg.packageName == startFrom) {
building = true;
}
//else still waiting for the package
else {
log(chalk_1.default.blue('skipping ' + pkg.packageName));
command = Promise.resolve(true);
skipping = true;
}
}
//unless told otherwise, build the package
if (!command) {
command = (0, exports.buildPackage)(null, null, path_1.default.join(process.cwd(), pkg.path), false);
// command = execPromise(
// 'cd ' + pkg.path + ' && yarn exec lincd build',
// // (target ? ' ' + target : '') +
// // (target2 ? ' ' + target2 : ''),
// false,
// false,
// {},
// false,
// );
log(chalk_1.default.cyan('Building ' + pkg.packageName));
process.stdout.write(packagesLeft + ' packages left\r');
}
return command.then(res => {
//empty string or true is success
//false is success with warnings
//any other string is the build error text
//undefined result means it failed
// if (res !== '' && res !== true && res !== false) {
if (typeof res === 'undefined') {
failedModules.push(pkg.packageName);
let dependentModules = getDependentPackages(dependencies, pkg);
if (dependentModules.length > 0) {
printBuildResults(failedModules, done);
console.log('Stopping build process because an error occurred whilst building ' +
pkg.packageName +
', which ' +
dependentModules.length +
' other packages depend on.'); //"+dependentModules.map(d => d.packageName).join(", ")));
log('Run ' +
chalk_1.default.greenBright(`lincd build-all --from=${pkg.packageName}`) +
' to build only the remaining packages'); //"+dependentModules.map(d => d.packageName).join(", ")));
process.exit(1);
}
}
else {
if (!skipping) {
log(chalk_1.default.green('Built ' + pkg.packageName) + (res === false ? chalk_1.default.redBright(' (with warnings)') : ''));
}
done.add(pkg);
packagesLeft--;
// log(chalk.magenta(packagesLeft + ' packages left'));
process.stdout.write(packagesLeft + ' packages left\r');
if (packagesLeft == 0) {
printBuildResults(failedModules, done);
if (failedModules.length > 0) {
process.exit(1);
}
}
return res;
}
})
.catch(({ error, stdout, stderr }) => {
warn(chalk_1.default.red('Failed to build ' + pkg.packageName));
console.log(stdout);
process.exit(1);
// let dependentModules = getDependentP
});
//undefined result means it failed
/*if (typeof res === 'undefined')
{
// .catch(({ error,stdout,stderr }) => {
//this prints out the webpack output, including the build errors
// warn('Failed to build ' + pkg.packageName);
// console.log(stdout);
failedModules.push(pkg.packageName);
let dependentModules = getDependentPackages(dependencies,pkg);
if (dependentModules.length > 0)
{
printBuildResults(failedModules,done);
console.log(
'Stopping build process because an error occurred whilst building ' +
pkg.packageName +
', which ' +
dependentModules.length +
' other packages depend on.',
); //"+dependentModules.map(d => d.packageName).join(", ")));
log(
'Run ' +
chalk.greenBright(`lincd build-all --from=${pkg.packageName}`) +
' to build only the remaining packages',
); //"+dependentModules.map(d => d.packageName).join(", ")));
process.exit(1);
}
}
else //true is successful build, false is successful but with warnings
{
//successful build
// })
// .then((res) => {
if (!skipping)
{
log(chalk.green('Built ' + pkg.packageName)+(res === false ? chalk.redBright(' (with warnings)') : ''));
}
done.add(pkg);
packagesLeft--;
// log(chalk.magenta(packagesLeft + ' packages left'));
process.stdout.write(packagesLeft + ' packages left\r');
if (packagesLeft == 0)
{
printBuildResults(failedModules,done);
if (failedModules.length > 0)
{
process.exit(1);
}
}
return res;
}*/
// }).catch(err => {
// console.log(err);
// })
};
}, (dependencies) => {
//if no more packages to build but we never started building...
if (!building) {
console.log(chalk_1.default.red('Could not find the package to start from. Please provide a correct package name or package name to build from'));
}
else {
//Detecting cyclical dependencies that caused some packages not to be build
let first = true;
lincdPackages.forEach((pkg) => {
if (!done.has(pkg)) {
let deps = dependencies.get(pkg);
if (first) {
console.log(chalk_1.default.red('CYCLICAL DEPENDENCIES? - could not build some packages because they depend on each other.'));
first = false;
}
//print the cyclical dependencies
console.log(chalk_1.default.red(pkg.packageName) +
' depends on ' +
deps
.filter((dependency) => {
return typeof dependency !== 'string';
})
.map((d) => {
return done.has(d)
? d.packageName
: chalk_1.default.red(d.packageName);
})
.join(', '));
//also print some information why these packages have not been moved into the stack
let stringDependencies = deps.filter((d) => typeof d === 'string');
if (stringDependencies.length > 0) {
console.log(chalk_1.default.red('And it depends on these package(s) - which seem not to be proper packages :' +
stringDependencies.join(', ')));
console.log(chalk_1.default.red('Could you remove this from dependencies? Should it be a devDependency?'));
}
}
});
}
}, sync);
}
function getDependentPackages(dependencies, pkg) {
let dependentModules = [];
dependencies.forEach((dModuleDependencies, dModule) => {
if (dModuleDependencies.indexOf(pkg) !== -1) {
dependentModules.push(dModule);
}
});
return dependentModules;
}
/**
* Returns a map of the packages that this repository manages (so no packages found through the workspaces who's path contains ../ )
* @param rootPath
*/
function getLocalLincdPackageMap(rootPath = './') {
let map = new Map();
getLincdPackages(rootPath).forEach((pkg) => {
if (pkg.path.indexOf('../') === -1 && pkg.path.indexOf('..\\') === -1) {
// console.log(package.path);
map.set(pkg.packageName, pkg);
}
});
return map;
}
function getLocalLincdModules(rootPath = './') {
return getLincdPackages(rootPath).filter((pkg) => {
return pkg.path.indexOf('..\\') === -1;
});
}
function getLincdPackages(rootPath = process.cwd()) {
let pack = (0, utils_js_1.getPackageJSON)();
if (!pack || !pack.workspaces) {
for (let i = 0; i <= 3; i++) {
rootPath = path_1.default.join(process.cwd(), ...Array(i).fill('..'));
pack = (0, utils_js_1.getPackageJSON)(rootPath);
if (pack && pack.workspaces) {
// log('Found workspace at '+packagePath);
break;
}
}
}
if (!pack || !pack.workspaces) {
warn(chalk_1.default.red('Could not find package workspaces. Make sure you run this command from a yarn workspace.'));
logHelp();
process.exit();
}
// console.log(pack.workspaces);
let res = [];
checkWorkspaces(rootPath, pack.workspaces, res);
return res;
}
function setVariable(name, replacement) {
//prepare name for regexp
name = name.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
variables[name] = replacement;
}
var replaceVariablesInFile = async (filePath) => {
var fileContent = await fs_extra_1.default.readFile(filePath, 'utf8').catch((err) => {
console.warn(chalk_1.default.red('Could not read file ' + filePath));
});
if (fileContent) {
var newContent = replaceCurlyVariables(fileContent);
return fs_extra_1.default.writeFile(filePath, newContent);
}
else {
return Promise.resolve();
}
};
var replaceCurlyVariables = function (string) {
// var reg = new RegExp('\\$\\{'+key+'\\}','g');
for (var key in variables) {
string = string.replace(new RegExp('\\$\\{' + key + '\\}', 'g'), variables[key]);
}
return string;
};
const capitalize = (str) => str.charAt(0).toUpperCase() + str.toLowerCase().slice(1);
const camelCase = (str) => {
let string = str.replace(/[^A-Za-z0-9]/g, ' ').split(' ');
if (string.length > 1) {
return string.reduce((result, word) => result + capitalize(word));
}
return str;
};
const createOntology = async (prefix, uriBase, basePath = process.cwd()) => {
if (!prefix) {
console.warn('Please provide a suggested prefix as the first argument');
return;
}
let sourceFolder = getSourceFolder(basePath);
let targetFolder = ensureFolderExists(sourceFolder, 'ontologies');
if (!uriBase) {
uriBase = 'http://lincd.org/ont/' + prefix + '/';
}
setVariable('uri_base', uriBase);
let { hyphenName, camelCaseName, underscoreName } = (0, exports.setNameVariables)(prefix);
//copy ontology accessor file
log('Creating files for ontology \'' + prefix + '\'');
let targetFile = path_1.default.join(targetFolder, hyphenName + '.ts');
fs_extra_1.default.copySync(path_1.default.join(dirname__, '..', '..', 'defaults', 'package', 'src', 'ontologies', 'example-ontology.ts'), targetFile);
//copy data files
let targetDataFile = path_1.default.join(targetFolder, '..', 'data', hyphenName + '.json');
let targetDataFile2 = path_1.default.join(targetFolder, '..', 'data', hyphenName + '.json.d.ts');
fs_extra_1.default.copySync(path_1.default.join(dirname__, '..', '..', 'defaults', 'package', 'src', 'data', 'example-ontology.json'), targetDataFile);
fs_extra_1.default.copySync(path_1.default.join(dirname__, '..', '..', 'defaults', 'package', 'src', 'data', 'example-ontology.json.d.ts'), targetDataFile2);
await replaceVariablesInFiles(targetFile, targetDataFile, targetDataFile2);
log(`Prepared a new ontology data files in ${chalk_1.default.magenta(targetDataFile.replace(basePath, ''))}`, `And an ontology accessor file in ${chalk_1.default.magenta(targetFile.replace(basePath, ''))}`);
//if this is not a lincd app (but a lincd package instead)
if (!sourceFolder.includes('frontend')) {
//then also add an import to index
let indexPath = addLineToIndex(`import './ontologies/${hyphenName}.js';`, 'ontologies');
log(`Added an import of this file from ${chalk_1.default.magenta(indexPath)}`);
}
};
exports.createOntology = createOntology;
const addLineToIndex = function (line, insertMatchString, root = process.cwd(), insertAtStart = false) {
//import ontology in index
let indexPath = ['index.ts', 'index.tsx']
.map((f) => path_1.default.join(root, 'src', f))
.find((indexFileName) => {
return fs_extra_1.default.existsSync(indexFileName);
});
if (indexPath) {
let indexContents = fs_extra_1.default.readFileSync(indexPath, 'utf-8');
let lines = indexContents.split(/\n/g);
let newContents;
for (var key in lines) {
//if the match string is found
if (lines[key].indexOf(insertMatchString) !== -1) {
//add the new line after this line
lines[key] += `\n${line}`;
newContents = lines.join('\n');
// log("Found at "+key,lines,newContents);
break;
}
}
if (!newContents) {
if (insertAtStart) {
newContents = `${line}\n${indexContents}`;
}
else {
newContents = `${indexContents}\n${line}`;
}
// log("Added at end",newContents);
}
fs_extra_1.default.writeFileSync(indexPath, newContents);
}
return indexPath;
};
const replaceVariablesInFiles = function (...files) {
return Promise.all(files.map((file) => {
return replaceVariablesInFile(file);
}));
};
const replaceVariablesInFolder = function (folder) {
//get all files in folder, including files that start with a dot
glob_1.glob(folder + '/**/*', { dot: true, nodir: true }, async function (err, files) {
if (err) {
console.log('Error', err);
}
else {
// console.log(files);
await Promise.all(files.map((file) => {
return replaceVariablesInFile(file);
}));
}
});
};
const replaceVariablesInFilesWithRoot = function (root, ...files) {
return replaceVariablesInFiles(...files.map((f) => path_1.default.join(root, f)));
};
const hasYarnInstalled = async function () {
let version = (await (0, utils_js_1.execPromise)('yarn --version').catch((err) => {
console.log('yarn probably not working');
return '';
}));
return version.toString().match(/[0-9]+/);
};
const ensureFolderExists = function (...folders) {
let target;
folders.forEach((folder) => {
target = target ? path_1.default.join(target, folder) : path_1.default.join(folder);
if (!fs_extra_1.default.existsSync(target)) {
fs_extra_1.default.mkdirSync(target);
}
});
return target;
/*let targetFolder = path.join(...folders);
let parentDirectory = folders.slice(0, folders.length - 1);
if (!fs.existsSync(targetFolder)) {
if (fs.existsSync(path.join(...parentDirectory))) {
fs.mkdirSync(targetFolder);
} else {
warn(
`Please run this command from the root of your package. This command expects ${parentDirectory.toString()} to exists from that folder`,
);
}
}
return targetFolder;*/
};
const setNameVariables = function (name) {
let hyphenName = name.replace(/[-_\s]+/g, '-');
let camelCaseName = camelCase(name); //some-package --> someModule
let underscoreName = name.replace(/[-\s]+/g, '_');
let plainName = name.replace(/[-\s]+/g, '');
//longer similar variables names should come before the shorter ones
setVariable('underscore_name', underscoreName);
setVariable('hyphen_name', hyphenName);
setVariable('camel_name', camelCaseName);
setVariable('name', name);
setVariable('plain_name', plainName);
return { hyphenName, camelCaseName, underscoreName, plainName };
};
exports.setNameVariables = setNameVariables;
function getSourceFolder(basePath = process.cwd()) {
//LINCD App
if (fs_extra_1.default.existsSync(path_1.default.join(basePath, 'frontend', 'src'))) {
return path_1.default.join(basePath, 'frontend', 'src');
}
//LINCD package
if (fs_extra_1.default.existsSync(path_1.default.join(basePath, 'src'))) {
return path_1.default.join(basePath, 'src');
}
else {
console.warn('Cannot find source folder');
return path_1.default.join(basePath, 'src');
}
}
/**
* get __dirname for either ESM/CJS
*/
const getScriptDir = () => {
return dirname__;
// // @ts-ignore
// if (typeof __dirname !== 'undefined')
// {
// // @ts-ignore
// return __dirname;
// }
// else
// {
// // @ts-ignore
// return dirname(import.meta.url).replace('file:/','');
// }
};
exports.getScriptDir = getScriptDir;
const createShape = async (name, basePath = process.cwd()) => {
let sourceFolder = getSourceFolder(basePath);
let targetFolder = ensureFolderExists(sourceFolder, 'shapes');
let { hyphenName, camelCaseName, underscoreName } = (0, exports.setNameVariables)(name);
//copy default shape file
// log("Creating files for shape '" + name + "'");
let targetFile = path_1.default.join(targetFolder, hyphenName + '.ts');
fs_extra_1.default.copySync(path_1.default.join((0, exports.getScriptDir)(), '..', '..', 'defaults', 'shape.ts'), targetFile);
//replace variables in some of the copied files
await replaceVariablesInFiles(targetFile);
log(`Created a new shape class template in ${chalk_1.default.magenta(targetFile.replace(basePath, ''))}`);
//if this is NOT a lincd app (but a lincd package)
let indexPath;
if (!sourceFolder.includes('frontend')) {
indexPath = addLineToIndex(`import './shapes/${hyphenName}.js';`, 'shapes');
log(`Added an import of this file from ${chalk_1.default.magenta(indexPath)}`);
}
};
exports.createShape = createShape;
const createSetComponent = async (name, basePath = process.cwd()) => {
let targetFolder = ensureFolderExists(basePath, 'src', 'components');
let { hyphenName, camelCaseName, underscoreName } = (0, exports.setNameVariables)(name);
//copy default shape file
log('Creating files for set component \'' + name + '\'');
let targetFile = path_1.default.join(targetFolder, hyphenName + '.tsx');
fs_extra_1.default.copySync(path_1.default.join((0, exports.getScriptDir)(), '..', '..', 'defaults', 'set-component.tsx'), targetFile);
let targetFile2 = path_1.default.join(targetFolder, hyphenName + '.scss');
fs_extra_1.default.copySync(path_1.default.join((0, exports.getScriptDir)(), '..', '..', 'defaults', 'component.scss'), targetFile2);
//replace variables in some of the copied files
await replaceVariablesInFiles(targetFile, targetFile2);
let indexPath = addLineToIndex(`import './components/${hyphenName}.js';`, 'components');
log(`Created a new set component in ${chalk_1.default.magenta(targetFile.replace(basePath, ''))}`, `Created a new stylesheet in ${chalk_1.default.magenta(targetFile2.replace(basePath, ''))}`, `Added an import of this file from ${chalk_1.default.magenta(indexPath)}`);
};
exports.createSetComponent = createSetComponent;
const createComponent = async (name, basePath = process.cwd()) => {
let sourceFolder = getSourceFolder(basePath);
let targetFolder = ensureFolderExists(sourceFolder, 'components');
let { hyphenName, camelCaseName, underscoreName } = (0, exports.setNameVariables)(name);
//copy default shape file
log('Creating files for component \'' + name + '\'');
let targetFile = path_1.default.join(targetFolder, hyphenName + '.tsx');
fs_extra_1.default.copySync(path_1.default.join((0, exports.getScriptDir)(), '..', 'defaults', 'component.tsx'), targetFile);
let targetFile2 = path_1.default.join(targetFolder, hyphenName + '.scss');
fs_extra_1.default.copySync(path_1.default.join((0, exports.getScriptDir)(), '..', 'defaults', 'component.scss'), targetFile2);
//replace variables in some of the copied files
await replaceVariablesInFiles(targetFile, targetFile2);
log(`Created a new component template in ${chalk_1.default.magenta(targetFile.replace(basePath, ''))}`, `Created component stylesheet template in ${chalk_1.default.magenta(targetFile2.replace(basePath, ''))}`);
//if this is not a lincd app (but a lincd package instead)
if (!sourceFolder.includes('frontend')) {
//then also add an import to index
let indexPath = addLineToIndex(`import './components/${hyphenName}.js';`, 'components');
log(`Added an import of this file from ${chalk_1.default.magenta(indexPath)}`);
}
};
exports.createComponent = createComponent;
//read the source of all ts/tsx files in the src folder
//if there is an import that imports a lincd package with /src/ in it, then warn
//if there is an import that imports something from outside the src folder, then warn
const checkImports = async (sourceFolder = getSourceFolder(), depth = 0, // Used to check if the import is outside the src folder
invalidImports = new Map()) => {
const dir = fs_extra_1.default.readdirSync(sourceFolder);
// Start checking each file in the source folder
for (const file of dir) {
const filename = path_1.default.join(sourceFolder, file);
// File is either a directory, or not a .ts(x)
// INFO: For future use - if this part fails, it could be due to user permissions
// i.e. the program not having access to check the file metadata
if (!filename.match(/\.tsx?$/)) {
try {
if ((0, fs_1.statSync)(filename).isDirectory()) {
await (0, exports.checkImports)(filename, depth + 1, invalidImports);
}
else {
// Ignore all files that aren't one of the following:
// - .ts
// - .tsx
continue;
}
}
catch (e) {
console.log(e);
}
}
const allImports = await (0, utils_js_1.getFileImports)(filename);
if (!invalidImports.has(filename)) {
invalidImports.set(filename, []);
}
allImports.forEach((i) => {
if ((0, utils_js_1.isImportOutsideOfPackage)(i, depth)) {
invalidImports.get(filename).push({
type: 'outside_package',
importPath: i
});
}
if ((0, utils_js_1.isInvalidLINCDImport)(i, depth)) {
invalidImports.get(filename).push({
type: 'lincd',
importPath: i
});
}
if ((0, utils_js_1.isImportWithMissingExtension)(i)) {
invalidImports.get(filename).push({
type: 'missing_extension',
importPath: i
});
}
});
}
let res = '';
//check if invalidImports has any
let flat = [...invalidImports.values()].flat();
// All recursion must have finished, display any errors
if (depth === 0 && flat.length > 0) {
res += chalk_1.default.red('Invalid imports found.\n');
invalidImports.forEach((value, key) => {
// res += '- '+chalk.blueBright(key.split('/').pop()) + ':\n';
value.forEach(({ type, importPath }) => {
let message = key.split('/').pop() + ' imports from \'' + importPath + '\'';
if (type === 'outside_package') {
message += ' which is outside the package source root';
}
if (type === 'lincd') {
message += ' which should not contain /src/ or /lib/ in the import path';
}
if (type === 'missing_extension') {
message += ' which should end with a file extension. Like .js or .scss';
}
res += chalk_1.default.red(message + '\n');
});
});
throw res;
// process.exit(1);
}
else if (depth === 0 && invalidImports.size === 0) {
// console.info('All imports OK');
// process.exit(0);
return true;
}
};
exports.checkImports = checkImports;
const depCheckStaged = async () => {
console.log('Checking dependencies of staged files');
(0, staged_git_files_1.default)(async function (err, results) {
const packages = new Set();
await Promise.all(results.map(async (file) => {
// console.log('STAGED: ', file.filename);
let root = await (0, find_nearest_package_json_1.findNearestPackageJson)(file.filename);
packages.add(root.path);
}));
[...packages].forEach((packageRoot) => {
const pack = JSON.parse(fs_extra_1.default.readFileSync(packageRoot, 'utf8'));
const srcPath = packageRoot.replace('package.json', '');
console.log('Checking dependencies of ' + chalk_1.default.blue(pack.name) + ':');
return (0, exports.depCheck)(process.cwd() + '/' + srcPath);
// console.log('check dependencies of ' + pack.name);
//
// console.log('ROOT of ' + file.filename + ': ' + root.path);
// console.log('ROOT of ' + file.filename + ': ' + root.data);
});
});
};
exports.depCheckStaged = depCheckStaged;
const depCheck = async (packagePath = process.cwd()) => {
return new Promise((resolve, reject) => {
(0, depcheck_1.default)(packagePath, {}, (results) => {
if (results.missing) {
let lincdPackages = getLocalLincdModules();
let missing = Object.keys(results.missing);
//filter out missing types, if it builds we're not too concerned about that at the moment?
//especially things like @types/react, @types/react-dom, @types/node (they are added elsewhere?)
// missing = missing.filter(m => m.indexOf('@types/') === 0);
//currently react is not an explicit dependency, but we should add it as a peer dependency
missing.splice(missing.indexOf('react'), 1);
let missingLincdPackages = missing.filter((missingDep) => {
return lincdPackages.some((lincdPackage) => {
return lincdPackage.packageName === missingDep;
});
});
//currently just missing LINCD packages cause a hard failure exit code
if (missingLincdPackages.length > 0) {
reject(chalk_1.default.red(packagePath.split('/').pop() +
'\n[ERROR] These LINCD packages are imported but they are not listed in package.json:\n- ' +
missingLincdPackages.join(',\n- ')));
}
else if (missing.length > 0) {
resolve(chalk_1.default.redBright('warning: ' + packagePath.split('/').pop() +
' is missing dependencies:\n - ' +
missing.join('\n - ')));
}
else {
resolve(true);
}
}
// if(Object.keys(results.invalidFiles).length > 0) {
// console.warn(chalk.red("Invalid files:\n")+Object.keys(results.invalidFiles).join(",\n"));
// }
// if(Object.keys(results.invalidDirs).length > 0) {
// console.warn(chalk.red("Invalid dirs:\n")+results.invalidDirs.toString());
// }
// if(results.unused) {
// console.warn("Unused dependencies: "+results.missing.join(", "));
// }
});
});
};
exports.depCheck = depCheck;
const ensureEnvironmentLoaded = async () => {
if (!process.env.NODE_ENV) {
//load env-cmd for development environment
let { GetEnvVars } = await Promise.resolve().then(() => __importStar(require('env-cmd')));
let envCmdrcPath = path_1.default.join(process.cwd(), '.env-cmdrc.json');
if (!fs_extra_1.default.existsSync(envCmdrcPath)) {
console.warn('No .env-cmdrc.json found in this folder. Are you running this command from the root of a LINCD app?');
process.exit();
}
let vars = await GetEnvVars({
envFile: {
filePath: envCmdrcPath,
},
});
let environments = Object.keys(vars);
//if _main is present, load it first
if (environments.includes('_main')) {
process.env = { ...process.env, ...vars._main };
}
//if --env is passed, load that environment
let args = process.argv.splice(2);
if (args.includes('--env')) {
let envIndex = args.indexOf('--env');
let env = args[envIndex + 1];
env.split(',').forEach((singleEnvironment) => {
if (environments.includes(singleEnvironment)) {
console.log('Environment: ' + singleEnvironment);
process.env = { ...process.env, ...vars[singleEnvironment] };
}
else {
console.warn('Environment ' +
singleEnvironment +
' not found in .env-cmdrc.json. Available environments: ' +
environments.join(', '));
}
});
}
else {
//chose development by default
process.env = { ...process.env, ...vars.development };
console.log('No environment specified, using development');
}
}
};
exports.ensureEnvironmentLoaded = ensureEnvironmentLoaded;
const startServer = async (initOnly = false, ServerClass = null) => {
await (0, exports.ensureEnvironmentLoaded)();
let lincdConfig = (await Promise.resolve(`${path_1.default.join(process.cwd(), 'lincd.config.js')}`).then(s => __importStar(require(s)))).default;
// function scssLoadcall(source, filename) {
// return 'console.log("SCSS CALL: ' + filename + '");\n' + source;
// process.exit();
// }
// hook.hook('.scss', scssLoadcall);
// hook.hook('.css', scssLoadcall);
// import.meta.
// // hook.hook('*.css', scssLoadcall);
// // hook.hook('Body.module.css', scssLoadcall);
// hook.hook('.module.css', scssLoadcall);
if (!ServerClass) {
//@ts-ignore
ServerClass = (await Promise.resolve().then(() => __importStar(require('lincd-server/shape