create-lt-adventure 0.0.15 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/addons/github-workflow/main.yml +91 -43
- package/addons/github-workflow/{setup.ts → setup.mjs} +29 -26
- package/addons/sf2e-pf2e-redirects/addon.json +5 -0
- package/addons/sf2e-pf2e-redirects/setup.mjs +119 -0
- package/dist/bin.js +223 -84
- package/dist/bin.js.map +1 -1
- package/dist/migrate.d.ts +2 -0
- package/dist/migrate.d.ts.map +1 -0
- package/dist/migrate.js +169 -0
- package/dist/migrate.js.map +1 -0
- package/dist/options.d.ts +5 -2
- package/dist/options.d.ts.map +1 -1
- package/dist/options.js +14 -5
- package/dist/options.js.map +1 -1
- package/package.json +7 -7
- package/templates/vite/.env.example +1 -1
- package/templates/vite/CHANGELOG +1 -0
- package/templates/vite/gitignore +37 -37
- package/templates/vite/module.json +37 -36
- package/templates/vite/package.json +5 -4
- package/templates/vite/scripts/extractPacks.mjs +54 -49
- package/templates/vite/scripts/jsonReplacer.mjs +11 -0
- package/templates/vite/scripts/onCreate.mjs +41 -13
- package/templates/vite/scripts/symlink.mjs +78 -78
- package/templates/vite/src/adventureSheet/index.js +497 -497
- package/templates/vite/src/hooks.ts +22 -0
- package/templates/vite/src/index.js +4 -4
- package/templates/vite/src/lib/utils.ts +1 -0
- package/templates/vite/src/misc/prosemirror.js +46 -46
- package/templates/vite/src/module.css +306 -306
- package/templates/vite/src/types.d.ts +7 -7
- package/templates/vite/tsconfig.json +33 -0
- package/templates/vite/vite.config.ts +129 -128
- package/templates/vite/bun.lock +0 -994
package/README.md
CHANGED
|
@@ -9,10 +9,10 @@ A CLI scaffolding tool for creating Foundry VTT modules.
|
|
|
9
9
|
Once published to npm, you can run the script via Bun:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
bunx create-lt-adventure
|
|
12
|
+
bunx create-lt-adventure
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Updating the package:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
18
|
create-lt-adventure
|
|
@@ -1,48 +1,96 @@
|
|
|
1
1
|
name: Release Creation
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
6
|
|
|
7
7
|
jobs:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
8
|
+
build:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- uses: oven-sh/setup-bun@v2
|
|
13
|
+
|
|
14
|
+
- name: Extract version from tag without the v
|
|
15
|
+
id: get-version
|
|
16
|
+
run: echo "v=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
|
|
17
|
+
|
|
18
|
+
- name: Substitute Manifest and Download Links For Versioned Ones
|
|
19
|
+
id: sub_manifest_link_version
|
|
20
|
+
uses: microsoft/variable-substitution@v1
|
|
21
|
+
with:
|
|
22
|
+
files: module.json
|
|
23
|
+
env:
|
|
24
|
+
flags.canUpload: false
|
|
25
|
+
version: ${{ steps.get-version.outputs.v }}
|
|
26
|
+
|
|
27
|
+
- name: Install packages
|
|
28
|
+
run: bun i --frozen-lockfile
|
|
29
|
+
|
|
30
|
+
- name: Build distribution
|
|
31
|
+
run: bun run build
|
|
32
|
+
|
|
33
|
+
# Create a zip file with all files required by the module to add to the release.
|
|
34
|
+
- name: Bundle into ZIP file
|
|
35
|
+
run: zip -r ./module.zip module.json assets/ dist/ packs/ lang/
|
|
36
|
+
|
|
37
|
+
# Create a release for this specific version.
|
|
38
|
+
- name: Update Release with Files
|
|
39
|
+
id: create_version_release
|
|
40
|
+
uses: ncipollo/release-action@v1
|
|
41
|
+
with:
|
|
42
|
+
allowUpdates: true # Set this to false if you want to prevent updating existing releases.
|
|
43
|
+
name: ${{ github.event.release.name }}
|
|
44
|
+
tag: ${{ github.event.release.tag_name }}
|
|
45
|
+
body: ${{ github.event.release.body }}
|
|
46
|
+
artifacts: "./module.json, ./module.zip"
|
|
47
|
+
omitDraftDuringUpdate: true
|
|
48
|
+
omitPrereleaseDuringUpdate: true
|
|
49
|
+
|
|
50
|
+
# https://stackoverflow.com/questions/61919141/read-json-file-in-github-actions
|
|
51
|
+
- id: set_var
|
|
52
|
+
run: echo "PACKAGE_JSON=$(jq -c . < module.json)" >> "$GITHUB_OUTPUT"
|
|
53
|
+
|
|
54
|
+
- name: Get Module ID
|
|
55
|
+
id: module_id
|
|
56
|
+
run: echo "module_id=${{ fromJson(steps.set_var.outputs.PACKAGE_JSON).id }}" >> "$GITHUB_OUTPUT"
|
|
57
|
+
|
|
58
|
+
- name: Get FTP Path
|
|
59
|
+
id: ftp
|
|
60
|
+
run: echo "ftp=${{ fromJson(steps.set_var.outputs.PACKAGE_JSON).flags.ftpPath || format('NEW/{0}', steps.module_id.outputs.module_id) }}" >> "$GITHUB_OUTPUT"
|
|
61
|
+
|
|
62
|
+
- name: Get Module Title
|
|
63
|
+
id: title
|
|
64
|
+
run: echo "title=${{fromJson(steps.set_var.outputs.PACKAGE_JSON).title}}" >> "$GITHUB_OUTPUT"
|
|
65
|
+
|
|
66
|
+
- name: Put Files into FTP Folder
|
|
67
|
+
env:
|
|
68
|
+
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
|
|
69
|
+
if: ${{ env.FTP_PASSWORD != '' }}
|
|
70
|
+
run: |
|
|
71
|
+
ls
|
|
72
|
+
mkdir _ftp
|
|
73
|
+
cp module.json _ftp/
|
|
74
|
+
cp module.zip _ftp/
|
|
75
|
+
mkdir _ftp/${{steps.module_id.outputs.module_id}}
|
|
76
|
+
cp module.json _ftp/${{steps.module_id.outputs.module_id}}/
|
|
77
|
+
|
|
78
|
+
- name: Upload FTP
|
|
79
|
+
uses: sebastianpopp/ftp-action@releases/v2
|
|
80
|
+
env:
|
|
81
|
+
FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
|
|
82
|
+
if: ${{ env.FTP_PASSWORD != '' }}
|
|
83
|
+
with:
|
|
84
|
+
host: ${{ secrets.FTP_SERVER }}
|
|
85
|
+
user: ${{ secrets.FTP_USERNAME }}
|
|
86
|
+
password: ${{ env.FTP_PASSWORD }}
|
|
87
|
+
localDir: _ftp
|
|
88
|
+
remoteDir: ${{steps.ftp.outputs.ftp}}
|
|
89
|
+
|
|
90
|
+
- name: Send Discord Ping
|
|
91
|
+
uses: Ilshidur/action-discord@0.3.2
|
|
92
|
+
env:
|
|
93
|
+
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
|
94
|
+
if: ${{ env.DISCORD_WEBHOOK != '' && !github.event.release.prerelease }}
|
|
95
|
+
with:
|
|
96
|
+
args: "${{steps.title.outputs.title}} has been updated to version `${{github.event.release.tag_name}}`!"
|
|
@@ -6,28 +6,31 @@
|
|
|
6
6
|
|
|
7
7
|
import * as p from "@clack/prompts";
|
|
8
8
|
import { cyan } from "kolorist";
|
|
9
|
-
import { mkdir } from "fs/promises";
|
|
9
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
10
|
+
import { dirname } from "path";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
12
|
+
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
14
|
|
|
11
15
|
const data = await p.group(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
{
|
|
17
|
+
features: () =>
|
|
18
|
+
p.multiselect({
|
|
19
|
+
message: "Additional features?",
|
|
20
|
+
initialValues: ["ftp", "discord"],
|
|
17
21
|
required: false,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
options: [
|
|
23
|
+
// { label: "Prereleases", value: "prereleases" },
|
|
24
|
+
{ label: "Uploading via FTP", value: "ftp" },
|
|
25
|
+
{ label: "Discord webhook on updates", value: "discord" },
|
|
26
|
+
],
|
|
27
|
+
}),
|
|
28
|
+
},
|
|
29
|
+
{ onCancel: () => process.exit(0) },
|
|
26
30
|
);
|
|
27
31
|
|
|
28
32
|
// Grab main.yml template
|
|
29
|
-
const
|
|
30
|
-
const mainYmlTemplate = await Bun.file(`${addonDir}/main.yml`).text();
|
|
33
|
+
const mainYmlTemplate = await readFile(`${__dirname}/main.yml`, "utf8");
|
|
31
34
|
|
|
32
35
|
// Get the module directory from environment variable
|
|
33
36
|
const moduleDir = process.env.MODULE_DIR || process.cwd();
|
|
@@ -36,27 +39,27 @@ let mainYml = mainYmlTemplate;
|
|
|
36
39
|
|
|
37
40
|
// I should probably just make this a JSON and convert it to accursed YAML at the end step...
|
|
38
41
|
if (data.features.includes("discord") || data.features.includes("ftp")) {
|
|
39
|
-
|
|
42
|
+
mainYml += `
|
|
40
43
|
# https://stackoverflow.com/questions/61919141/read-json-file-in-github-actions
|
|
41
44
|
- id: set_var
|
|
42
45
|
run: echo "PACKAGE_JSON=$(jq -c . < module.json)" >> $GITHUB_OUTPUT
|
|
43
46
|
|
|
44
47
|
- name: Get FTP Path
|
|
45
48
|
id: ftp
|
|
46
|
-
run: echo "ftp=\${{fromJson(steps.set_var.outputs.PACKAGE_JSON).flags.ftpPath}}" >>
|
|
49
|
+
run: echo "ftp=\${{fromJson(steps.set_var.outputs.PACKAGE_JSON).flags.ftpPath}}" >> $GITHUB_OUTPUT
|
|
47
50
|
|
|
48
51
|
- name: Get Module ID
|
|
49
52
|
id: module_id
|
|
50
|
-
run: echo "module_id=\${{fromJson(steps.set_var.outputs.PACKAGE_JSON).id}}" >>
|
|
53
|
+
run: echo "module_id=\${{fromJson(steps.set_var.outputs.PACKAGE_JSON).id}}" >> $GITHUB_OUTPUT
|
|
51
54
|
|
|
52
55
|
- name: Get Module Title
|
|
53
56
|
id: title
|
|
54
|
-
run: echo "title=\${{fromJson(steps.set_var.outputs.PACKAGE_JSON).title}}" >>
|
|
57
|
+
run: echo "title=\${{fromJson(steps.set_var.outputs.PACKAGE_JSON).title}}" >> $GITHUB_OUTPUT
|
|
55
58
|
`;
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
if (data.features.includes("ftp")) {
|
|
59
|
-
|
|
62
|
+
mainYml += `
|
|
60
63
|
- name: Put Files into FTP Folder
|
|
61
64
|
env:
|
|
62
65
|
FTP_PASSWORD: \${{ secrets.FTP_PASSWORD }}
|
|
@@ -84,7 +87,7 @@ if (data.features.includes("ftp")) {
|
|
|
84
87
|
}
|
|
85
88
|
|
|
86
89
|
if (data.features.includes("discord")) {
|
|
87
|
-
|
|
90
|
+
mainYml += `
|
|
88
91
|
- name: Send Discord Ping
|
|
89
92
|
uses: Ilshidur/action-discord@0.3.2
|
|
90
93
|
env:
|
|
@@ -98,15 +101,15 @@ if (data.features.includes("discord")) {
|
|
|
98
101
|
// Create main.yml file
|
|
99
102
|
const workflowDir = `${moduleDir}/.github/workflows`;
|
|
100
103
|
await mkdir(workflowDir, { recursive: true });
|
|
101
|
-
await
|
|
104
|
+
await writeFile(`${workflowDir}/main.yml`, mainYml);
|
|
102
105
|
|
|
103
106
|
let note = "✅ Installed!";
|
|
104
107
|
note += "\nThe Github workflow is triggered by making a new release. To make a new release go to your repository's Releases page which can be found in the sidebar on the right and press \"Draft a new release.\" Fill in the version number and you're done!"
|
|
105
108
|
|
|
106
109
|
if (data.features.includes("discord"))
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
note +=
|
|
111
|
+
"\n - For the Discord integration, make sure to create a DISCORD_WEBHOOK secret with the webhook url.";
|
|
109
112
|
if (data.features.includes("ftp"))
|
|
110
|
-
|
|
113
|
+
note += `\n - For the FTP integration, make sure to include the FTP_SERVER, FTP_USERNAME, and FTP_PASSWORD secrets.\n\tThe module JSON also can include a flag stating its subdirectory on the FTP server under ${cyan("flags.ftpPath")}.`;
|
|
111
114
|
|
|
112
115
|
p.note(note, "Github Workflow");
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Creates a uuid-redirects.js file that redirects sf2e compendium UUIDs to pf2e equivalents.
|
|
2
|
+
// This addon only activates when both sf2e and pf2e systems are selected.
|
|
3
|
+
|
|
4
|
+
import * as p from "@clack/prompts";
|
|
5
|
+
import { cyan } from "kolorist";
|
|
6
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
7
|
+
import { existsSync } from "fs";
|
|
8
|
+
import { dirname, join } from "path";
|
|
9
|
+
import { fileURLToPath } from "url";
|
|
10
|
+
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
|
|
13
|
+
// Get the module directory from environment variable
|
|
14
|
+
const moduleDir = process.env.MODULE_DIR || process.cwd();
|
|
15
|
+
|
|
16
|
+
// Read the module.json to get module ID and packs
|
|
17
|
+
const moduleJsonPath = join(moduleDir, "module.json");
|
|
18
|
+
if (!existsSync(moduleJsonPath)) {
|
|
19
|
+
p.log.warn("⚠️ module.json not found, skipping SF2e to PF2e UUID redirects");
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const moduleJson = JSON.parse(await readFile(moduleJsonPath, "utf8"));
|
|
24
|
+
const moduleId = moduleJson.id;
|
|
25
|
+
const systems = (moduleJson.relationships?.systems || []).map(s => s.id);
|
|
26
|
+
const packs = moduleJson.packs || [];
|
|
27
|
+
|
|
28
|
+
// Check if both sf2e and pf2e are selected
|
|
29
|
+
if (!systems.includes("sf2e") || !systems.includes("pf2e")) {
|
|
30
|
+
p.note("⏭️ Skipped - both sf2e and pf2e systems must be selected", "SF2e to PF2e UUID Redirects");
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Find base pack names (e.g., "items", "actors") that have both sf2e and pf2e variants
|
|
35
|
+
const sf2ePackNames = packs.filter(p => p.system === "sf2e").map(p => p.name.replace("sf2e-", ""));
|
|
36
|
+
const pf2ePackNames = packs.filter(p => p.system === "pf2e").map(p => p.name.replace("pf2e-", ""));
|
|
37
|
+
const commonPackNames = sf2ePackNames.filter(name => pf2ePackNames.includes(name));
|
|
38
|
+
|
|
39
|
+
if (commonPackNames.length === 0) {
|
|
40
|
+
p.note("⏭️ Skipped - no common packs found between sf2e and pf2e", "SF2e to PF2e UUID Redirects");
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Build the UUID_REDIRECTS object
|
|
45
|
+
const redirects = {};
|
|
46
|
+
for (const packName of commonPackNames) {
|
|
47
|
+
redirects[`Compendium.${moduleId}.sf2e-${packName}`] = `Compendium.${moduleId}.pf2e-${packName}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Generate the uuid-redirects.js content
|
|
51
|
+
const redirectsContent = `// Auto-generated by create-fvtt-module - sf2e-pf2e-redirects addon
|
|
52
|
+
// Redirects sf2e compendium UUIDs to their pf2e equivalents
|
|
53
|
+
|
|
54
|
+
const UUID_REDIRECTS = {
|
|
55
|
+
${Object.entries(redirects).map(([from, to]) => ` "${from}": "${to}"`).join(",\n")}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
for (const [from, to] of Object.entries(UUID_REDIRECTS)) {
|
|
59
|
+
CONFIG.compendium.uuidRedirects[from] = to;
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
// Check if src directory exists
|
|
64
|
+
const srcDir = join(moduleDir, "src");
|
|
65
|
+
const srcExists = existsSync(srcDir);
|
|
66
|
+
|
|
67
|
+
// Check for index files
|
|
68
|
+
const indexTs = join(srcDir, "index.ts");
|
|
69
|
+
const indexJs = join(srcDir, "index.js");
|
|
70
|
+
const indexTsExists = existsSync(indexTs);
|
|
71
|
+
const indexJsExists = existsSync(indexJs);
|
|
72
|
+
|
|
73
|
+
if (srcExists) {
|
|
74
|
+
// Determine file extension based on existing index files
|
|
75
|
+
const useTypeScript = indexTsExists;
|
|
76
|
+
const redirectFileName = useTypeScript ? "uuid-redirects.ts" : "uuid-redirects.js";
|
|
77
|
+
const importFileName = useTypeScript ? "uuid-redirects.js" : "uuid-redirects.js"; // Always import as .js (TS compilers handle this)
|
|
78
|
+
const redirectsPath = join(srcDir, redirectFileName);
|
|
79
|
+
|
|
80
|
+
await writeFile(redirectsPath, redirectsContent);
|
|
81
|
+
p.log.success(`Created ${cyan("src/" + redirectFileName)}`);
|
|
82
|
+
|
|
83
|
+
// Try to import into index.ts or index.js
|
|
84
|
+
const importStatement = `import "./${importFileName}";`;
|
|
85
|
+
|
|
86
|
+
if (indexTsExists) {
|
|
87
|
+
const indexContent = await readFile(indexTs, "utf8");
|
|
88
|
+
// Check if import already exists
|
|
89
|
+
if (!indexContent.includes("uuid-redirects")) {
|
|
90
|
+
const newIndexContent = `${importStatement}\n${indexContent}`;
|
|
91
|
+
await writeFile(indexTs, newIndexContent);
|
|
92
|
+
p.log.success(`Imported ${redirectFileName} into ${cyan("src/index.ts")}`);
|
|
93
|
+
} else {
|
|
94
|
+
p.log.info(`Import already exists in ${cyan("src/index.ts")}`);
|
|
95
|
+
}
|
|
96
|
+
} else if (indexJsExists) {
|
|
97
|
+
const indexContent = await readFile(indexJs, "utf8");
|
|
98
|
+
if (!indexContent.includes("uuid-redirects")) {
|
|
99
|
+
const newIndexContent = `${importStatement}\n${indexContent}`;
|
|
100
|
+
await writeFile(indexJs, newIndexContent);
|
|
101
|
+
p.log.success(`Imported ${redirectFileName} into ${cyan("src/index.js")}`);
|
|
102
|
+
} else {
|
|
103
|
+
p.log.info(`Import already exists in ${cyan("src/index.js")}`);
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
p.log.warn(`⚠️ No index.ts or index.js found in src/. Please manually add ${cyan(importStatement)} to your main entry file.`);
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
// No src directory - write to module root and warn
|
|
110
|
+
const redirectsPath = join(moduleDir, "uuid-redirects.js");
|
|
111
|
+
await writeFile(redirectsPath, redirectsContent);
|
|
112
|
+
p.log.warn(`⚠️ No src/ directory found. Created ${cyan("uuid-redirects.js")} in module root.`);
|
|
113
|
+
p.log.warn(`⚠️ Please manually add ${cyan('import "./uuid-redirects.js";')} to your module's main entry point.`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let note = "✅ Installed!";
|
|
117
|
+
note += `\n${commonPackNames.length} pack(s) configured for sf2e → pf2e redirect: ${cyan(commonPackNames.join(", "))}`;
|
|
118
|
+
|
|
119
|
+
p.note(note, "SF2e to PF2e UUID Redirects");
|