Begin work on new structure resolvers.

This commit is contained in:
Daniel Scalzi
2019-08-21 22:25:11 -04:00
parent b942f4df59
commit 2bbf732d8e
12 changed files with 413 additions and 87 deletions

64
package-lock.json generated
View File

@@ -24,16 +24,25 @@
"js-tokens": "^4.0.0" "js-tokens": "^4.0.0"
} }
}, },
"@types/fs-extra": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.0.tgz",
"integrity": "sha512-bCtL5v9zdbQW86yexOlXWTEGvLNqWxMFyi7gQA7Gcthbezr2cPSOb8SkESVKA937QD5cIwOFLDFt0MQoXOEr9Q==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/node": { "@types/node": {
"version": "12.6.8", "version": "12.7.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.8.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz",
"integrity": "sha512-aX+gFgA5GHcDi89KG5keey2zf0WfZk/HAQotEamsK2kbey+8yGKcson0hbK8E+v0NArlCJQCqMP161YhV6ZXLg==", "integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==",
"dev": true "dev": true
}, },
"@types/yargs": { "@types/yargs": {
"version": "13.0.0", "version": "13.0.2",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.2.tgz",
"integrity": "sha512-hY0o+kcz9M6kH32NUeb6VURghqMuCVkiUx+8Btsqhj4Hhov/hVGUx9DmBJeIkzlp1uAQK4wngQBCjqWdUUkFyA==", "integrity": "sha512-lwwgizwk/bIIU+3ELORkyuOgDjCh7zuWDFqRtPPhhVgq9N1F7CvLNKg1TX4f2duwtKQ0p044Au9r1PLIXHrIzQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/yargs-parser": "*" "@types/yargs-parser": "*"
@@ -174,9 +183,9 @@
"dev": true "dev": true
}, },
"esutils": { "esutils": {
"version": "2.0.2", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true "dev": true
}, },
"find-up": { "find-up": {
@@ -321,9 +330,9 @@
} }
}, },
"p-limit": { "p-limit": {
"version": "2.2.0", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
"integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
"requires": { "requires": {
"p-try": "^2.0.0" "p-try": "^2.0.0"
} }
@@ -369,27 +378,27 @@
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
}, },
"resolve": { "resolve": {
"version": "1.11.1", "version": "1.12.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
"integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
"dev": true, "dev": true,
"requires": { "requires": {
"path-parse": "^1.0.6" "path-parse": "^1.0.6"
} }
}, },
"rimraf": { "rimraf": {
"version": "2.6.3", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==",
"dev": true, "dev": true,
"requires": { "requires": {
"glob": "^7.1.3" "glob": "^7.1.3"
} }
}, },
"semver": { "semver": {
"version": "5.7.0", "version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true "dev": true
}, },
"set-blocking": { "set-blocking": {
@@ -437,9 +446,9 @@
"dev": true "dev": true
}, },
"tslint": { "tslint": {
"version": "5.18.0", "version": "5.19.0",
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.18.0.tgz", "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.19.0.tgz",
"integrity": "sha512-Q3kXkuDEijQ37nXZZLKErssQVnwCV/+23gFEMROi8IlbaBG6tXqLPQJ5Wjcyt/yHPKBC+hD5SzuGaMora+ZS6w==", "integrity": "sha512-1LwwtBxfRJZnUvoS9c0uj8XQtAnyhWr9KlNvDIdB+oXyT+VpsOAaEhEgKi1HrZ8rq0ki/AAnbGSv4KM6/AfVZw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.0.0", "@babel/code-frame": "^7.0.0",
@@ -504,11 +513,12 @@
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
}, },
"yargs": { "yargs": {
"version": "13.3.0", "version": "14.0.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.0.0.tgz",
"integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", "integrity": "sha512-ssa5JuRjMeZEUjg7bEL99AwpitxU/zWGAGpdj0di41pOEmJti8NR6kyUIJBkR78DTYNPZOU08luUo0GTHuB+ow==",
"requires": { "requires": {
"cliui": "^5.0.0", "cliui": "^5.0.0",
"decamelize": "^1.2.0",
"find-up": "^3.0.0", "find-up": "^3.0.0",
"get-caller-file": "^2.0.1", "get-caller-file": "^2.0.1",
"require-directory": "^2.1.1", "require-directory": "^2.1.1",

View File

@@ -26,15 +26,16 @@
}, },
"homepage": "https://github.com/dscalzi/Nebula#readme", "homepage": "https://github.com/dscalzi/Nebula#readme",
"devDependencies": { "devDependencies": {
"@types/node": "^12.6.8", "@types/fs-extra": "^8.0.0",
"@types/yargs": "^13.0.0", "@types/node": "^12.7.2",
"rimraf": "^2.6.3", "@types/yargs": "^13.0.2",
"tslint": "^5.18.0", "rimraf": "^3.0.0",
"tslint": "^5.19.0",
"typescript": "^3.5.3" "typescript": "^3.5.3"
}, },
"dependencies": { "dependencies": {
"adm-zip": "^0.4.13", "adm-zip": "^0.4.13",
"fs-extra": "^8.1.0", "fs-extra": "^8.1.0",
"yargs": "^13.3.0" "yargs": "^14.0.0"
} }
} }

