diff --git a/.eslintrc.js b/.eslintrc.js index 537f0a6..3c36f62 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -17,4 +17,13 @@ module.exports = { // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs // e.g. "@typescript-eslint/explicit-function-return-type": "off", }, + + overrides: [ + { + files: ['./*.js'], + rules: { + '@typescript-eslint/no-var-requires': 'off', + }, + }, + ], }; diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3f9deaa..db853c5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -46,9 +46,9 @@ build: cache: <<: *global_cache script: | - yarn updateManifest -- --update=${RELEASE_TYPE} + yarn bump-version --release=${RELEASE_TYPE} RELEASE_VERSION=$(jq -r '.version' < package.json) - git add package.json package-lock.json src/module.json + git add package.json src/module.json git --no-pager diff git commit -m "release version ${RELEASE_VERSION}" git tag -f latest diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 6b8762a..27837e0 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,7 +3,6 @@ "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "gruntfuggly.todo-tree", - "eg2.vscode-npm-script", "msjsdiag.debugger-for-chrome", "arcanis.vscode-zipfs" ] diff --git a/README.md b/README.md index 964cd64..d106385 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ the following content: ``` { - "dataPath": "/.local/share/FoundryVTT" + "dataPath": "/.local/share/FoundryVTT/Data" } ``` diff --git a/gulpfile.js b/gulpfile.js index 8cd4cd3..c5215f7 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,41 +1,32 @@ -const gulp = require('gulp'); -const fs = require('fs-extra'); -const path = require('path'); -const chalk = require('chalk'); -const stringify = require('json-stringify-pretty-compact'); -const argv = require('yargs').argv; const { rollup } = require('rollup'); +const argv = require('yargs').argv; +const chalk = require('chalk'); +const fs = require('fs-extra'); +const gulp = require('gulp'); +const path = require('path'); const rollupConfig = require('./rollup.config'); - -function getManifest() { - const json = {}; - - if (fs.existsSync('src')) { - json.root = 'src'; - } else { - json.root = 'dist'; - } - - const modulePath = path.join(json.root, 'module.json'); - - if (fs.existsSync(modulePath)) { - json.file = fs.readJSONSync(modulePath); - json.name = 'module.json'; - } else { - return; - } - - return json; -} +const semver = require('semver'); /********************/ -/* BUILD */ +/* CONFIGURATION */ +/********************/ + +const name = path.basename(path.resolve('.')); +const sourceDirectory = './src'; +const distDirectory = './dist'; +const sourceFileExtension = '.ts'; +const staticFiles = ['module.json']; +const getDownloadURL = (version) => + `https://git.f3l.de/ghost/risk-dice-modifier/-/jobs/artifacts/${version}/download?job=build`; + +/********************/ +/* BUILD */ /********************/ /** - * Build TypeScript + * Build the distributable JavaScript code */ -async function buildTS() { +async function buildCode() { const build = await rollup({ input: rollupConfig.input, plugins: rollupConfig.plugins }); return build.write(rollupConfig.output); } @@ -44,16 +35,10 @@ async function buildTS() { * Copy static files */ async function copyFiles() { - const statics = ['module.json']; - try { - for (const file of statics) { - if (fs.existsSync(path.join('src', file))) { - await fs.copy(path.join('src', file), path.join('dist', file)); - } + for (const file of staticFiles) { + if (fs.existsSync(path.join(sourceDirectory, file))) { + await fs.copy(path.join(sourceDirectory, file), path.join(distDirectory, file)); } - return Promise.resolve(); - } catch (err) { - Promise.reject(err); } } @@ -61,158 +46,146 @@ async function copyFiles() { * Watch for changes for each build step */ function buildWatch() { - gulp.watch('src/**/*.ts', { ignoreInitial: false }, buildTS); - gulp.watch(['src/*.json'], { ignoreInitial: false }, copyFiles); + gulp.watch( + path.join(sourceDirectory, '**', `*${sourceFileExtension}`).replace(/\\/g, '/'), + { ignoreInitial: false }, + buildCode, + ); + gulp.watch( + staticFiles.map((file) => path.join(sourceDirectory, file).replace(/\\/g, '/')), + { ignoreInitial: false }, + copyFiles, + ); } /********************/ -/* CLEAN */ +/* CLEAN */ /********************/ /** - * Remove built files from `dist` folder - * while ignoring source files + * Remove built files from `dist` folder while ignoring source files */ async function clean() { - const name = path.basename(path.resolve('.')); - const files = []; - - // If the project uses TypeScript - if (fs.existsSync(path.join('src', 'module', `${name}.ts`))) { - files.push('module', `${name}.js`, 'module.json'); - } + const files = [...staticFiles, 'module']; console.log(' ', chalk.yellow('Files to clean:')); console.log(' ', chalk.blueBright(files.join('\n '))); - // Attempt to remove the files - try { - for (const filePath of files) { - await fs.remove(path.join('dist', filePath)); - } - return Promise.resolve(); - } catch (err) { - Promise.reject(err); + for (const filePath of files) { + await fs.remove(path.join(distDirectory, filePath)); } } /********************/ -/* LINK */ +/* LINK */ /********************/ +/** + * Get the data path of Foundry VTT based on what is configured in `foundryconfig.json` + */ +function getDataPath() { + const config = fs.readJSONSync('foundryconfig.json'); + + if (config?.dataPath) { + if (!fs.existsSync(path.resolve(config.dataPath))) { + throw new Error('User Data path invalid, no Data directory found'); + } + + return path.resolve(config.dataPath); + } else { + throw new Error('No User Data path defined in foundryconfig.json'); + } +} + /** * Link build to User Data folder */ async function linkUserData() { - const name = path.basename(path.resolve('.')); - const config = fs.readJSONSync('foundryconfig.json'); + let destinationDirectory; + if (fs.existsSync(path.resolve('.', sourceDirectory, 'module.json'))) { + destinationDirectory = 'modules'; + } else { + throw new Error(`Could not find ${chalk.blueBright('module.json')}`); + } - let destDir; - try { - if ( - fs.existsSync(path.resolve('.', 'dist', 'module.json')) || - fs.existsSync(path.resolve('.', 'src', 'module.json')) - ) { - destDir = 'modules'; - } else { - throw Error(`Could not find ${chalk.blueBright('module.json')}`); - } + const linkDirectory = path.resolve(getDataPath(), destinationDirectory, name); - let linkDir; - if (config.dataPath) { - if (!fs.existsSync(path.join(config.dataPath, 'Data'))) - throw Error('User Data path invalid, no Data directory found'); + if (argv.clean || argv.c) { + console.log(chalk.yellow(`Removing build in ${chalk.blueBright(linkDirectory)}.`)); - linkDir = path.join(config.dataPath, 'Data', destDir, name); - } else { - throw Error('No User Data path defined in foundryconfig.json'); - } - - if (argv.clean || argv.c) { - console.log(chalk.yellow(`Removing build in ${chalk.blueBright(linkDir)}`)); - - await fs.remove(linkDir); - } else if (!fs.existsSync(linkDir)) { - console.log(chalk.green(`Copying build to ${chalk.blueBright(linkDir)}`)); - await fs.symlink(path.resolve('./dist'), linkDir); - } - return Promise.resolve(); - } catch (err) { - Promise.reject(err); + await fs.remove(linkDirectory); + } else if (!fs.existsSync(linkDirectory)) { + console.log(chalk.green(`Copying build to ${chalk.blueBright(linkDirectory)}.`)); + await fs.ensureDir(path.resolve(linkDirectory, '..')); + await fs.symlink(path.resolve('.', distDirectory), linkDirectory); } } -/*********************/ -/* PACKAGE */ -/*********************/ +/********************/ +/* VERSIONING */ +/********************/ /** - * Update version and URLs in the manifest JSON + * Get the contents of the manifest file as object. */ -function updateManifest(cb) { +function getManifest() { + const manifestPath = path.join(sourceDirectory, 'module.json'); + + if (fs.existsSync(manifestPath)) { + return { + file: fs.readJSONSync(manifestPath), + name: 'module.json', + }; + } +} + +/** + * Get the target version based on on the current version and the argument passed as release. + */ +function getTargetVersion(currentVersion, release) { + if (['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'].includes(release)) { + return semver.inc(currentVersion, release); + } else { + return semver.valid(release); + } +} + +/** + * Update version and download URL. + */ +function bumpVersion(cb) { const packageJson = fs.readJSONSync('package.json'); - const packageLockJson = fs.readJSONSync('package-lock.json'); const manifest = getManifest(); if (!manifest) cb(Error(chalk.red('Manifest JSON not found'))); try { - const version = argv.update || argv.u; + const release = argv.release || argv.r; - /* Update version */ + const currentVersion = packageJson.version; - const versionMatch = /^(\d{1,}).(\d{1,}).(\d{1,})$/; - const currentVersion = manifest.file.version; - let targetVersion = ''; - - if (!version) { - cb(Error('Missing version number')); + if (!release) { + return cb(Error('Missing release type')); } - if (versionMatch.test(version)) { - targetVersion = version; - } else { - targetVersion = currentVersion.replace(versionMatch, (substring, major, minor, patch) => { - console.log(substring, Number(major) + 1, Number(minor) + 1, Number(patch) + 1); - if (version === 'major') { - return `${Number(major) + 1}.0.0`; - } else if (version === 'minor') { - return `${major}.${Number(minor) + 1}.0`; - } else if (version === 'patch') { - return `${major}.${minor}.${Number(patch) + 1}`; - } else { - return ''; - } - }); - } + const targetVersion = getTargetVersion(currentVersion, release); - if (targetVersion === '') { - return cb(Error(chalk.red('Error: Incorrect version arguments.'))); + if (!targetVersion) { + return cb(new Error(chalk.red('Error: Incorrect version arguments'))); } if (targetVersion === currentVersion) { - return cb(Error(chalk.red('Error: Target version is identical to current version.'))); + return cb(new Error(chalk.red('Error: Target version is identical to current version'))); } + console.log(`Updating version number to '${targetVersion}'`); packageJson.version = targetVersion; - packageLockJson.version = targetVersion; - manifest.file.version = targetVersion; - - /* Update URL */ - const result = `https://git.f3l.de/ghost/${packageJson.name}/-/jobs/artifacts/${targetVersion}/download?job=build`; - - manifest.file.download = result; - - const prettyProjectJson = - stringify(manifest.file, { - maxLength: 40, - indent: 4, - }) + '\n'; - fs.writeJSONSync('package.json', packageJson, { spaces: 4 }); - fs.writeJSONSync('package-lock.json', packageLockJson, { spaces: 4 }); - fs.writeFileSync(path.join(manifest.root, manifest.name), prettyProjectJson, 'utf8'); + + manifest.file.version = targetVersion; + manifest.file.download = getDownloadURL(targetVersion); + fs.writeJSONSync(path.join(sourceDirectory, manifest.name), manifest.file, { spaces: 4 }); return cb(); } catch (err) { @@ -220,10 +193,10 @@ function updateManifest(cb) { } } -const execBuild = gulp.parallel(buildTS, copyFiles); +const execBuild = gulp.parallel(buildCode, copyFiles); exports.build = gulp.series(clean, execBuild); exports.watch = buildWatch; exports.clean = clean; exports.link = linkUserData; -exports.updateManifest = updateManifest; +exports.bumpVersion = bumpVersion; diff --git a/package.json b/package.json index e64e9a4..934d00f 100644 --- a/package.json +++ b/package.json @@ -21,16 +21,17 @@ "scripts": { "build": "gulp build", "build:watch": "gulp watch", - "link": "gulp link", - "clean": "gulp clean && gulp link --clean", - "update": "yarn add --dev foundry-vtt-types@github:League-of-Foundry-Developers/foundry-vtt-types#foundry-0.7.9", - "updateManifest": "gulp updateManifest", - "lint": "eslint 'src/**/*.ts' --cache", - "lint:fix": "eslint 'src/**/*.ts' --cache --fix", - "format": "prettier --write 'src/**/*.(ts|json)'", + "link-project": "gulp link", + "clean": "gulp clean", + "clean:link": "gulp link --clean", + "bump-version": "gulp bumpVersion", + "lint": "eslint --ext .ts,.js .", + "lint:fix": "eslint --ext .ts,.js --fix .", + "format": "prettier --write \"./**/*.(ts|js|json)\"", "postinstall": "husky install" }, "devDependencies": { + "@league-of-foundry-developers/foundry-vtt-types": "^0.7.9-6", "@rollup/plugin-node-resolve": "^13.0.0", "@types/fs-extra": "^9.0.11", "@typescript-eslint/eslint-plugin": "^4.24.0", @@ -39,7 +40,6 @@ "eslint": "^7.27.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-prettier": "^3.4.0", - "foundry-vtt-types": "github:League-of-Foundry-Developers/foundry-vtt-types#foundry-0.7.9", "fs-extra": "^10.0.0", "gulp": "^4.0.2", "husky": "^6.0.0", @@ -48,12 +48,13 @@ "prettier": "^2.3.0", "rollup": "^2.48.0", "rollup-plugin-typescript2": "^0.30.0", + "semver": "^7.3.5", "tslib": "^2.2.0", "typescript": "^4.2.4", "yargs": "^17.0.1" }, "lint-staged": { - "*.ts": "eslint --cache --fix", + "*.(ts|js)": "eslint --fix", "*.json": "prettier --write" } } diff --git a/tsconfig.json b/tsconfig.json index 3d0d26d..55672c0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "ES2020", "lib": ["DOM", "ES2020"], - "types": ["foundry-vtt-types"], + "types": ["@league-of-foundry-developers/foundry-vtt-types"], "esModuleInterop": true, "moduleResolution": "node", "forceConsistentCasingInFileNames": true, diff --git a/yarn.lock b/yarn.lock index 374c636..aac7ad2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -58,6 +58,22 @@ __metadata: languageName: node linkType: hard +"@league-of-foundry-developers/foundry-vtt-types@npm:^0.7.9-6": + version: 0.7.9-6 + resolution: "@league-of-foundry-developers/foundry-vtt-types@npm:0.7.9-6" + dependencies: + "@types/howler": 2.2.1 + "@types/jquery": 3.5.1 + "@types/socket.io-client": ^1.4.33 + handlebars: 4.7.6 + pixi-particles: ^4.3.0 + pixi.js: 5.3.4 + tinymce: 5.6.2 + typescript: ^4.1.4 + checksum: ea8783a4da939db6d51e12a6cb343e53cb6df747ccf8d823063066322c707c98c0fffd2559efc0e0e8fec47b08528f5920be3ac9cd4708c673d947f0e8898e6e + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.4": version: 2.1.4 resolution: "@nodelib/fs.scandir@npm:2.1.4" @@ -2429,21 +2445,6 @@ __metadata: languageName: node linkType: hard -"foundry-vtt-types@github:League-of-Foundry-Developers/foundry-vtt-types#foundry-0.7.9": - version: 0.1.0 - resolution: "foundry-vtt-types@https://github.com/League-of-Foundry-Developers/foundry-vtt-types.git#commit=de66d24eb891c97923db47eb1a819eec2a298f02" - dependencies: - "@types/howler": 2.2.1 - "@types/jquery": 3.5.1 - "@types/socket.io-client": ^1.4.33 - handlebars: 4.7.6 - pixi.js: 5.3.4 - tinymce: 5.6.2 - typescript: ^4.1.4 - checksum: fb6065ce7ed2c969ee421abd3d259f264ed707fabfce01f27d59707338a9ca6854233c0cb8b91ef2310af22a7f7ee95b3e5080d0d2c6662e9b31ed3a5d10ba17 - languageName: node - linkType: hard - "fragment-cache@npm:^0.2.1": version: 0.2.1 resolution: "fragment-cache@npm:0.2.1" @@ -4437,6 +4438,15 @@ fsevents@~2.3.1: languageName: node linkType: hard +"pixi-particles@npm:^4.3.0": + version: 4.3.0 + resolution: "pixi-particles@npm:4.3.0" + peerDependencies: + pixi.js: ">=4.0.0" + checksum: 66da332ae33a236afb5a5b2ebeea0308314423bab1017851be860a0904aed91cb5f345ea488c75a6efdfa6e42096ba7762472f8573590b924b93cae293b8b6d9 + languageName: node + linkType: hard + "pixi.js@npm:5.3.4": version: 5.3.4 resolution: "pixi.js@npm:5.3.4" @@ -4897,6 +4907,7 @@ fsevents@~2.3.1: version: 0.0.0-use.local resolution: "risk-dice-modifier@workspace:." dependencies: + "@league-of-foundry-developers/foundry-vtt-types": ^0.7.9-6 "@rollup/plugin-node-resolve": ^13.0.0 "@types/fs-extra": ^9.0.11 "@typescript-eslint/eslint-plugin": ^4.24.0 @@ -4905,7 +4916,6 @@ fsevents@~2.3.1: eslint: ^7.27.0 eslint-config-prettier: ^8.3.0 eslint-plugin-prettier: ^3.4.0 - foundry-vtt-types: "github:League-of-Foundry-Developers/foundry-vtt-types#foundry-0.7.9" fs-extra: ^10.0.0 gulp: ^4.0.2 husky: ^6.0.0 @@ -4914,6 +4924,7 @@ fsevents@~2.3.1: prettier: ^2.3.0 rollup: ^2.48.0 rollup-plugin-typescript2: ^0.30.0 + semver: ^7.3.5 tslib: ^2.2.0 typescript: ^4.2.4 yargs: ^17.0.1 @@ -5043,6 +5054,17 @@ fsevents@~2.3.1: languageName: node linkType: hard +"semver@npm:^7.3.5": + version: 7.3.5 + resolution: "semver@npm:7.3.5" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: c53624ddf4b9779bcbf55a1eb8b37074cc44bfeca416f3cc263429408202a8a3c59b00eef8c647d697303bc39b95c022a5c61959221d3814bfb1270ff7c14986 + languageName: node + linkType: hard + "set-blocking@npm:^2.0.0, set-blocking@npm:~2.0.0": version: 2.0.0 resolution: "set-blocking@npm:2.0.0"