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.
Files changed (35) hide show
  1. package/README.md +2 -2
  2. package/addons/github-workflow/main.yml +91 -43
  3. package/addons/github-workflow/{setup.ts → setup.mjs} +29 -26
  4. package/addons/sf2e-pf2e-redirects/addon.json +5 -0
  5. package/addons/sf2e-pf2e-redirects/setup.mjs +119 -0
  6. package/dist/bin.js +223 -84
  7. package/dist/bin.js.map +1 -1
  8. package/dist/migrate.d.ts +2 -0
  9. package/dist/migrate.d.ts.map +1 -0
  10. package/dist/migrate.js +169 -0
  11. package/dist/migrate.js.map +1 -0
  12. package/dist/options.d.ts +5 -2
  13. package/dist/options.d.ts.map +1 -1
  14. package/dist/options.js +14 -5
  15. package/dist/options.js.map +1 -1
  16. package/package.json +7 -7
  17. package/templates/vite/.env.example +1 -1
  18. package/templates/vite/CHANGELOG +1 -0
  19. package/templates/vite/gitignore +37 -37
  20. package/templates/vite/module.json +37 -36
  21. package/templates/vite/package.json +5 -4
  22. package/templates/vite/scripts/extractPacks.mjs +54 -49
  23. package/templates/vite/scripts/jsonReplacer.mjs +11 -0
  24. package/templates/vite/scripts/onCreate.mjs +41 -13
  25. package/templates/vite/scripts/symlink.mjs +78 -78
  26. package/templates/vite/src/adventureSheet/index.js +497 -497
  27. package/templates/vite/src/hooks.ts +22 -0
  28. package/templates/vite/src/index.js +4 -4
  29. package/templates/vite/src/lib/utils.ts +1 -0
  30. package/templates/vite/src/misc/prosemirror.js +46 -46
  31. package/templates/vite/src/module.css +306 -306
  32. package/templates/vite/src/types.d.ts +7 -7
  33. package/templates/vite/tsconfig.json +33 -0
  34. package/templates/vite/vite.config.ts +129 -128
  35. 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
- Then run it from anywhere:
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
- release:
5
- types: [published]
4
+ release:
5
+ types: [published]
6
6
 
7
7
  jobs:
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 ci
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/
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
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
- features: () =>
14
- p.multiselect({
15
- message: "Additional features?",
16
- initialValues: ["ftp", "discord"],
16
+ {
17
+ features: () =>
18
+ p.multiselect({
19
+ message: "Additional features?",
20
+ initialValues: ["ftp", "discord"],
17
21
  required: false,
18
- options: [
19
- // { label: "Prereleases", value: "prereleases" },
20
- { label: "Uploading via FTP", value: "ftp" },
21
- { label: "Discord webhook on updates", value: "discord" },
22
- ],
23
- }),
24
- },
25
- { onCancel: () => process.exit(0) },
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 addonDir = import.meta.dir;
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
- mainYml += `
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}}" >> "$GITHUB_OUTPUT"
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}}" >> "$GITHUB_OUTPUT"
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}}" >> "$GITHUB_OUTPUT"
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
- mainYml += `
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
- mainYml += `
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 Bun.write(`${workflowDir}/main.yml`, mainYml);
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
- note +=
108
- "\n - For the Discord integration, make sure to create a DISCORD_WEBHOOK secret with the webhook url.";
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
- 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")}.`;
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,5 @@
1
+ {
2
+ "name": "SF2e <=> PF2e UUID Redirects",
3
+ "description": "Adds UUID redirects for modules that support both SF2e and PF2e. Skipped if module doesn't support both systems.",
4
+ "default": false
5
+ }
@@ -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");