diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..9922d9a --- /dev/null +++ b/.eslintignore @@ -0,0 +1,9 @@ +# Exclude these folders from linting +node_modules +dist/ +types/ + +# Exclude these filetypes from linting +*.json +*.txt +*.exe \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..c505160 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,75 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/no-unused-vars": 1, + "@typescript-eslint/no-empty-interface": 0, + "@typescript-eslint/no-namespace": 0, + "@typescript-eslint/comma-dangle": 1, + "@typescript-eslint/func-call-spacing": 2, + "@typescript-eslint/quotes": 1, + "@typescript-eslint/brace-style": [ + "warn", + "allman" + ], + "@typescript-eslint/naming-convention": [ + "warn", + { + "selector": "default", + "format": ["camelCase"], + "leadingUnderscore": "allow" + }, + { + "selector": "typeLike", + "format": ["PascalCase"] + }, + { + "selector": "objectLiteralProperty", + "format": ["PascalCase", "camelCase"], + "leadingUnderscore": "allow" + }, + { + "selector": "typeProperty", + "format": ["PascalCase", "camelCase"], + "leadingUnderscore": "allow" + }, + { + "selector": "enumMember", + "format": ["UPPER_CASE"] + } + ], + "@typescript-eslint/indent": [ + "warn", + 4 + ], + "@typescript-eslint/no-unused-expressions": [ + "warn", + { + "allowShortCircuit": false, + "allowTernary": false + } + ], + "@typescript-eslint/keyword-spacing": [ + "warn", + { + "before": true, + "after": true + } + ], + "@typescript-eslint/explicit-module-boundary-types": [ + "warn", + { + "allowArgumentsExplicitlyTypedAsAny": true + } + ] + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..9342d21 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "LogToConsole", + "version": "1.0.0", + "main": "src/mod.js", + "license": "MIT", + "author": "Chomp", + "akiVersion": "3.4.1", + "scripts": { + "setup": "npm i", + "build": "node ./packageBuild.ts" + }, + "devDependencies": { + "@types/node": "16.18.10", + "@typescript-eslint/eslint-plugin": "5.46.1", + "@typescript-eslint/parser": "5.46.1", + "bestzip": "2.2.1", + "eslint": "8.30.0", + "fs-extra": "11.1.0", + "glob": "8.0.3", + "tsyringe": "4.7.0", + "typescript": "4.9.4" + } +} diff --git a/packageBuild.ts b/packageBuild.ts new file mode 100644 index 0000000..c829979 --- /dev/null +++ b/packageBuild.ts @@ -0,0 +1,72 @@ +#!/usr/bin/env node + +// This is a simple script used to build a mod package. The script will copy necessary files to the build directory +// and compress the build directory into a zip file that can be easily shared. + +const fs = require("fs-extra"); +const glob = require("glob"); +const zip = require('bestzip'); +const path = require("path"); + +// Load the package.json file to get some information about the package so we can name things appropriately. This is +// atypical, and you would never do this in a production environment, but this script is only used for development so +// it's fine in this case. Some of these values are stored in environment variables, but those differ between node +// versions; the 'author' value is not available after node v14. +const { author, name:packageName, version } = require("./package.json"); + +// Generate the name of the package, stripping out all non-alphanumeric characters in the 'author' and 'name'. +const modName = `${author.replace(/[^a-z0-9]/gi, "")}-${packageName.replace(/[^a-z0-9]/gi, "")}-${version}`; +console.log(`Generated package name: ${modName}`); + +// Delete the old build directory and compressed package file. +fs.rmSync(`${__dirname}/dist`, { force: true, recursive: true }); +console.log("Previous build files deleted."); + +// Generate a list of files that should not be copied over into the distribution directory. This is a blacklist to ensure +// we always copy over additional files and directories that authors may have added to their project. This may need to be +// expanded upon by the mod author to allow for node modules that are used within the mod; example commented out below. +const ignoreList = [ + "node_modules/", + // "node_modules/!(weighted|glob)", // Instead of excluding the entire node_modules directory, allow two node modules. + "src/**/*.js", + "types/", + ".git/", + ".gitea/", + ".eslintignore", + ".eslintrc.json", + ".gitignore", + ".DS_Store", + "packageBuild.ts", + "mod.code-workspace", + "package-lock.json", + "tsconfig.json" +]; +const exclude = glob.sync(`{${ignoreList.join(",")}}`, { realpath: true, dot: true }); + +// For some reason these basic-bitch functions won't allow us to copy a directory into itself, so we have to resort to +// using a temporary directory, like an idiot. Excuse the normalize spam; some modules cross-platform, some don't... +fs.copySync(__dirname, path.normalize(`${__dirname}/../~${modName}`), {filter:(filePath) => +{ + return !exclude.includes(filePath); +}}); +fs.moveSync(path.normalize(`${__dirname}/../~${modName}`), path.normalize(`${__dirname}/${modName}`), { overwrite: true }); +fs.copySync(path.normalize(`${__dirname}/${modName}`), path.normalize(`${__dirname}/dist`)); +console.log("Build files copied."); + +// Compress the files for easy distribution. The compressed file is saved into the dist directory. When uncompressed we +// need to be sure that it includes a directory that the user can easily copy into their game mods directory. +zip({ + source: modName, + destination: `dist/${modName}.zip`, + cwd: __dirname +}).catch(function(err) +{ + console.error("A bestzip error has occurred: ", err.stack); +}).then(function() +{ + console.log(`Compressed mod package to: /dist/${modName}.zip`); + + // Now that we're done with the compression we can delete the temporary build directory. + fs.rmSync(`${__dirname}/${modName}`, { force: true, recursive: true }); + console.log("Build successful! your zip file has been created and is ready to be uploaded to hub.sp-tarkov.com/files/"); +}); \ No newline at end of file diff --git a/src/mod.ts b/src/mod.ts new file mode 100644 index 0000000..43ffdd0 --- /dev/null +++ b/src/mod.ts @@ -0,0 +1,22 @@ +import { DependencyContainer } from "tsyringe"; +import { IPreAkiLoadMod } from "@spt-aki/models/external/IPreAkiLoadMod"; +import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; +import { LogTextColor } from "@spt-aki/models/spt/logging/LogTextColor"; +import { LogBackgroundColor } from "@spt-aki/models/spt/logging/LogBackgroundColor"; + +class Mod implements IPreAkiLoadMod +{ + // Code added here will load BEFORE the server has started loading + preAkiLoad(container: DependencyContainer): void + { + // get the logger from the server container + const logger = container.resolve("WinstonLogger"); + + logger.info("I am logging info!"); + logger.warning("I am logging a warning!"); + logger.error("I am logging an error!"); + logger.logWithColor("I am logging with color!", LogTextColor.YELLOW, LogBackgroundColor.RED); + } +} + +module.exports = { mod: new Mod() } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..8151310 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "allowJs": true, + "module": "CommonJS", + "target": "es2020", + "moduleResolution": "node", + "esModuleInterop": true, + "downlevelIteration": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "resolveJsonModule": true, + "outDir": "tmp", + "baseUrl": ".", + "paths": { + "@spt-aki/*": ["./types/*"] + } + }, + "lib": [ + "es2020" + ], + "include": [ + "src/*", + "src/**/*" + ] +} \ No newline at end of file