Support building TS declarations

`./build decl` now builds TS declarations for everything exported by
`sim/`. Unfortunately, the built TS declarations still refer to global
types, so some things still have `any` type, but it's much better than
nothing.
This commit is contained in:
Guangcong Luo 2021-06-09 16:26:46 -05:00
parent 147b7e01c9
commit f47e38c5ad
7 changed files with 59 additions and 16 deletions

17
build
View File

@ -11,7 +11,8 @@ try {
var child_process = require('child_process');
var fs = require('fs');
var force = ['--force', 'force', '--full', 'full'].includes(process.argv[2]);
var decl = ['--decl', 'decl'].includes(process.argv[2]);
var force = decl || ['--force', 'force', '--full', 'full'].includes(process.argv[2]);
process.chdir(__dirname);
@ -28,16 +29,16 @@ try {
) {
throw new Error("Sucrase version too old");
}
require('./tools/build-utils').transpile(force);
} catch (e) {
console.log('Installing dependencies...');
shell('npm install --production');
// for some reason, sucrase won't be requirable until a tick has passed
// see https://stackoverflow.com/questions/53270058/node-cant-find-certain-modules-after-synchronous-install
setImmediate(() => {
require('./tools/build-utils').transpile(true);
});
shell('npm install' + (decl ? '' : ' --production'));
force = true;
}
// for some reason, sucrase won't be requirable until a tick has passed
// see https://stackoverflow.com/questions/53270058/node-cant-find-certain-modules-after-synchronous-install
setImmediate(() => {
require('./tools/build-utils').transpile(force, decl);
});
// Make sure config.js exists. If not, copy it over synchronously from
// config-example.js, since it's needed before we can start the server

View File

@ -10,6 +10,7 @@
import * as fs from 'fs';
import * as path from 'path';
declare const Config: any;
const CRASH_EMAIL_THROTTLE = 5 * 60 * 1000; // 5 minutes
const LOCKDOWN_PERIOD = 30 * 60 * 1000; // 30 minutes

View File

@ -9,6 +9,7 @@ import * as https from 'https';
import * as http from 'http';
import * as url from 'url';
import * as Streams from './streams';
declare const Config: any;
export interface PostData {
[key: string]: string | number;

View File

@ -13,6 +13,7 @@ import * as net from 'net';
import * as path from 'path';
import * as repl from 'repl';
import {crashlogger} from './crashlogger';
declare const Config: any;
export const Repl = new class {
/**
@ -61,7 +62,8 @@ export const Repl = new class {
* non-global context.
*/
start(filename: string, evalFunction: (input: string) => any) {
if ('repl' in Config && !Config.repl) return;
const config = typeof Config !== 'undefined' ? Config : {};
if (config.repl !== undefined && !config.repl) return;
// TODO: Windows does support the REPL when using named pipes. For now,
// this only supports UNIX sockets.
@ -70,7 +72,7 @@ export const Repl = new class {
if (filename === 'app') {
// Clean up old REPL sockets.
const directory = path.dirname(path.resolve(__dirname, '..', Config.replsocketprefix || 'logs/repl', 'app'));
const directory = path.dirname(path.resolve(__dirname, '..', config.replsocketprefix || 'logs/repl', 'app'));
for (const file of fs.readdirSync(directory)) {
const pathname = path.resolve(directory, file);
const stat = fs.statSync(pathname);

View File

@ -14,6 +14,7 @@ import {State} from './state';
import {BattleQueue, Action} from './battle-queue';
import {BattleActions} from './battle-actions';
import {Utils} from '../lib';
declare const __version: any;
interface BattleOptions {
format?: Format;
@ -228,12 +229,12 @@ export class Battle {
formatid: options.formatid, seed: this.prng.seed,
};
if (this.rated) inputOptions.rated = this.rated;
if (global.__version) {
if (global.__version.head) {
this.inputLog.push(`>version ${global.__version.head}`);
if (typeof __version !== 'undefined') {
if (__version.head) {
this.inputLog.push(`>version ${__version.head}`);
}
if (global.__version.origin) {
this.inputLog.push(`>version-origin ${global.__version.origin}`);
if (__version.origin) {
this.inputLog.push(`>version-origin ${__version.origin}`);
}
}
this.inputLog.push(`>start ` + JSON.stringify(inputOptions));

21
sim/tsconfig.json Normal file
View File

@ -0,0 +1,21 @@
{
"compilerOptions": {
"lib": ["es2019"],
"emitDeclarationOnly": true,
"outDir": "../.sim-dist",
"declaration": true,
"target": "esnext",
"module": "commonjs",
"moduleResolution": "node",
"strict": true,
"allowJs": true,
"checkJs": true,
"incremental": true,
"allowUnreachableCode": false
},
"types": ["node"],
"include": [
"./global-types.ts",
"./index.ts",
]
}

View File

@ -3,6 +3,7 @@
const {transform} = require("sucrase");
const fs = require("fs");
const path = require("path");
const child_process = require("child_process");
let force = false;
@ -190,7 +191,7 @@ function copyOverDataJSON(file) {
});
}
exports.transpile = (doForce) => {
exports.transpile = (doForce, decl) => {
if (doForce) force = true;
if (sucrase('./config', './.config-dist')) {
replace('.config-dist', [
@ -252,4 +253,19 @@ exports.transpile = (doForce) => {
copyOverDataJSON('mods/gen6/factory-sets.json');
// NOTE: replace is asynchronous - add additional replacements for the same path in one call instead of making multiple calls.
if (decl) {
exports.buildDecls();
}
};
exports.buildDecls = () => {
try {
child_process.execSync(`node ./node_modules/typescript/bin/tsc -p sim`, {stdio: 'inherit'});
} catch (e) {}
for (const file of fs.readdirSync(`./.sim-dist/lib/`)) {
fs.renameSync(`./.sim-dist/lib/${file}`, `./.lib-dist/${file}`);
}
for (const file of fs.readdirSync(`./.sim-dist/sim/`)) {
fs.renameSync(`./.sim-dist/sim/${file}`, `./.sim-dist/${file}`);
}
};