View File

@@ -1,6 +1,8 @@
/* tslint:disable:no-shadowed-variable */ /* tslint:disable:no-shadowed-variable */
import { resolve } from 'path' import { writeFile } from 'fs-extra'
import { resolve as resolvePath } from 'path'
import yargs from 'yargs' import yargs from 'yargs'
import { DistributionStructure } from './model/struct/distribution.struct'
function rootOption(yargs: yargs.Argv) { function rootOption(yargs: yargs.Argv) {
return yargs.option('root', { return yargs.option('root', {
@@ -10,7 +12,29 @@ function rootOption(yargs: yargs.Argv) {
global: true global: true
}) })
.coerce({ .coerce({
root: resolve root: resolvePath
})
}
function baseUrlOption(yargs: yargs.Argv) {
return yargs.option('baseUrl', {
describe: 'Base url of your file host.',
type: 'string',
demandOption: true,
global: true
})
.coerce({
baseUrl: (arg: string) => {
// Users must provide protocol in all other instances.
if (arg.indexOf('//') === -1) {
if (arg.toLowerCase().startsWith('localhost')) {
arg = 'http://' + arg
} else {
throw new TypeError('Please provide a URL protocol (ex. http:// or https://)')
}
}
return (new URL(arg)).toString()
}
}) })
} }
@@ -32,9 +56,15 @@ const initRootCommand: yargs.CommandModule = {
yargs = rootOption(yargs) yargs = rootOption(yargs)
return yargs return yargs
}, },
handler: (argv) => { handler: async (argv) => {
console.log(`Root set to ${argv.root}`) console.debug(`Root set to ${argv.root}`)
console.log('Invoked init root.') console.debug('Invoked init root.')
try {
await new DistributionStructure(argv.root as string, '').init()
console.log(`Successfully created new root at ${argv.root}`)
} catch (error) {
console.error(`Failed to init new root at ${argv.root}`, error)
}
} }
} }
@@ -80,8 +110,8 @@ const generateServerCommand: yargs.CommandModule = {
}) })
}, },
handler: (argv) => { handler: (argv) => {
console.log(`Root set to ${argv.root}`) console.debug(`Root set to ${argv.root}`)
console.log(`Generating server ${argv.id} for Minecraft ${argv.version}.`, console.debug(`Generating server ${argv.id} for Minecraft ${argv.version}.`,
`\n\t├ Include forge: ${argv.forge}`, `\n\t├ Include forge: ${argv.forge}`,
`\n\t└ Include liteloader: ${argv.liteloader}`) `\n\t└ Include liteloader: ${argv.liteloader}`)
} }
@@ -92,12 +122,22 @@ const generateDistroCommand: yargs.CommandModule = {
describe: 'Generate a distribution index from the root file structure.', describe: 'Generate a distribution index from the root file structure.',
builder: (yargs) => { builder: (yargs) => {
yargs = rootOption(yargs) yargs = rootOption(yargs)
yargs = baseUrlOption(yargs)
yargs = namePositional(yargs) yargs = namePositional(yargs)
return yargs return yargs
}, },
handler: (argv) => { handler: async (argv) => {
console.log(`Root set to ${argv.root}`) console.debug(`Root set to ${argv.root}`)
console.log(`Invoked generate distro name ${argv.name}.json.`) console.debug(`Base Url set to ${argv.baseUrl}`)
console.debug(`Invoked generate distro name ${argv.name}.json.`)
try {
const distributionStruct = new DistributionStructure(argv.root as string, argv.baseUrl as string)
const distro = await distributionStruct.getSpecModel()
writeFile(resolvePath(argv.root as string, `${argv.name}.json`), JSON.stringify(distro, null, 2))
console.log(distro)
} catch (error) {
console.error(`Failed to generate distribution with root ${argv.root}.`, error)
}
} }
} }
@@ -122,7 +162,7 @@ const validateCommand: yargs.CommandModule = {
return namePositional(yargs) return namePositional(yargs)
}, },
handler: (argv) => { handler: (argv) => {
console.log(`Invoked validate with name ${argv.name}.json`) console.debug(`Invoked validate with name ${argv.name}.json`)
} }
} }

