mirror of https://github.com/msgbyte/tailchat
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
3.6 KiB
TypeScript
149 lines
3.6 KiB
TypeScript
import ts from 'typescript';
|
|
import fs from 'fs-extra';
|
|
import ora from 'ora';
|
|
import { glob } from 'glob';
|
|
import path from 'path';
|
|
import execa from 'execa';
|
|
|
|
async function buildTailchatServer() {
|
|
const spinner = ora({
|
|
prefixText: 'Tailchat Server',
|
|
});
|
|
|
|
try {
|
|
spinner.start('Start compiling');
|
|
await fs.remove('./dist');
|
|
spinner.info('Compiling TS code');
|
|
await compileTsCode();
|
|
spinner.info('Moving static resource files');
|
|
await Promise.all([
|
|
fs.copy('./public', './dist/public', { recursive: true }),
|
|
fs.copy('./locales', './dist/locales', { recursive: true }),
|
|
fs.copy('./views', './dist/views', { recursive: true }),
|
|
fs.copy(
|
|
'./services/openapi/oidc/views',
|
|
'./dist/services/openapi/oidc/views',
|
|
{ recursive: true }
|
|
),
|
|
]);
|
|
|
|
if (process.platform !== 'win32' || (await isAdmin())) {
|
|
spinner.info('Building plugin dependent symlink');
|
|
const nodeModulesList = await glob('./plugins/*/node_modules/*');
|
|
for (const item of nodeModulesList) {
|
|
const src = path.resolve(__dirname, '../', item);
|
|
const dest = path.resolve(__dirname, '../dist', item);
|
|
|
|
spinner.text = `Building Symlink: ${src} -> ${dest}`;
|
|
|
|
await fs.createSymlink(src, dest, 'dir');
|
|
}
|
|
} else {
|
|
spinner.warn(
|
|
'You are run command in windows without admin permit, create symlink will be skip'
|
|
);
|
|
}
|
|
|
|
spinner.succeed('Compiled!');
|
|
} catch (e) {
|
|
console.error(e);
|
|
spinner.fail('Compilation failed!');
|
|
}
|
|
}
|
|
|
|
buildTailchatServer();
|
|
|
|
/**
|
|
* 编译Ts代码
|
|
*
|
|
* tsc的api实现
|
|
*/
|
|
function compileTsCode(): Promise<void> {
|
|
function compile(
|
|
fileNames: string[],
|
|
options: ts.CompilerOptions
|
|
): Promise<void> {
|
|
return new Promise<void>((resolve, reject) => {
|
|
const program = ts.createProgram(fileNames, options);
|
|
const emitResult = program.emit();
|
|
|
|
const allDiagnostics = ts
|
|
.getPreEmitDiagnostics(program)
|
|
.concat(emitResult.diagnostics);
|
|
|
|
allDiagnostics.forEach((diagnostic) => {
|
|
if (diagnostic.file) {
|
|
const { line, character } = ts.getLineAndCharacterOfPosition(
|
|
diagnostic.file,
|
|
diagnostic.start!
|
|
);
|
|
const message = ts.flattenDiagnosticMessageText(
|
|
diagnostic.messageText,
|
|
'\n'
|
|
);
|
|
console.log(
|
|
`${diagnostic.file.fileName} (${line + 1},${
|
|
character + 1
|
|
}): ${message}`
|
|
);
|
|
} else {
|
|
console.log(
|
|
ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')
|
|
);
|
|
}
|
|
});
|
|
|
|
const exitCode = emitResult.emitSkipped ? 1 : 0;
|
|
if (exitCode === 0) {
|
|
resolve();
|
|
} else {
|
|
reject();
|
|
}
|
|
});
|
|
}
|
|
|
|
const configPath = ts.findConfigFile(
|
|
process.cwd() /*searchPath*/,
|
|
ts.sys.fileExists,
|
|
'tsconfig.json'
|
|
);
|
|
const configFile = ts.readJsonConfigFile(configPath, ts.sys.readFile);
|
|
const { fileNames, options } = ts.parseJsonSourceFileConfigFileContent(
|
|
configFile,
|
|
ts.sys,
|
|
process.cwd()
|
|
);
|
|
|
|
return compile(fileNames, options);
|
|
}
|
|
|
|
/**
|
|
* check is window admin
|
|
*/
|
|
async function isAdmin() {
|
|
if (process.platform !== 'win32') {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
// https://stackoverflow.com/a/21295806/1641422
|
|
await execa('fsutil', ['dirty', 'query', process.env.systemdrive]);
|
|
return true;
|
|
} catch (error) {
|
|
if (error.code === 'ENOENT') {
|
|
return testFltmc();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function testFltmc() {
|
|
try {
|
|
await execa('fltmc');
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|