typescript

This commit is contained in:
2021-02-07 16:00:39 +01:00
parent d53d19bb4d
commit 16adeee59f
9 changed files with 233 additions and 64 deletions

1
.gitignore vendored
View File

@ -111,3 +111,4 @@ dist
/mods
/mods-lock.json
/mods.json
build

78
package-lock.json generated
View File

@ -4,6 +4,36 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/node": {
"version": "14.14.25",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.25.tgz",
"integrity": "sha512-EPpXLOVqDvisVxtlbvzfyqSsFeQxltFbluZNRndIb8tr9KiBnYNLzrc1N3pyKUCww2RNrfHDViqDWWE1LCJQtQ==",
"dev": true
},
"arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
},
"create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
"flex-exec": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/flex-exec/-/flex-exec-1.0.0.tgz",
@ -36,15 +66,63 @@
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
},
"make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"node-json-minify": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-json-minify/-/node-json-minify-1.0.0.tgz",
"integrity": "sha1-e7NDL5ZYtr6x2ZP9XVOzyinQ15w="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-support": {
"version": "0.5.19",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"ts-node": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
"integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==",
"dev": true,
"requires": {
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"source-map-support": "^0.5.17",
"yn": "3.1.1"
}
},
"typescript": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
"integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==",
"dev": true
},
"underscore": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.0.tgz",
"integrity": "sha512-21rQzss/XPMjolTiIezSu3JAjgagXKROtNrYFEOWK109qY1Uv2tVjPTZ1ci2HgvQDA16gHYSthQIJfB+XId/rQ=="
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true
}
}
}

View File

@ -17,5 +17,10 @@
"gift": "^0.10.2",
"gradle-to-js": "^2.0.0",
"node-json-minify": "^1.0.0"
},
"devDependencies": {
"@types/node": "^14.14.25",
"ts-node": "^9.1.1",
"typescript": "^4.1.3"
}
}

View File

