redscript-mc 1.2.19 → 1.2.20

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.
@@ -2,7 +2,8 @@
2
2
  * Compile-all smoke test
3
3
  *
4
4
  * Finds every .mcrs file in the repo (excluding declaration files and node_modules)
5
- * and verifies that each one compiles without throwing an error.
5
+ * and verifies that each one compiles without errors via the CLI (which handles
6
+ * `import` statements, unlike the bare `compile()` function).
6
7
  *
7
8
  * This catches regressions where a language change breaks existing source files.
8
9
  */
@@ -3,7 +3,8 @@
3
3
  * Compile-all smoke test
4
4
  *
5
5
  * Finds every .mcrs file in the repo (excluding declaration files and node_modules)
6
- * and verifies that each one compiles without throwing an error.
6
+ * and verifies that each one compiles without errors via the CLI (which handles
7
+ * `import` statements, unlike the bare `compile()` function).
7
8
  *
8
9
  * This catches regressions where a language change breaks existing source files.
9
10
  */
@@ -43,8 +44,10 @@ var __importStar = (this && this.__importStar) || (function () {
43
44
  Object.defineProperty(exports, "__esModule", { value: true });
44
45
  const fs = __importStar(require("fs"));
45
46
  const path = __importStar(require("path"));
46
- const compile_1 = require("../compile");
47
+ const child_process_1 = require("child_process");
48
+ const os = __importStar(require("os"));
47
49
  const REPO_ROOT = path.resolve(__dirname, '../../');
50
+ const CLI = path.join(REPO_ROOT, 'dist', 'cli.js');
48
51
  /** Patterns to skip */
49
52
  const SKIP_GLOBS = [
50
53
  'node_modules',
@@ -72,18 +75,28 @@ function findMcrsFiles(dir) {
72
75
  return results;
73
76
  }
74
77
  const mcrsFiles = findMcrsFiles(REPO_ROOT);
75
- describe('compile-all: every .mcrs file should compile without errors', () => {
78
+ const TMP_OUT = path.join(os.tmpdir(), 'redscript-compile-all');
79
+ describe('compile-all: every .mcrs file should compile without errors (CLI)', () => {
76
80
  test('found at least one .mcrs file', () => {
77
81
  expect(mcrsFiles.length).toBeGreaterThan(0);
78
82
  });
79
83
  for (const filePath of mcrsFiles) {
80
84
  const label = path.relative(REPO_ROOT, filePath);
81
85
  test(label, () => {
82
- const source = fs.readFileSync(filePath, 'utf8');
83
- // Should not throw
84
- expect(() => {
85
- (0, compile_1.compile)(source, { namespace: 'smoke_test', optimize: false });
86
- }).not.toThrow();
86
+ const outDir = path.join(TMP_OUT, label.replace(/[^a-zA-Z0-9]/g, '_'));
87
+ let stdout = '';
88
+ let stderr = '';
89
+ try {
90
+ const result = (0, child_process_1.execSync)(`node "${CLI}" compile "${filePath}" -o "${outDir}"`, { encoding: 'utf8', stdio: 'pipe' });
91
+ stdout = result;
92
+ }
93
+ catch (err) {
94
+ stdout = err.stdout ?? '';
95
+ stderr = err.stderr ?? '';
96
+ const output = (stdout + stderr).trim();
97
+ // Fail with the compiler error message
98
+ throw new Error(`Compile failed for ${label}:\n${output}`);
99
+ }
87
100
  });
88
101
  }
89
102
  });
package/dist/cli.js CHANGED
@@ -51,6 +51,8 @@ const repl_1 = require("./repl");
51
51
  const metadata_1 = require("./builtins/metadata");
52
52
  const fs = __importStar(require("fs"));
53
53
  const path = __importStar(require("path"));
54
+ const https = __importStar(require("https"));
55
+ const child_process_1 = require("child_process");
54
56
  // Parse command line arguments
55
57
  const args = process.argv.slice(2);
56
58
  function printUsage() {
@@ -74,6 +76,7 @@ Commands:
74
76
  generate-dts Generate builtin function declaration file (builtins.d.mcrs)
75
77
  repl Start an interactive RedScript REPL
76
78
  version Print the RedScript version
79
+ upgrade Upgrade to the latest version (npm install -g redscript-mc@latest)
77
80
 
78
81
  Options:
79
82
  -o, --output <path> Output directory or file path, depending on target
@@ -92,15 +95,90 @@ Targets:
92
95
  structure Generate a Minecraft structure .nbt file with command blocks
93
96
  `);
94
97
  }
95
- function printVersion() {
98
+ function getLocalVersion() {
96
99
  const packagePath = path.join(__dirname, '..', 'package.json');
97
100
  try {
98
101
  const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
99
- console.log(`RedScript v${pkg.version}`);
102
+ return pkg.version ?? '0.0.0';
100
103
  }
101
104
  catch {
102
- console.log('RedScript v0.1.0');
105
+ return '0.0.0';
106
+ }
107
+ }
108
+ function printVersion() {
109
+ console.log(`RedScript v${getLocalVersion()}`);
110
+ }
111
+ /** Fetch latest version from npm registry (non-blocking, best-effort). */
112
+ function fetchLatestVersion() {
113
+ return new Promise(resolve => {
114
+ const req = https.get('https://registry.npmjs.org/redscript-mc/latest', { timeout: 3000 }, res => {
115
+ let data = '';
116
+ res.on('data', chunk => { data += chunk; });
117
+ res.on('end', () => {
118
+ try {
119
+ const json = JSON.parse(data);
120
+ resolve(json.version ?? null);
121
+ }
122
+ catch {
123
+ resolve(null);
124
+ }
125
+ });
126
+ });
127
+ req.on('error', () => resolve(null));
128
+ req.on('timeout', () => { req.destroy(); resolve(null); });
129
+ });
130
+ }
131
+ /** Compare semver strings. Returns true if b > a. */
132
+ function isNewer(current, latest) {
133
+ const parse = (v) => v.replace(/^v/, '').split('.').map(Number);
134
+ const [ca, cb, cc] = parse(current);
135
+ const [la, lb, lc] = parse(latest);
136
+ if (la !== ca)
137
+ return la > ca;
138
+ if (lb !== cb)
139
+ return lb > cb;
140
+ return lc > cc;
141
+ }
142
+ /**
143
+ * Check for a newer version and print a notice if one exists.
144
+ * Runs in background — does NOT block normal CLI operation.
145
+ */
146
+ async function checkForUpdates(silent = false) {
147
+ const current = getLocalVersion();
148
+ const latest = await fetchLatestVersion();
149
+ if (latest && isNewer(current, latest)) {
150
+ console.log(`\nšŸ’” New version available: v${current} → v${latest}`);
151
+ console.log(` Run: redscript upgrade\n`);
103
152
  }
153
+ else if (!silent && latest) {
154
+ // Only print when explicitly running 'version' or 'upgrade'
155
+ // No output for normal commands — keep startup noise-free
156
+ }
157
+ }
158
+ /** Run npm install -g to upgrade to latest. */
159
+ function upgradeCommand() {
160
+ const current = getLocalVersion();
161
+ console.log(`Current version: v${current}`);
162
+ console.log('Checking latest version...');
163
+ fetchLatestVersion().then(latest => {
164
+ if (!latest) {
165
+ console.error('Could not fetch latest version from npm.');
166
+ process.exit(1);
167
+ }
168
+ if (!isNewer(current, latest)) {
169
+ console.log(`āœ… Already up to date (v${current})`);
170
+ return;
171
+ }
172
+ console.log(`Upgrading v${current} → v${latest}...`);
173
+ try {
174
+ (0, child_process_1.execSync)('npm install -g redscript-mc@latest', { stdio: 'inherit' });
175
+ console.log(`āœ… Upgraded to v${latest}`);
176
+ }
177
+ catch {
178
+ console.error('Upgrade failed. Try manually: npm install -g redscript-mc@latest');
179
+ process.exit(1);
180
+ }
181
+ });
104
182
  }
105
183
  function parseArgs(args) {
106
184
  const result = { dce: true };
@@ -369,6 +447,12 @@ async function main() {
369
447
  printUsage();
370
448
  process.exit(parsed.help ? 0 : 1);
371
449
  }
450
+ // Background update check — non-blocking, only shows notice if newer version exists
451
+ // Skip for repl/upgrade/version to avoid double-printing
452
+ const noCheckCmds = new Set(['upgrade', 'update', 'version', 'repl']);
453
+ if (!noCheckCmds.has(parsed.command ?? '')) {
454
+ checkForUpdates().catch(() => { });
455
+ }
372
456
  switch (parsed.command) {
373
457
  case 'compile':
374
458
  if (!parsed.file) {
@@ -429,6 +513,11 @@ async function main() {
429
513
  break;
430
514
  case 'version':
431
515
  printVersion();
516
+ await checkForUpdates();
517
+ break;
518
+ case 'upgrade':
519
+ case 'update':
520
+ upgradeCommand();
432
521
  break;
433
522
  default:
434
523
  console.error(`Error: Unknown command '${parsed.command}'`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "redscript-mc",
3
- "version": "1.2.19",
3
+ "version": "1.2.20",
4
4
  "description": "A high-level programming language that compiles to Minecraft datapacks",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -2,16 +2,19 @@
2
2
  * Compile-all smoke test
3
3
  *
4
4
  * Finds every .mcrs file in the repo (excluding declaration files and node_modules)
5
- * and verifies that each one compiles without throwing an error.
5
+ * and verifies that each one compiles without errors via the CLI (which handles
6
+ * `import` statements, unlike the bare `compile()` function).
6
7
  *
7
8
  * This catches regressions where a language change breaks existing source files.
8
9
  */
9
10
 
10
11
  import * as fs from 'fs'
11
12
  import * as path from 'path'
12
- import { compile } from '../compile'
13
+ import { execSync } from 'child_process'
14
+ import * as os from 'os'
13
15
 
14
16
  const REPO_ROOT = path.resolve(__dirname, '../../')
17
+ const CLI = path.join(REPO_ROOT, 'dist', 'cli.js')
15
18
 
16
19
  /** Patterns to skip */
17
20
  const SKIP_GLOBS = [
@@ -41,8 +44,9 @@ function findMcrsFiles(dir: string): string[] {
41
44
  }
42
45
 
43
46
  const mcrsFiles = findMcrsFiles(REPO_ROOT)
47
+ const TMP_OUT = path.join(os.tmpdir(), 'redscript-compile-all')
44
48
 
45
- describe('compile-all: every .mcrs file should compile without errors', () => {
49
+ describe('compile-all: every .mcrs file should compile without errors (CLI)', () => {
46
50
  test('found at least one .mcrs file', () => {
47
51
  expect(mcrsFiles.length).toBeGreaterThan(0)
48
52
  })
@@ -50,11 +54,22 @@ describe('compile-all: every .mcrs file should compile without errors', () => {
50
54
  for (const filePath of mcrsFiles) {
51
55
  const label = path.relative(REPO_ROOT, filePath)
52
56
  test(label, () => {
53
- const source = fs.readFileSync(filePath, 'utf8')
54
- // Should not throw
55
- expect(() => {
56
- compile(source, { namespace: 'smoke_test', optimize: false })
57
- }).not.toThrow()
57
+ const outDir = path.join(TMP_OUT, label.replace(/[^a-zA-Z0-9]/g, '_'))
58
+ let stdout = ''
59
+ let stderr = ''
60
+ try {
61
+ const result = execSync(
62
+ `node "${CLI}" compile "${filePath}" -o "${outDir}"`,
63
+ { encoding: 'utf8', stdio: 'pipe' }
64
+ )
65
+ stdout = result
66
+ } catch (err: any) {
67
+ stdout = err.stdout ?? ''
68
+ stderr = err.stderr ?? ''
69
+ const output = (stdout + stderr).trim()
70
+ // Fail with the compiler error message
71
+ throw new Error(`Compile failed for ${label}:\n${output}`)
72
+ }
58
73
  })
59
74
  }
60
75
  })
package/src/cli.ts CHANGED
@@ -18,6 +18,8 @@ import { generateDts } from './builtins/metadata'
18
18
  import type { OptimizationStats } from './optimizer/commands'
19
19
  import * as fs from 'fs'
20
20
  import * as path from 'path'
21
+ import * as https from 'https'
22
+ import { execSync } from 'child_process'
21
23
 
22
24
  // Parse command line arguments
23
25
  const args = process.argv.slice(2)
@@ -43,6 +45,7 @@ Commands:
43
45
  generate-dts Generate builtin function declaration file (builtins.d.mcrs)
44
46
  repl Start an interactive RedScript REPL
45
47
  version Print the RedScript version
48
+ upgrade Upgrade to the latest version (npm install -g redscript-mc@latest)
46
49
 
47
50
  Options:
48
51
  -o, --output <path> Output directory or file path, depending on target
@@ -62,16 +65,96 @@ Targets:
62
65
  `)
63
66
  }
64
67
 
65
- function printVersion(): void {
68
+ function getLocalVersion(): string {
66
69
  const packagePath = path.join(__dirname, '..', 'package.json')
67
70
  try {
68
71
  const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf-8'))
69
- console.log(`RedScript v${pkg.version}`)
72
+ return pkg.version ?? '0.0.0'
70
73
  } catch {
71
- console.log('RedScript v0.1.0')
74
+ return '0.0.0'
75
+ }
76
+ }
77
+
78
+ function printVersion(): void {
79
+ console.log(`RedScript v${getLocalVersion()}`)
80
+ }
81
+
82
+ /** Fetch latest version from npm registry (non-blocking, best-effort). */
83
+ function fetchLatestVersion(): Promise<string | null> {
84
+ return new Promise(resolve => {
85
+ const req = https.get(
86
+ 'https://registry.npmjs.org/redscript-mc/latest',
87
+ { timeout: 3000 },
88
+ res => {
89
+ let data = ''
90
+ res.on('data', chunk => { data += chunk })
91
+ res.on('end', () => {
92
+ try {
93
+ const json = JSON.parse(data)
94
+ resolve(json.version ?? null)
95
+ } catch {
96
+ resolve(null)
97
+ }
98
+ })
99
+ }
100
+ )
101
+ req.on('error', () => resolve(null))
102
+ req.on('timeout', () => { req.destroy(); resolve(null) })
103
+ })
104
+ }
105
+
106
+ /** Compare semver strings. Returns true if b > a. */
107
+ function isNewer(current: string, latest: string): boolean {
108
+ const parse = (v: string) => v.replace(/^v/, '').split('.').map(Number)
109
+ const [ca, cb, cc] = parse(current)
110
+ const [la, lb, lc] = parse(latest)
111
+ if (la !== ca) return la > ca
112
+ if (lb !== cb) return lb > cb
113
+ return lc > cc
114
+ }
115
+
116
+ /**
117
+ * Check for a newer version and print a notice if one exists.
118
+ * Runs in background — does NOT block normal CLI operation.
119
+ */
120
+ async function checkForUpdates(silent = false): Promise<void> {
121
+ const current = getLocalVersion()
122
+ const latest = await fetchLatestVersion()
123
+ if (latest && isNewer(current, latest)) {
124
+ console.log(`\nšŸ’” New version available: v${current} → v${latest}`)
125
+ console.log(` Run: redscript upgrade\n`)
126
+ } else if (!silent && latest) {
127
+ // Only print when explicitly running 'version' or 'upgrade'
128
+ // No output for normal commands — keep startup noise-free
72
129
  }
73
130
  }
74
131
 
132
+ /** Run npm install -g to upgrade to latest. */
133
+ function upgradeCommand(): void {
134
+ const current = getLocalVersion()
135
+ console.log(`Current version: v${current}`)
136
+ console.log('Checking latest version...')
137
+
138
+ fetchLatestVersion().then(latest => {
139
+ if (!latest) {
140
+ console.error('Could not fetch latest version from npm.')
141
+ process.exit(1)
142
+ }
143
+ if (!isNewer(current, latest)) {
144
+ console.log(`āœ… Already up to date (v${current})`)
145
+ return
146
+ }
147
+ console.log(`Upgrading v${current} → v${latest}...`)
148
+ try {
149
+ execSync('npm install -g redscript-mc@latest', { stdio: 'inherit' })
150
+ console.log(`āœ… Upgraded to v${latest}`)
151
+ } catch {
152
+ console.error('Upgrade failed. Try manually: npm install -g redscript-mc@latest')
153
+ process.exit(1)
154
+ }
155
+ })
156
+ }
157
+
75
158
  function parseArgs(args: string[]): {
76
159
  command?: string
77
160
  file?: string
@@ -378,6 +461,13 @@ async function main(): Promise<void> {
378
461
  process.exit(parsed.help ? 0 : 1)
379
462
  }
380
463
 
464
+ // Background update check — non-blocking, only shows notice if newer version exists
465
+ // Skip for repl/upgrade/version to avoid double-printing
466
+ const noCheckCmds = new Set(['upgrade', 'update', 'version', 'repl'])
467
+ if (!noCheckCmds.has(parsed.command ?? '')) {
468
+ checkForUpdates().catch(() => { /* ignore */ })
469
+ }
470
+
381
471
  switch (parsed.command) {
382
472
  case 'compile':
383
473
  if (!parsed.file) {
@@ -458,6 +548,12 @@ async function main(): Promise<void> {
458
548
 
459
549
  case 'version':
460
550
  printVersion()
551
+ await checkForUpdates()
552
+ break
553
+
554
+ case 'upgrade':
555
+ case 'update':
556
+ upgradeCommand()
461
557
  break
462
558
 
463
559
  default: