Initial commit

This commit is contained in:
Johannes Loher 2021-02-07 16:01:14 +01:00
commit 676e84b920
20 changed files with 8543 additions and 0 deletions

9
.editorconfig Normal file
View file

@ -0,0 +1,9 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
charset = utf-8
trim_trailing_whitespace = true

21
.eslintrc.js Normal file
View file

@ -0,0 +1,21 @@
module.exports = {
parser: "@typescript-eslint/parser", // Specifies the ESLint parser
parserOptions: {
ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features
sourceType: "module", // Allows for the use of imports
},
extends: [
"plugin:@typescript-eslint/recommended", // Uses the recommended rules from the @typescript-eslint/eslint-plugin
"prettier/@typescript-eslint", // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier
"plugin:prettier/recommended", // Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
],
plugins: ["@typescript-eslint"],
rules: {
// 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",
},
};

19
.gitignore vendored Normal file
View file

@ -0,0 +1,19 @@
# IDE
.idea/
.vs/
# Node Modules
node_modules/
npm-debug.log
# Local configuration
foundryconfig.json
# Distribution files
dist
# ESLint
.eslintcache
# Junit results
results.xml

84
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,84 @@
image: node:latest
stages:
- prepare
- build
- release
cache: &global_cache
key:
files:
- package-lock.json
policy: pull
paths:
- node_modules/
install-dependencies:
stage: prepare
script:
- npm install
cache:
<<: *global_cache
policy: pull-push
lint:
stage: test
script:
- npm run lint
cache:
<<: *global_cache
build:
stage: build
script:
- npm run build
- mv dist risk-dice
cache:
<<: *global_cache
artifacts:
paths:
- risk-dice
expire_in: 1 week
.release-template: &release-template
stage: release
before_script:
- apt update
- apt install --yes jq
- REPOSITORY_URL=$(echo "${CI_REPOSITORY_URL}" | sed -e "s|gitlab-ci-token:.*@|${RELEASE_TOKEN}:${RELEASE_TOKEN_SECRET}@|g")
- git remote set-url origin $REPOSITORY_URL
- git config user.name $GITLAB_USER_LOGIN
- git config user.email $GITLAB_USER_EMAIL
- git branch -D ci-processing || true
- git checkout -b ci-processing
cache:
<<: *global_cache
script: |
npm run updateManifest -- --update=${RELEASE_TYPE}
RELEASE_VERSION=$(jq -r '.version' < package.json)
git add package.json package-lock.json src/system.json
git --no-pager diff
git commit -m "release version ${RELEASE_VERSION}"
git tag -f latest
git tag -f ${RELEASE_VERSION}
git push origin ci-processing:${CI_BUILD_REF_NAME}
git push origin latest -f
git push origin ${RELEASE_VERSION}
only:
- master
when: manual
release-patch:
variables:
RELEASE_TYPE: patch
<<: *release-template
release-minor:
variables:
RELEASE_TYPE: minor
<<: *release-template
release-major:
variables:
RELEASE_TYPE: major
<<: *release-template

View file

@ -0,0 +1,29 @@
# Description
Please describe the issue.
# Steps to Reproduce
1. ...
2. ...
3. ...
# Expected Behavior
Please describe the expected behavior.
# Actual Behavior
Please describe the actual behavior.
# Additional Details
These are optional, please add them if it makes sense.
- ![Screenshot]()
- [Logfile]()
- ...
# Possible Solutions
If you have any suggestions on how to solve the issue, please add them here.

View file

@ -0,0 +1,13 @@
# Story
As a …, I want … so that …
# Description
Please add a more detailed description of the feature here.
# Acceptance criteria
1. Criterion 1
2. Criterion 2
3. …

7
.npmignore Normal file
View file

@ -0,0 +1,7 @@
# IDE
.idea/
.vs/
# Node Modules
node_modules/
npm-debug.log

1
.nvmrc Normal file
View file