@ -1,14 +1,25 @@
const { http, https } = require('follow-redirects');
const fs = require("fs");
const util = require("./util.js");
let mods_lock;
let downloadStarted = false;
let dep = new Map();
import { https } from "follow-redirects";
import fs from "fs";
interface modLockElement {
fileId: number;
url: string;
filename: string;
}
type modLockMap = Map<string, modLockElement>;
interface Dependency {
readonly addonId: number;
readonly type: number;
}
let mods_lock: modLockMap;
let downloadStarted: boolean = false;
let globCallback;
let config;
let dep: modLockMap = new Map();
function main() {
mods_lock = new Map(Object.entries(mods_lock));
if(global.config.mods.curse.length === 0) globCallback("curse", {});
global.config.mods.curse.forEach(mod => {
getData(`search?categoryId=0&gameId=432&gameVersion=${encodeURI(global.config.gameVersion)}&index=0&pageSize=15&searchFilter=${encodeURI(mod)}&sectionId=6&sort=0`, (result) => { // resolve projectID
if(config.mods.curse.length === 0) globCallback("curse", {});
config.mods.curse.forEach((mod: string) => {
getData(`search?categoryId=0&gameId=432&gameVersion=${encodeURI(config.gameVersion)}&index=0&pageSize=15&searchFilter=${encodeURI(mod)}&sectionId=6&sort=0`, (result: Array<any>) => { // resolve projectID
let i = 0;
while(result[i].name !== mod) {
++i;
@ -23,24 +34,24 @@ function main() {
}
var resolveDepRecursionCount = 0;
function resolveDep(modId, callback) {
function resolveDep(modId: number, callback: Function) {
++resolveDepRecursionCount;
getData(`${modId}/files`, (files) => {
let rightVersion;
getData(`${modId}/files`, (files: Array<any>) => {
let rightVersion: any;
for(let i = files.length - 1; i >= 0; --i) {
let versionArray = files[i].gameVersion;
if(versionMatch(versionArray, global.config.gameVersion) && (versionMatch(versionArray, global.config.modloader) || modloaderMatch(versionArray, global.config.modloader))) {
if(versionMatch(versionArray, config.gameVersion) && (versionMatch(versionArray, config.modloader) || modloaderMatch(versionArray, config.modloader))) {
rightVersion = files[i];
}
}
if(rightVersion === undefined) {
getData(modId, (mod) => {
getData(String(modId), (mod: any) => {
console.log(`cursemod ${mod.name}: no version for the correct minecraft version and modloader found`);
});
return;
}
dep.set(String(modId), {fileId: rightVersion.id, url: rightVersion.downloadUrl, filename: rightVersion.fileName});
rightVersion.dependencies.forEach(mod => {
rightVersion.dependencies.forEach((mod: Dependency) => {
if(mod.type !== 3) return;
resolveDep(mod.addonId, callback);
});
@ -49,9 +60,9 @@ function resolveDep(modId, callback) {
});
}
function getData(url, callback) {
function getData(url: string, callback: Function) {
https.get(`https://addons-ecs.forgesvc.net/api/v2/addon/${url}`, (resp) => {
let data = '';
let data: string = '';
resp.on('data', (chunk) => {
data += chunk;
});
@ -80,24 +91,21 @@ function downloadMods() {
if(!downloadStarted) {
downloadStarted = true;
globCallback("curse", Object.fromEntries(dep));
dep.forEach((mod, modId) => {
let path = getPath(mod)
dep.forEach((mod: modLockElement, modId: string) => {
let path = modPath(mod)
if(mods_lock.has(modId)) {
if(mods_lock.get(modId).fileId === mod.fileId) return;
if(mods_lock.get(modId)!.fileId === mod.fileId) return;
fs.unlink(path, () => {});
}
downloadFile(mod.url, path);
});
mods_lock.forEach((mod, modId) => {
if(!dep.has(modId)) fs.unlink(getPath(mod), () => {})
mods_lock.forEach((mod: modLockElement, modId: string) => {
if(!dep.has(modId)) fs.unlink(modPath(mod), () => {})
});
}
}
function getPath(mod) {
return `mods/${mod.filename}`
}
function downloadFile(url, dest) {
function downloadFile(url: string, dest: string) {
let file = fs.createWriteStream(dest);
console.log(`downloading ${url}`);
let request = https.get(url, (response) => {
@ -113,19 +121,20 @@ function downloadFile(url, dest) {
file.on('finish', () => file.close());
// check for request error too
request.on('error', (err) => {
request.on('error', (err: Error) => {
fs.unlink(dest, () => {});
throw err;
});
file.on('error', (err) => { // Handle errors
file.on('error', (err: Error) => { // Handle errors
fs.unlink(dest, () => {});
throw err;
});
}
module.exports = function(mods_lock_p, callback) {
module.exports = function(mods_lock_p, _config, callback) {
mods_lock = mods_lock_p;
globCallback = callback;
config = _config;
main();
};

View File

@ -1,18 +1,27 @@
const git = require("gift");
const childProcess = require("child_process");
const fs = require("fs");
const g2js = require('gradle-to-js/lib/parser');
const util = require("./util.js");
let modsLock;
let globCallback;
let loopCounter = 0;
import git from "gift";
import childProcess from "child_process";
import fs from "fs";
import g2js from "gradle-to-js/lib/parser";
interface modLockElement {
commitId: string;
url: string;
filename: string;
}
type modLockMap = Map<string, modLockElement>;
interface commit {
id: string;
}
let modsLock: modLockMap;
let globCallback: Function;
let loopCounter: number = 0;
let config;
function main () {
modsLock = new Map(Object.entries(modsLock));
let deleteMods = new Map(modsLock);
let deleteMods: modLockMap = new Map(modsLock);
let cacheDir = process.env.XDG_CACHE_HOME;
if(cacheDir == null) cacheDir = `${process.env.HOME}/.cache`;
let repoPathRoot = `${cacheDir}/minecraft-mod-packager`;
global.config.mods.git.forEach((gitRepo) => {
config.mods.git.forEach((gitRepo) => {
++loopCounter;
deleteMods.delete(gitRepo.url);
let repoPath = `${repoPathRoot}/${gitRepo.url.replace("://", "+")}/${gitRepo.branch}`;
@ -20,7 +29,7 @@ function main () {
if(err) {
if(err.code !== "ENOENT") throw err;
console.log(`cloning git repo ${gitRepo.url}`);
git.clone(gitRepo.url, repoPath, undefined, gitRepo.branch, (err, repo) => {
git.clone(gitRepo.url, repoPath, undefined, gitRepo.branch, (err: Error, repo) => {
if(err) throw err;
build(repo, repoPath, gitRepo);
});
@ -28,7 +37,7 @@ function main () {
else {
let repo = git(repoPath);
console.log(`pulling git repo ${gitRepo.url}`);
repo.pull(["origin"], gitRepo.branch, (err) => {
repo.pull(["origin"], gitRepo.branch, (err: Error) => {
if(err) throw err;
build(repo, repoPath, gitRepo);
});
@ -37,20 +46,18 @@ function main () {
});
deleteMods.forEach((mod, url) => {
modsLock.delete(url);
fs.unlink(util.modPath(mod), (err) => {
fs.unlink(modPath(mod), (err) => {
if(err) throw err;
});
});
mayCb();
}
function build(repo, repoPath, gitRepo) {
if(modsLock.has(gitRepo.url)) newLock = modsLock.get(gitRepo.url);
else {
newLock = {};
modsLock.set(gitRepo.url, newLock);
}
repo.current_commit((err, commit) => {
function build(repo, repoPath, gitRepo):void {
let newLock: modLockElement;
newLock = modsLock.get(gitRepo.url) ?? {} as modLockElement;
modsLock.set(gitRepo.url, newLock);
repo.current_commit((err: Error, commit: commit) => {
if(err) throw err;
if(commit.id === newLock.commitId) cbDecrease();
else {
@ -62,11 +69,11 @@ function build(repo, repoPath, gitRepo) {
fs.readFile(`${repoPath}/gradle.properties`, "utf-8", (err, data) => {
if(err) throw err;
g2js.parseText(data).then((gradleProp) => {
if(newLock.filename != null) fs.unlink(util.modPath(newLock), (err) => {
if(newLock.filename != null) fs.unlink(modPath(newLock), (err) => {
if(err) throw err;
});
newLock.filename = `${gradleProp.archives_base_name}-${gradleProp.mod_version}.jar`;
fs.copyFile(`${buildPath}/${newLock.filename}`, util.modPath(newLock), (err) => {
fs.copyFile(`${buildPath}/${newLock.filename}`, modPath(newLock), (err) => {
if(err) throw err;
});
cbDecrease();
@ -77,17 +84,18 @@ function build(repo, repoPath, gitRepo) {
});
}
function cbDecrease() {
function cbDecrease():void {
--loopCounter;
mayCb();
}
function mayCb() {
function mayCb():void {
if(loopCounter <= 0) globCallback("git", Object.fromEntries(modsLock));
}
module.exports = (mods_lock_p, cb) => {
module.exports = (mods_lock_p, _config, cb) => {
globCallback = cb;
modsLock = mods_lock_p;
config = _config;
main()
}

View File

@ -1,10 +1,11 @@
const jsonMinify = require("node-json-minify");
const fs = require("fs");
let config;
switch(process.argv.length) {
case 3:
process.chdir(process.argv[2]);
case 2:
global.config = JSON.parse(jsonMinify(fs.readFileSync("mods.json", "utf-8")));
config = JSON.parse(jsonMinify(fs.readFileSync("mods.json", "utf-8")));
break;
default:
throw "unexpected argument";
@ -21,8 +22,8 @@ catch(err) {
}
const numberCallback = 2;
let callbackCounter = 0;
require("./curse.js")(modsLock.curse, finnish);
require("./git.js")(modsLock.git, finnish);
require("./curse")(modsLock.curse, config, finnish);
require("./git.js")(modsLock.git, config, finnish);
function finnish(name, data) {
save_mods_lock[name] = data;

View File

@ -1,7 +0,0 @@
function modPath(mod) {
return `mods/${mod.filename}`;
}
module.exports = {
modPath: modPath
}

3
src/util.ts Normal file
View File

@ -0,0 +1,3 @@
function modPath(mod: any) {
return `mods/${mod.filename}`;
}

71
tsconfig.json Normal file
View File

@ -0,0 +1,71 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "ES2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
"lib": ["es2020"], /* Specify library files to be included in the compilation. */
"allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "build", /* Redirect output structure to the directory. */
"rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"resolveJsonModule": true, /* Include modules imported with '.json' extension */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
}