This commit is contained in:
Carlos Fernandez 2026-06-05 20:49:24 -04:00 committed by GitHub
commit 44b142e608
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 107 additions and 73 deletions

View file

@ -1,2 +1,2 @@
FOUNDRY_MAIN_PATH=/path/to/foundry/resources/app/main.js
FOUNDRY_DATA_PATH=/path/to/foundry/data
FOUNDRY_DATA_PATH=/path/to/foundry/

View file

@ -38,11 +38,13 @@ You can find the documentation here: https://github.com/Foundryborne/daggerheart
3. **Configure your Foundry paths:**
```bash
npm run setup:dev -- --foundry-path="/path/to/foundry/main.js" --data-path="/path/to/data"
```
Copy `.env.example` to `.env` and set up the foundry path and data path. The foundry path must point to main.js, and the data path must point the folder containing the Data folder itself (but not the `Data` folder itself).
4. **Start developing:**
4. **Setup symlinks:**
In a shell with elevated privilages, run `npm run createSymlink`. It will add a foundry folder for types, and add a symlink to the daggerheart folder into your foundry data.
5. **Start developing:**
```bash
npm start
```
@ -51,7 +53,7 @@ You can find the documentation here: https://github.com/Foundryborne/daggerheart
- `npm start` - Start development with file watching and Foundry launching
- `npm run build` - One-time build
- `npm run setup:dev -- --foundry-path="<path>" --data-path="<path>"` - Configure development environment
- `npm run createSymlink` - Setup types and output symlinks
### Notes

View file

@ -18,7 +18,6 @@
"pullYMLtoLDB": "node ./tools/pullYMLtoLDB.mjs",
"pullYMLtoLDBBuild": "node ./tools/pullYMLtoLDB.mjs --build",
"createSymlink": "node ./tools/create-symlink.mjs",
"setup:dev": "node ./tools/dev-setup.mjs",
"lint": "eslint",
"lint:fix": "eslint --fix",
"prepare": "husky"

View file