View File

@@ -1,45 +1,58 @@
export const Types: {[property: string]: Type} = { export enum Type {
Library = 'Library',
ForgeHosted = 'ForgeHosted',
Forge = 'Forge',
LiteLoader = 'LiteLoader',
ForgeMod = 'ForgeMod',
LiteMod = 'LiteMod',
File = 'File',
VersionManifest = 'VersionManifest'
}
export interface TypeMetadata {
id: string
defaultExtension?: string
}
export const TypeMetadata: {[property: string]: TypeMetadata} = {
Library: { Library: {
id: 'Library', id: Type.Library,
defaultExtension: 'jar' defaultExtension: 'jar'
}, },
/** /**
* @deprecated Will be replaced by Types.Forge. * @deprecated Will be replaced by Types.Forge.
*/ */
ForgeHosted: { ForgeHosted: {
id: 'ForgeHosted', id: Type.ForgeHosted,
defaultExtension: 'jar' defaultExtension: 'jar'
}, },
Forge: { Forge: {
id: 'Forge', id: Type.Forge,
defaultExtension: 'jar' defaultExtension: 'jar'
}, },
LiteLoader: { LiteLoader: {
id: 'LiteLoader', id: Type.LiteLoader,
defaultExtension: 'jar' defaultExtension: 'jar'
}, },
ForgeMod: { ForgeMod: {
id: 'ForgeMod', id: Type.ForgeMod,
defaultExtension: 'jar' defaultExtension: 'jar'
}, },
LiteMod: { LiteMod: {
id: 'LiteMod', id: Type.LiteMod,
defaultExtension: 'litemod' defaultExtension: 'litemod'
}, },
File: { File: {
id: 'File' id: Type.File
}, },
VersionManifest: { VersionManifest: {
id: 'VersionManifest', id: Type.VersionManifest,
defaultExtension: 'json' defaultExtension: 'json'
} }
} }
export interface Type {
id: string
defaultExtension?: string
}

View File

@@ -0,0 +1,26 @@
import { mkdirs } from 'fs-extra'
import { join, resolve } from 'path'
import { ModelStructure } from './model.struct'
export abstract class BaseModelStructure<T> implements ModelStructure<T[]> {
protected resolvedModels: T[] | undefined
protected containerDirectory: string
constructor(
protected absoluteRoot: string,
protected relativeRoot: string,
protected structRoot: string,
protected baseUrl: string
) {
this.relativeRoot = join(relativeRoot, structRoot)
this.containerDirectory = resolve(absoluteRoot, structRoot)
}
public async init() {
mkdirs(this.containerDirectory)
}
public abstract async getSpecModel(): Promise<T[]>
}

View File

