devextreme
Version:
JavaScript/TypeScript Component Suite for Responsive Web Development
241 lines (196 loc) • 7.21 kB
JavaScript
const fs = require('fs');
const path = require('path');
const { getDevExpressLCXKey } = require('./dx-get-lcx');
const { tryConvertLCXtoLCP, getLCPInfo } = require('./dx-lcx-2-lcp');
const { TEMPLATES } = require('./messages');
const EXPORT_NAME = 'licenseKey';
const TRIAL_VALUE = 'TRIAL';
const CLI_PREFIX = '[devextreme-license]';
function logStderr(...lines) {
process.stderr.write(lines.join('\n') + '\n\n');
}
function prefixed(msg) {
return `${CLI_PREFIX} ${msg}`;
}
function fail(msg) {
process.stderr.write(msg.endsWith('\n') ? msg : msg + '\n');
process.exit(0);
}
function printHelp() {
process.stdout.write(
[
'Usage:',
' devextreme-license --out <path> [options]',
'',
'Options:',
' --out <path> Output file path (optional)',
' --non-modular Generate a non-modular JS file (only with .js extension)',
' --no-gitignore Do not modify .gitignore',
' --force Overwrite existing output file',
' --cwd <path> Project root (default: process.cwd())',
' -h, --help Show help',
'',
'Examples:',
' "prebuild": "devextreme-license --out src/.devextreme/license-key.ts"',
' "prebuild": "devextreme-license --non-modular --out src/.devextreme/license-key.js"',
'',
].join('\n')
);
}
function parseArgs(argv) {
const args = argv.slice(2);
const out = {
outPath: null,
nonModular: false,
gitignore: true,
force: false,
cwd: process.cwd(),
help: false,
};
for(let i = 0; i < args.length; i++) {
const a = args[i];
if(a === '-h' || a === '--help') out.help = true;
else if(a === '--out') {
const next = args[i + 1];
if(!next || next.startsWith('-')) {
logStderr(prefixed('Warning: --out requires a path argument but none was provided. Ignoring --out.'));
} else {
out.outPath = args[++i];
}
}
else if(a.startsWith('--out=')) {
const val = a.slice('--out='.length);
if(!val) {
logStderr(prefixed('Warning: --out requires a path argument but none was provided. Ignoring --out.'));
} else {
out.outPath = val;
}
}
else if(a === '--non-modular') out.nonModular = true;
else if(a === '--no-gitignore') out.gitignore = false;
else if(a === '--force') out.force = true;
else if(a === '--cwd') out.cwd = args[++i] || process.cwd();
else if(a.startsWith('--cwd=')) out.cwd = a.slice('--cwd='.length);
else fail(`Unknown argument: ${a}\nRun devextreme-license --help`);
}
return out;
}
function ensureDirExists(dirPath) {
fs.mkdirSync(dirPath, { recursive: true });
}
function readTextIfExists(filePath) {
try {
if(!fs.existsSync(filePath)) return null;
return fs.readFileSync(filePath, 'utf8');
} catch{
return null;
}
}
function writeFileAtomic(filePath, content) {
const dir = path.dirname(filePath);
const base = path.basename(filePath);
const tmp = path.join(dir, `.${base}.${process.pid}.${Date.now()}.tmp`);
fs.writeFileSync(tmp, content, 'utf8');
fs.renameSync(tmp, filePath);
}
function toPosixPath(p) {
return p.split(path.sep).join('/');
}
function addToGitignore(projectRoot, outAbsPath) {
const gitignorePath = path.join(projectRoot, '.gitignore');
let rel = path.relative(projectRoot, outAbsPath);
if(rel.startsWith('..')) return;
rel = toPosixPath(rel).trim();
const existing = readTextIfExists(gitignorePath);
if(existing == null) {
writeFileAtomic(gitignorePath, rel + '\n');
return;
}
const lines = existing.split(/\r?\n/).map((l) => l.trim());
if(lines.includes(rel) || lines.includes('/' + rel)) return;
const needsNewline = existing.length > 0 && !existing.endsWith('\n');
fs.appendFileSync(gitignorePath, (needsNewline ? '\n' : '') + rel + '\n', 'utf8');
}
function renderFile(lcpKey) {
return [
'// Auto-generated by devextreme-license.',
'// Do not commit this file to source control.',
'',
`export const ${EXPORT_NAME} = ${JSON.stringify(lcpKey)};`,
'',
].join('\n');
}
function renderNonModularFile(lcpKey) {
return [
'// Auto-generated by devextreme-license.',
'// Do not commit this file to source control.',
'',
`DevExpress.config({ licenseKey: ${JSON.stringify(lcpKey)} });`,
'',
].join('\n');
}
function main() {
const opts = parseArgs(process.argv);
if(opts.help) {
printHelp();
process.exit(0);
}
const { key: lcx, source, currentVersion } = getDevExpressLCXKey() || {};
let lcp = TRIAL_VALUE;
let licenseId = null;
if(lcx) {
lcp = tryConvertLCXtoLCP(lcx) || TRIAL_VALUE;
const { warning, licenseId: id } = getLCPInfo(lcp);
licenseId = id;
if(warning) {
const lines = [];
lines.push(
prefixed(`${TEMPLATES.warningPrefix(1000)} ${TEMPLATES.purchaseLicense}`),
);
if(licenseId) {
lines.push(TEMPLATES.licenseId(licenseId));
}
lines.push(
TEMPLATES.keyWasFound(source.type, source.path),
);
if(warning.type !== 'trial') {
const code = TEMPLATES.warningCodeByType(warning.type);
lines.push(
TEMPLATES.keyVerificationFailed(warning.type, warning.keyVersion, warning.currentVersion),
);
if(warning.type === 'trialExpired') {
lines.push(prefixed(`${TEMPLATES.warningPrefix(code)} ${TEMPLATES.purchaseLicense}`));
} else {
lines.push(prefixed(`${TEMPLATES.warningPrefix(code)} ${TEMPLATES.installationInstructions}`));
}
}
logStderr(...lines);
}
} else {
logStderr(
prefixed(`${TEMPLATES.warningPrefix(1000)} ${TEMPLATES.purchaseLicense}`),
TEMPLATES.keyNotFound,
prefixed(`${TEMPLATES.warningPrefix(1001)} ${TEMPLATES.installationInstructions}`),
);
}
if(!opts.outPath) {
process.stdout.write(lcp + '\n');
process.exit(0);
}
const projectRoot = path.resolve(opts.cwd);
const outAbs = path.resolve(projectRoot, opts.outPath);
ensureDirExists(path.dirname(outAbs));
if(!opts.force && fs.existsSync(outAbs)) {
fail(`Output file already exists: ${opts.outPath}\nUse --force to overwrite.`);
}
const useNonModular = opts.nonModular && outAbs.endsWith('.js');
writeFileAtomic(outAbs, useNonModular ? renderNonModularFile(lcp) : renderFile(lcp));
if(opts.gitignore) {
try {
addToGitignore(projectRoot, outAbs);
} catch{}
}
process.exit(0);
}
main();