semantic-release-steam 2.0.0 → 2.1.1

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 CHANGED
@@ -196,9 +196,13 @@ After that, every push to `main` / `beta` will trigger an update via this plugin
196
196
 
197
197
  ## Example `.steamignore`
198
198
 
199
- Place at the root of each mod's `path` to exclude files from the upload. Patterns are passed to `rsync --exclude-from`.
199
+ Place at the root of each mod's `path` to exclude files from the upload. Patterns use rsync exclude syntax, plus gitignore-style `!` negation to re-include something a broader pattern would exclude. Later patterns win over earlier ones (gitignore semantics), so put negations after the patterns they override.
200
200
 
201
201
  ```
202
+ # Keep .run/ even though dotfiles below are excluded
203
+ .*
204
+ !.run/
205
+
202
206
  # Source control
203
207
  .git
204
208
  .gitignore
@@ -1,5 +1,4 @@
1
- import { access, mkdtemp } from 'node:fs/promises';
2
- import { constants } from 'node:fs';
1
+ import { mkdtemp, readFile } from 'node:fs/promises';
3
2
  import { tmpdir } from 'node:os';
4
3
  import { join } from 'node:path';
5
4
  import { execFile } from 'node:child_process';
@@ -7,14 +6,39 @@ import { promisify } from 'node:util';
7
6
 
8
7
  const execFileAsync = promisify(execFile);
9
8
 
9
+ function buildFilterArgs(content) {
10
+ const rules = [];
11
+
12
+ for (const raw of content.split('\n')) {
13
+ const line = raw.trim();
14
+ if (!line || line.startsWith('#')) {
15
+ continue;
16
+ }
17
+ if (line.startsWith('!')) {
18
+ const pattern = line.slice(1).trim();
19
+ if (pattern) {
20
+ rules.push(`+ ${pattern}`);
21
+ }
22
+ continue;
23
+ }
24
+ rules.push(`- ${line}`);
25
+ }
26
+
27
+ // .steamignore is last-match-wins (gitignore semantics); rsync filters are
28
+ // first-match-wins, so reverse the rule order to preserve precedence.
29
+ rules.reverse();
30
+
31
+ return rules.map((rule) => `--filter=${rule}`);
32
+ }
33
+
10
34
  export async function stageModContent({ modPath }) {
11
35
  const stagePath = await mkdtemp(join(tmpdir(), 'steam-release-'));
12
36
  const ignorePath = join(modPath, '.steamignore');
13
37
  const args = ['-av'];
14
38
 
15
39
  try {
16
- await access(ignorePath, constants.F_OK);
17
- args.push(`--exclude-from=${ignorePath}`, '--exclude=.steamignore');
40
+ const content = await readFile(ignorePath, 'utf8');
41
+ args.push('--exclude=.steamignore', ...buildFilterArgs(content));
18
42
  } catch {
19
43
  }
20
44
 
package/lib/vdf.mjs CHANGED
@@ -1,5 +1,10 @@
1
1
  function escapeVdfValue(value) {
2
- return String(value ?? '').replaceAll('"', '\\"');
2
+ let open = true;
3
+ return String(value ?? '').replace(/"/g, () => {
4
+ const quote = open ? '“' : '”';
5
+ open = !open;
6
+ return quote;
7
+ });
3
8
  }
4
9
 
5
10
  function appendOptional(lines, key, value) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "semantic-release-steam",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "semantic-release plugin that publishes a Steam Workshop item from a built mod directory.",
5
5
  "type": "module",
6
6
  "main": "index.mjs",