@ -0,0 +1 @@
lts/*

7
.prettierrc.js Normal file
View file

@ -0,0 +1,7 @@
module.exports = {
semi: true,
trailingComma: "all",
singleQuote: true,
printWidth: 120,
tabWidth: 4,
};

8
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,8 @@
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"gruntfuggly.todo-tree",
"eg2.vscode-npm-script"
]
}

7
LICENSE Normal file
View file

@ -0,0 +1,7 @@
Copyright 2020 Johannes Loher
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

76
README.md Normal file
View file

@ -0,0 +1,76 @@
# Risk Dice
An implementation of Risk Dice as found for example in the Splittermond game system.
## Installation
To install and use the Risk Dice module for Foundry Virtual Tabletop,
simply paste the following URL into the **Install Module** dialog on the Setup
menu of the application.
https://git.f3l.de/dungeonslayers/risk-dice/-/raw/latest/src/module.json?inline=false
## Development
### Prerequisites
In order to build this module, recent versions of `node` and `npm` are required.
We recommend using the latest lts version of `node`, which is `v14.15.4` at the
time of writing. If you use `nvm` to manage your `node` versions, you can simply
run
```
nvm install
```
in the project's root directory.
You also need to install the the project's dependencies. To do so, run
```
npm install
```
### Building
You can build the project by running
```
npm run build
```
Alternatively, you can run
```
npm run build:watch
```
to watch for changes and automatically build as necessary.
### Linking the built module to Foundry VTT
In order to provide a fluent development experience, it is recommended to link
the built system to your local Foundry VTT installation's data folder. In order
to do so, first add a file called `foundryconfig.json` to the project root with
the following content:
```
{
"dataPath": "<path to your home directory>/.local/share/FoundryVTT"
}
```
On platforms other than Linux you need to adjust the path accordingly.
Then run
```
npm run link
```
## Contributing
TODO
## Licensing
This project is licensed under the MIT License, a copy of which can be found
under [LICENSE](LICENSE).

298
gulpfile.js Normal file
View file

@ -0,0 +1,298 @@
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 typescript = require('typescript');
const ts = require('gulp-typescript');
const argv = require('yargs').argv;
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;
}
/**
* TypeScript transformers
* @returns {typescript.TransformerFactory<typescript.SourceFile>}
*/
function createTransformer() {
/**
* @param {typescript.Node} node
*/
function shouldMutateModuleSpecifier(node) {
if (!typescript.isImportDeclaration(node) && !typescript.isExportDeclaration(node)) return false;
if (node.moduleSpecifier === undefined) return false;
if (!typescript.isStringLiteral(node.moduleSpecifier)) return false;
if (!node.moduleSpecifier.text.startsWith('./') && !node.moduleSpecifier.text.startsWith('../')) return false;
if (path.extname(node.moduleSpecifier.text) !== '') return false;
return true;
}
/**
* Transforms import/export declarations to append `.js` extension
* @param {typescript.TransformationContext} context
*/
function importTransformer(context) {
return (node) => {
/**
* @param {typescript.Node} node
*/
function visitor(node) {
if (shouldMutateModuleSpecifier(node)) {
if (typescript.isImportDeclaration(node)) {
const newModuleSpecifier = typescript.createLiteral(`${node.moduleSpecifier.text}.js`);
return typescript.updateImportDeclaration(
node,
node.decorators,
node.modifiers,
node.importClause,
newModuleSpecifier,
);
} else if (typescript.isExportDeclaration(node)) {
const newModuleSpecifier = typescript.createLiteral(`${node.moduleSpecifier.text}.js`);
return typescript.updateExportDeclaration(
node,
node.decorators,
node.modifiers,
node.exportClause,
newModuleSpecifier,
);
}
}
return typescript.visitEachChild(node, visitor, context);
}
return typescript.visitNode(node, visitor);
};
}
return importTransformer;
}
const tsConfig = ts.createProject('tsconfig.json', {
getCustomTransformers: (_program) => ({
after: [createTransformer()],
}),
});
/********************/
/* BUILD */
/********************/
/**
* Build TypeScript
*/
function buildTS() {
return gulp.src('src/**/*.ts').pipe(tsConfig()).pipe(gulp.dest('dist'));
}
/**
* Copy static files
*/
async function copyFiles() {
const statics = ['lang', '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));
}
}
return Promise.resolve();
} catch (err) {
Promise.reject(err);
}
}
/**
* Watch for changes for each build step
*/
function buildWatch() {
gulp.watch('src/**/*.ts', { ignoreInitial: false }, buildTS);
gulp.watch(
['src/fonts', 'src/lang', 'src/templates', 'src/*.json', 'src/packs'],
{ ignoreInitial: false },
copyFiles,
);
}
/********************/
/* CLEAN */
/********************/
/**
* 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('lang', 'module', `${name}.js`, 'module.json');
}
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);
}
}
/********************/
/* LINK */
/********************/
/**
* Link build to User Data folder
*/
async function linkUserData() {
const name = path.basename(path.resolve('.'));
const config = fs.readJSONSync('foundryconfig.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')}`);
}
let linkDir;
if (config.dataPath) {
if (!fs.existsSync(path.join(config.dataPath, 'Data')))
throw Error('User Data path invalid, no Data directory found');
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);
}
}
/*********************/
/* PACKAGE */
/*********************/
/**
* Update version and URLs in the manifest JSON
*/
function updateManifest(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;
/* Update version */
const versionMatch = /^(\d{1,}).(\d{1,}).(\d{1,})$/;
const currentVersion = manifest.file.version;
let targetVersion = '';
if (!version) {
cb(Error('Missing version number'));
}
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 '';
}
});
}
if (targetVersion === '') {
return cb(Error(chalk.red('Error: Incorrect version arguments.')));
}
if (targetVersion === currentVersion) {
return cb(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/risk-dice/-/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');
return cb();
} catch (err) {
cb(err);
}
}
const execBuild = gulp.parallel(buildTS, copyFiles);
exports.build = gulp.series(clean, execBuild);
exports.watch = buildWatch;
exports.clean = clean;
exports.link = linkUserData;
exports.updateManifest = updateManifest;

7859
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

65
package.json Normal file
View file

@ -0,0 +1,65 @@
{
"private": true,
"name": "risk-dice",
"description": "An implementation of Risk Dice as found for example in the Splittermond game system",
"version": "0.0.1",
"license": "MIT",
"homepage": "https://git.f3l.de/ghost/risk-dice",
"repository": {
"type": "git",
"url": "https://git.f3l.de/ghost/risk-dice"
},
"bugs": {
"url": "https://git.f3l.de/ghost/risk-dice/-/issues"
},
"contributors": [
{
"name": "Johannes Loher",
"email": "johannes.loher@fg4f.de"
}
],
"scripts": {
"build": "gulp build",
"build:watch": "gulp watch",
"link": "gulp link",
"clean": "gulp clean && gulp link --clean",
"update": "npm install --save-dev 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|scss)'"
},
"devDependencies": {
"@types/fs-extra": "^9.0.6",
"@typescript-eslint/eslint-plugin": "^4.14.2",
"@typescript-eslint/parser": "^4.14.2",
"archiver": "^5.2.0",
"chalk": "^4.1.0",
"eslint": "^7.19.0",
"eslint-config-prettier": "^7.2.0",
"eslint-plugin-prettier": "^3.3.1",
"foundry-vtt-types": "github:League-of-Foundry-Developers/foundry-vtt-types#foundry-0.7.9",
"fs-extra": "^9.1.0",
"gulp": "^4.0.2",
"gulp-git": "^2.10.1",
"gulp-less": "^4.0.1",
"gulp-sass": "^4.1.0",
"gulp-typescript": "^6.0.0-alpha.1",
"husky": "^4.3.8",
"json-stringify-pretty-compact": "^2.0.0",
"lint-staged": "^10.5.4",
"prettier": "^2.2.1",
"ts-node": "^9.1.1",
"typescript": "^4.1.3",
"yargs": "^16.2.0"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.ts": "eslint --cache --fix",
"*.json": "prettier --write"
}
}

1
src/lang/de.json Normal file
View file

@ -0,0 +1 @@
{}

1
src/lang/en.json Normal file
View file

@ -0,0 +1 @@
{}

26
src/module.json Normal file
View file

@ -0,0 +1,26 @@
{
"name": "risk-dice",
"title": "Risk Dice",
"description": "An implementation of Risk Dice as found for example in the Splittermond game system",
"author": "Johannes Loher",
"version": "0.0.1",
"minimumCoreVersion": "0.7.9",
"compatibleCoreVersion": "0.7.9",
"esmodules": ["module/risk-dice.js"],
"languages": [
{
"lang": "en",
"name": "English",
"path": "lang/en.json"
},
{
"lang": "de",
"name": "German",
"path": "lang/de.json"
}
],
"url": "https://git.f3l.de/ghost/risk-dice",
"manifest": "https://git.f3l.de/ghost/risk-dice/-/raw/latest/src/system.json?inline=false",
"download": "https://git.f3l.de/ghost/risk-dice/-/jobs/artifacts/0.0.1/download?job=build",
"license": "MIT"
}

0
src/module/risk-die.ts Normal file
View file

12
tsconfig.json Normal file
View file

@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ES2020",
"lib": ["DOM", "ES2020"],
"types": ["foundry-vtt-types"],
"esModuleInterop": true,
"moduleResolution": "node",
"forceConsistentCasingInFileNames": true,
"strict": true
},
"include": ["src"]
}