@@ -1,25 +1,32 @@
import { mkdirs } from 'fs-extra'
import { Distribution } from '../spec/distribution' import { Distribution } from '../spec/distribution'
import { ModelStructure } from './model.struct' import { ModelStructure } from './model.struct'
import { ServerStructure } from './server.struct' import { ServerStructure } from './server.struct'
export class DistributionStructure implements ModelStructure<Distribution> { export class DistributionStructure implements ModelStructure<Distribution> {
private servers: ServerStructure[] | undefined private serverStruct: ServerStructure
constructor( constructor(
private root: string private absoluteRoot: string,
) {} private baseUrl: string
) {
public getServers() { this.serverStruct = new ServerStructure(this.absoluteRoot, this.baseUrl)
return new ServerStructure(this.root).getSpecModel()
} }
public getSpecModel(): Distribution { public async init() {
return { await mkdirs(this.absoluteRoot)
version: '1.0.0', await this.serverStruct.init()
rss: 'TODO', }
servers: this.getServers()
} public async getSpecModel() {
return new Promise(async (resolve) => {
resolve({
version: '1.0.0',
rss: '<FILL IN MANUALLY>',
servers: await this.serverStruct.getSpecModel()
})
}) as Promise<Distribution>
} }
} }

View File

@@ -1,5 +1,7 @@
export interface ModelStructure<T> { export interface ModelStructure<T> {
getSpecModel(): T init(): void
getSpecModel(): Promise<T>
} }

View File

@@ -0,0 +1,28 @@
import { Stats } from 'fs'
import { Type } from '../../spec/type'
import { ModuleStructure } from './module.struct'
export class FileStructure extends ModuleStructure {
constructor(
absoluteRoot: string,
relativeRoot: string,
baseUrl: string
) {
super(absoluteRoot, relativeRoot, 'files', baseUrl, Type.File)
}
protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return name
}
protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return name
}
protected async getModuleUrl(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return 'TODO'
}
protected async getModulePath(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return 'TODO'
}
}

View File

@@ -0,0 +1,28 @@
import { Stats } from 'fs-extra'
import { Type } from '../../spec/type'
import { ModuleStructure } from './module.struct'
export class ForgeModStructure extends ModuleStructure {
constructor(
absoluteRoot: string,
relativeRoot: string,
baseUrl: string
) {
super(absoluteRoot, relativeRoot, 'forgemods', baseUrl, Type.ForgeMod)
}
protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return name
}
protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return name
}
protected async getModuleUrl(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return 'TODO'
}
protected async getModulePath(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return 'TODO'
}
}

View File

@@ -0,0 +1,29 @@
import { Stats } from 'fs-extra'
import { join } from 'path'
import { Type } from '../../spec/type'
import { ModuleStructure } from './module.struct'
export class LiteModStructure extends ModuleStructure {
constructor(
absoluteRoot: string,
relativeRoot: string,
baseUrl: string
) {
super(absoluteRoot, relativeRoot, 'litemods', baseUrl, Type.LiteMod)
}
protected async getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return name
}
protected async getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return name
}
protected async getModuleUrl(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return 'TODO'
}
protected async getModulePath(name: string, path: string, stats: Stats, buf: Buffer): Promise<string> {
return 'TODO'
}
}

View File

@@ -0,0 +1,67 @@
import { createHash } from 'crypto'
import { lstat, pathExists, readdir, readFile, Stats } from 'fs-extra'
import { resolve } from 'path'
import { Module } from '../../spec/module'
import { Type } from '../../spec/type'
import { BaseModelStructure } from '../basemodel.struct'
export abstract class ModuleStructure extends BaseModelStructure<Module> {
constructor(
absoluteRoot: string,
relativeRoot: string,
structRoot: string,
baseUrl: string,
protected type: Type
) {
super(absoluteRoot, relativeRoot, structRoot, baseUrl)
}
public async getSpecModel(): Promise<Module[]> {
if (this.resolvedModels == null) {
this.resolvedModels = await this._doModuleRetrieval()
}
return this.resolvedModels
}
protected async abstract getModuleId(name: string, path: string, stats: Stats, buf: Buffer): Promise<string>
protected async abstract getModuleName(name: string, path: string, stats: Stats, buf: Buffer): Promise<string>
protected async abstract getModuleUrl(name: string, path: string, stats: Stats, buf: Buffer): Promise<string>
protected async abstract getModulePath(name: string, path: string, stats: Stats, buf: Buffer): Promise<string>
private async _doModuleRetrieval(): Promise<Module[]> {
const accumulator: Module[] = []
if (await pathExists(this.containerDirectory)) {
const files = await readdir(this.containerDirectory)
for (const file of files) {
const filePath = resolve(this.containerDirectory, file)
const stats = await lstat(filePath)
const buf = await readFile(filePath)
if (stats.isFile()) {
accumulator.push({
id: await this.getModuleId(file, filePath, stats, buf),
name: await this.getModuleName(file, filePath, stats, buf),
type: this.type,
required: {
value: false,
def: false
},
artifact: {
size: stats.size,
MD5: createHash('md5').update(buf).digest('hex'),
url: await this.getModuleUrl(file, filePath, stats, buf),
path: await this.getModulePath(file, filePath, stats, buf)
}
})
}
}
}
return accumulator
}
}

