orange-orm
Version:
Object Relational Mapper
202 lines (182 loc) • 5.33 kB
JavaScript
let url = require('url');
let compile = require('./compile');
let path = require('path');
let fs = require('fs');
let util = require('util');
let writeFile = util.promisify(fs.writeFile);
let ts = require('typescript');
let getTSDefinition = require('../src/getTSDefinition');
const _axios = require('axios');
const axios = _axios.default ? _axios.default.create() : _axios.create();
async function run(cwd) {
for (let schemaTs of await findSchemaJs(cwd)) {
await runSingle(schemaTs);
}
}
async function runSingle(schemaTs) {
let outDir;
try {
let schemaJsPath;
let isPureJs = false;
if (!schemaTs)
return;
if (schemaTs.substring(schemaTs.length - 2) === 'js') {
schemaJsPath = schemaTs;
isPureJs = true;
}
console.log(`Orange: found schema ${schemaTs}`);
if (!schemaJsPath) {
let nodeModules = findClosestNodeModules(schemaTs);
outDir = path.join(nodeModules, '/.rdb', '/' + new Date().getUTCMilliseconds());
schemaJsPath = compile(schemaTs, { outDir });
}
let schemaJs = isPureJs ? await import(url.pathToFileURL(schemaJsPath)) : require(schemaJsPath);
if ('default' in schemaJs)
schemaJs = schemaJs.default;
if (!schemaJs.tables) {
console.log('Orange: no tables found.');
return;
}
let src = '';
if (typeof schemaJs.db === 'string') {
src = ((await tryDownload(schemaJs.db + '.d.ts', isPureJs) || await download(schemaJs.db, isPureJs)));
}
else {
let tsArg = Object.keys(schemaJs.tables).map(x => {
return { table: schemaJs.tables[x], name: x };
});
src = getTSDefinition(tsArg);
}
let indexDts = path.join(path.dirname(schemaTs), isPureJs ? '/index.d.ts' : '/index.ts');
let sourceFile = ts.createSourceFile(indexDts, src, ts.ScriptTarget.ES2015, true, ts.ScriptKind.TS);
const printer = ts.createPrinter();
await writeFile(indexDts, printer.printFile(sourceFile));
if (isPureJs)
await writeIndexJs(schemaJsPath);
console.log('Orange: created ts typings successfully.');
}
catch(e) {
console.dir(e);
}
if (outDir)
fs.rmSync(outDir, { recursive: true, force: true });
}
async function writeIndexJs(schemaJsPath) {
const schema = path.basename(schemaJsPath);
const indexJs = path.join(path.dirname(schemaJsPath), '/index' + path.extname(schemaJsPath));
if (detectModuleFormat(schemaJsPath) === 'commonjs')
await writeFile(indexJs, `module.exports = require('./${schema}');`);
else
await writeFile(indexJs, `export {default} from './${schema}';`);
}
function detectModuleFormat(filePath) {
const extension = path.extname(filePath);
if (extension === '.mjs')
return 'module';
if (extension === '.cjs')
return 'commonjs';
const pkg = findClosestPackageJson(path.dirname(filePath));
if (pkg && pkg.type === 'module')
return 'module';
return 'commonjs';
}
function findClosestPackageJson(startDir) {
let currentDir = startDir;
while (currentDir) {
const packageJsonPath = path.join(currentDir, 'package.json');
if (fs.existsSync(packageJsonPath)) {
try {
return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
}
catch (e) {
return null;
}
}
const parentDir = path.dirname(currentDir);
if (parentDir === currentDir)
return null;
currentDir = parentDir;
}
return null;
}
function findClosestNodeModules(startPath) {
const startDir = fs.statSync(startPath).isDirectory() ? startPath : path.dirname(startPath);
let currentDir = startDir;
// eslint-disable-next-line no-constant-condition
while (true) {
const nodeModulesPath = path.join(currentDir, 'node_modules');
if (fs.existsSync(nodeModulesPath))
return nodeModulesPath;
const parentDir = path.dirname(currentDir);
if (parentDir === currentDir)
return path.join(startDir, 'node_modules');
currentDir = parentDir;
}
}
async function findSchemaJs(cwd) {
let ignoredDirNames = {
node_modules: true,
dist: true,
dev: true,
deploy: true,
build: true
};
let files = [];
scanForSchemaFiles(cwd, ignoredDirNames, files);
files.sort((a, b) => {
const aIsTs = a.substring(a.length - 2) === 'ts';
const bIsTs = b.substring(b.length - 2) === 'ts';
if (aIsTs && bIsTs)
return 0;
else if (aIsTs)
return -1;
else if (bIsTs)
return 1;
else
return 0;
});
return files;
}
function scanForSchemaFiles(currentDir, ignoredDirNames, results) {
for (let entry of fs.readdirSync(currentDir)) {
const fullPath = path.join(currentDir, entry);
let stat;
try {
stat = fs.statSync(fullPath);
}
catch (e) {
continue;
}
if (stat.isDirectory()) {
if (ignoredDirNames[entry])
continue;
scanForSchemaFiles(fullPath, ignoredDirNames, results);
continue;
}
if (entry === 'schema.js' || entry === 'schema.mjs' || entry === 'schema.ts')
results.push(fullPath);
}
}
function tryDownload(_url, _isNamespace) {
try {
return download.apply(null, arguments).then((res) => res, () => '');
}
// eslint-disable-next-line no-empty
catch (e) {
}
}
async function download(url, isNamespace) {
url = `${url}?isNamespace=${isNamespace}`;
console.log(`Orange: downloading from ${url}`);
// eslint-disable-next-line no-undef
try {
let response = await axios.get(url);
return response.data;
}
catch(e) {
throw new Error('No config found at ' + url);
}
}
module.exports = function(cwd) {
run(cwd).then(null, console.log);
};