@ -1,47 +1,70 @@
import fs from 'fs';
import path from 'path';
import readline from 'readline';
import { isContainedPath, readEnvFile } from './util.mjs';
console.log('Creates a foundry symlink in the base folder for type purposes\n');
const projectRoot = path.resolve(import.meta.dirname, '../')
const { foundryRoot, dataPath } = readEnvFile();
const askQuestion = question => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
async function createFoundrySymlink() {
// If foundry already exists, exit and inform the user. This operation can't complete correctly otherwise.
// If the folder is empty, its fine. It may have failed due to perms
const foundryDestPath = path.join(projectRoot, 'foundry');
if (fs.existsSync(foundryDestPath) && fs.readdirSync(foundryDestPath).length) {
console.log('"foundry" folder already exists in this project');
return;
}
return new Promise(resolve =>
rl.question(question, answer => {
rl.close();
resolve(answer);
})
);
};
const installPath = await askQuestion('Enter your Foundry install path: ');
// Determine if it's an Electron install (nested structure)
const nested = fs.existsSync(path.join(installPath, 'resources', 'app'));
const fileRoot = nested ? path.join(installPath, 'resources', 'app') : installPath;
try {
await fs.promises.mkdir('foundry');
} catch (e) {
if (e.code !== 'EEXIST') throw e;
}
// JavaScript files
for (const p of ['client', 'common', 'tsconfig.json']) {
console.log('Creating "foundry" symlinks for types');
try {
await fs.promises.symlink(path.join(fileRoot, p), path.join('foundry', p));
await fs.promises.mkdir(foundryDestPath);
console.log('Root foundry folder created');
} catch (e) {
if (e.code !== 'EEXIST') throw e;
}
// JavaScript files
for (const p of ['client', 'common', 'tsconfig.json']) {
try {
await fs.promises.symlink(path.join(foundryRoot, p), path.join(foundryDestPath, p));
console.log(`${p} folder created`);
} catch (e) {
if (e.code !== 'EEXIST') throw e;
}
}
// Language files
try {
await fs.promises.symlink(path.join(foundryRoot, 'public', 'lang'), path.join(foundryDestPath, 'lang'));
console.log(`lang folder created`);
} catch (e) {
if (e.code !== 'EEXIST') throw e;
console.log(`lang folder already exists`);
}
}
// Language files
try {
await fs.promises.symlink(path.join(fileRoot, 'public', 'lang'), path.join('foundry', 'lang'));
} catch (e) {
if (e.code !== 'EEXIST') throw e;
async function createDaggerheartSymlink() {
if (isContainedPath(dataPath, projectRoot)) {
console.log('The Daggerheart project repo is in foundry data, so a symlink won\'t be created');
return;
}
const destination = path.join(dataPath, 'Data', 'systems', 'daggerheart');
if (fs.existsSync(destination)) {
console.log('A Daggerheart folder already exists in Foundry data');
return;
}
console.log('Creating Daggerheart symlink in the foundry systems folder')
try {
await fs.promises.symlink(projectRoot, destination);
console.log('Daggerheart system folder symlink created');
} catch (e) {
if (e.code !== 'EEXIST') throw e;
console.log(`Daggerheart system folder already exists`);
}
}
await createFoundrySymlink();
console.log();
await createDaggerheartSymlink();

View file

@ -1,18 +0,0 @@
#!/usr/bin/env node
import fs from 'fs';
const args = process.argv.slice(2);
const foundryPath = args.find(arg => arg.startsWith('--foundry-path='))?.split('=')[1];
const dataPath = args.find(arg => arg.startsWith('--data-path='))?.split('=')[1];
if (!foundryPath || !dataPath) {
console.log('Usage: npm run setup:dev -- --foundry-path="/path/to/foundry/main.js" --data-path="/path/to/data"');
process.exit(1);
}
const envContent = `FOUNDRY_MAIN_PATH=${foundryPath}
FOUNDRY_DATA_PATH=${dataPath}
`;
fs.writeFileSync('.env', envContent);
console.log(`✅ Development environment configured: ${foundryPath}, ${dataPath}`);

View file

@ -1,21 +1,10 @@
#!/usr/bin/env node
import { spawn } from 'child_process';
import { readEnvFile } from './util.mjs';
import fs from 'fs';
// Load .env file if it exists
if (fs.existsSync('.env')) {
const envFile = fs.readFileSync('.env', 'utf8');
envFile.split('\n').forEach(line => {
const [key, value] = line.split('=');
if (key && value) {
process.env[key] = value;
}
});
}
// Set defaults if not in environment
const foundryPath = process.env.FOUNDRY_MAIN_PATH || '../../../../FoundryDev/main.js';
const dataPath = process.env.FOUNDRY_DATA_PATH || '../../../';
// Load .env file params
const { foundryPath, dataPath } = readEnvFile();
// Run the original command with proper environment
const args = ['rollup -c --watch', `node "\"${foundryPath}\"" --dataPath="${dataPath}" --noupnp`, 'gulp'];

39
tools/util.mjs Normal file
View file

@ -0,0 +1,39 @@
import fs from 'fs';
import path from 'path';
export function readEnvFile() {
if (!fs.existsSync('.env')) {
console.error('No configured .env file. Copy .env.example to .env and configure it.');
process.exit();
}
const envFile = fs.readFileSync('.env', 'utf8');
envFile.split('\n').forEach(line => {
const [key, value] = line.split('=');
if (key && value) {
process.env[key] = value;
}
});
// Determine foundry path, handling if its an electron install (nested structure)
const foundryPath = path.normalize(process.env.FOUNDRY_MAIN_PATH);
const dataPath = path.normalize(process.env.FOUNDRY_DATA_PATH);
if (!foundryPath.endsWith(path.join('app', 'main.js'))) {
console.error('Configured FOUNDRY_MAIN_PATH is invalid, it must end with app/main.js');
process.exit();
}
if (/Data(\/|\\)?$/.test(dataPath) || !fs.existsSync(path.join(dataPath, 'Data'))) {
console.error('Configured FOUNDRY_DATA_PATH is incorrect. This must be a folder that contains "Data"');
}
return {
foundryPath,
foundryRoot: path.dirname(foundryPath),
dataPath
};
}
export function isContainedPath(parent, child) {
const relative = path.relative(parent, child);
return relative && !relative.startsWith('..') && !path.isAbsolute(relative);
}