View File

@@ -1,25 +1,100 @@
import { resolve } from 'path' import { lstat, readdir } from 'fs-extra'
import { join, resolve as resolvePath } from 'path'
import { resolve as resolveUrl } from 'url'
import { Server } from '../spec/server' import { Server } from '../spec/server'
import { ModelStructure } from './model.struct' import { BaseModelStructure } from './basemodel.struct'
import { FileStructure } from './module/file.struct'
import { ForgeModStructure } from './module/forgemod.struct'
import { LiteModStructure } from './module/litemod.struct'
export class ServerStructure implements ModelStructure<Server[]> { export class ServerStructure extends BaseModelStructure<Server> {
private servers: Server[] | undefined private readonly ID_REGEX = /(.+-(.+)$)/
constructor( constructor(
private root: string absoluteRoot: string,
) {} baseUrl: string
) {
public getSpecModel(): Server[] { super(absoluteRoot, '', 'servers', baseUrl)
if (this.servers == null) {
this.servers = this._doSeverRetrieval()
}
return this.servers
} }
private _doSeverRetrieval(): Server[] { public async getSpecModel() {
const base = resolve(this.root, 'servers') if (this.resolvedModels == null) {
return [] // TODO this.resolvedModels = await this._doSeverRetrieval()
}
return this.resolvedModels
}
private async _doSeverRetrieval(): Promise<Server[]> {
const accumulator: Server[] = []
const files = await readdir(this.containerDirectory)
for (const file of files) {
const absoluteServerRoot = resolvePath(this.containerDirectory, file)
const relativeServerRoot = join(this.relativeRoot, file)
if ((await lstat(absoluteServerRoot)).isDirectory()) {
const match = this.ID_REGEX.exec(file)
if (match == null) {
console.warn(`Server directory ${file} does not match the defined standard.`)
console.warn(`All server ids must end with -<minecraft version> (ex. -1.12.2)`)
continue
}
let iconUrl
// Resolve server icon
const subFiles = await readdir(absoluteServerRoot)
for (const subFile of subFiles) {
const caseInsensitive = subFile.toLowerCase()
if (caseInsensitive.endsWith('.jpg') || caseInsensitive.endsWith('.png')) {
iconUrl = resolveUrl(this.baseUrl, join(relativeServerRoot, subFile))
}
}
if (!iconUrl) {
console.warn(`No icon file found for server ${file}.`)
iconUrl = '<FILL IN MANUALLY>'
}
const forgeModStruct = new ForgeModStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl)
const forgeModModules = await forgeModStruct.getSpecModel()
const liteModStruct = new LiteModStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl)
const liteModModules = await liteModStruct.getSpecModel()
const fileStruct = new FileStructure(absoluteServerRoot, relativeServerRoot, this.baseUrl)
const fileModules = await fileStruct.getSpecModel()
const modules = [
...forgeModModules,
...liteModModules,
...fileModules
]
accumulator.push({
id: match[1],
name: '<FILL IN MANUALLY>',
description: '<FILL IN MANUALLY>',
icon: iconUrl,
version: '1.0.0',
address: '<FILL IN MANUALLY>',
minecraftVersion: match[2],
discord: {
shortId: '<FILL IN MANUALLY OR REMOVE>',
largeImageText: '<FILL IN MANUALLY OR REMOVE>',
largeImageKey: '<FILL IN MANUALLY OR REMOVE>'
},
mainServer: false,
autoconnect: false,
modules
})
} else {
console.warn(`Path ${file} in server directory is not a directory!`)
}
}
return accumulator
} }
} }