sandstone-cli 2.3.2 → 2.4.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/.github/FUNDING.yml +0 -0
- package/.github/workflows/npm-publish.yml +86 -20
- package/LICENSE +0 -0
- package/README.md +6 -0
- package/bun.lock +15 -11
- package/lib/create.js +19 -3
- package/lib/create.js.map +114 -0
- package/lib/index.js +2540 -561
- package/lib/index.js.map +273 -0
- package/package.json +7 -5
- package/src/commands/build/export.ts +2 -2
- package/src/commands/build/index.ts +10 -3
- package/src/commands/create.ts +1 -1
- package/src/commands/dependency.ts +0 -0
- package/src/commands/index.ts +0 -0
- package/src/commands/watch.ts +9 -1
- package/src/create.ts +0 -0
- package/src/index.ts +0 -0
- package/src/shared.ts +0 -0
- package/src/ui/logger.ts +4 -3
- package/src/utils/source-map.ts +191 -0
- package/src/utils.ts +0 -0
- package/src/version.ts +1 -1
- package/tsconfig.json +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sandstone-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "The CLI for Sandstone - the minecraft pack creation library.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": "./lib/index.js",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"create-sandstone": "./lib/create.js"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"bundle": "bun scripts/version.ts && bun build src/index.ts --
|
|
12
|
+
"bundle": "bun scripts/version.ts && bun build src/index.ts --outdir=lib --sourcemap=external --target=bun --external=@parcel/watcher --external=figlet --external=@inquirer/prompts && bun build src/create.ts --outdir=lib --sourcemap=external --target=bun --external=@parcel/watcher --external=figlet --external=@inquirer/prompts",
|
|
13
13
|
"dev:build": "tsc && bun bundle",
|
|
14
14
|
"test:harness": "npx tsx scripts/test-harness.ts"
|
|
15
15
|
},
|
|
@@ -59,7 +59,8 @@
|
|
|
59
59
|
"node-fetch": "^3.3.2",
|
|
60
60
|
"obliterator": "^2.0.5",
|
|
61
61
|
"react": "^19.2.4",
|
|
62
|
-
"semver": "^7.5.4"
|
|
62
|
+
"semver": "^7.5.4",
|
|
63
|
+
"source-map-js": "^1.2.1"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
66
|
"@types/adm-zip": "^0.5.2",
|
|
@@ -69,10 +70,11 @@
|
|
|
69
70
|
"@types/semver": "^7.5.3",
|
|
70
71
|
"bun-types": "^1.3.9",
|
|
71
72
|
"node-pty": "^1.1.0",
|
|
72
|
-
"sandstone": "^1.0.0-beta.
|
|
73
|
+
"sandstone": "^1.0.0-beta.5",
|
|
73
74
|
"typescript": "^5.2.2"
|
|
74
75
|
},
|
|
75
76
|
"trustedDependencies": [
|
|
76
|
-
"@parcel/watcher"
|
|
77
|
+
"@parcel/watcher",
|
|
78
|
+
"node-pty"
|
|
77
79
|
]
|
|
78
80
|
}
|
|
@@ -101,9 +101,9 @@ export async function createSymlink(
|
|
|
101
101
|
|
|
102
102
|
const comment = `# Sandstone Pack: ${packName}\n`
|
|
103
103
|
try {
|
|
104
|
-
const currentlyAllowed = await fs.readFile(allowedList, 'utf-8')
|
|
104
|
+
const currentlyAllowed = (await fs.readFile(allowedList, 'utf-8')).replace(/\r/g, '')
|
|
105
105
|
|
|
106
|
-
if (
|
|
106
|
+
if (currentlyAllowed.match(new RegExp(`^${allowPath}$`, 'm')) === null) {
|
|
107
107
|
log('[symlink] Adding workspace to allowed_symlinks.txt. If the game is running please restart it.')
|
|
108
108
|
await fs.writeFile(allowedList, `${currentlyAllowed}\n#\n${comment}${allowPath}`)
|
|
109
109
|
} else {
|
|
@@ -7,6 +7,7 @@ import { split } from 'obliterator'
|
|
|
7
7
|
import type { BuildResult, ResourceCounts } from '../../ui/types.js'
|
|
8
8
|
import { log, initLoggerNoFile, setSilent } from '../../ui/logger.js'
|
|
9
9
|
import { hash } from '../../utils.js'
|
|
10
|
+
import { resolveStackTrace } from '../../utils/source-map.js'
|
|
10
11
|
|
|
11
12
|
import {
|
|
12
13
|
type SandstoneCache,
|
|
@@ -173,7 +174,7 @@ export async function loadBuildContext(
|
|
|
173
174
|
}
|
|
174
175
|
}
|
|
175
176
|
|
|
176
|
-
const sandstoneUrl = pathToFileURL(path.join(folder, 'node_modules', 'sandstone', 'dist', 'index.js'))
|
|
177
|
+
const sandstoneUrl = pathToFileURL(path.join(folder, 'node_modules', 'sandstone', 'dist', 'exports', 'index.js'))
|
|
177
178
|
/* @ts-ignore */
|
|
178
179
|
const { createSandstonePack, resetSandstonePack } = (await import(sandstoneUrl)) as typeof sandstone
|
|
179
180
|
|
|
@@ -512,7 +513,10 @@ export async function _buildCommand(
|
|
|
512
513
|
const stackLines = cleanedStack.split('\n')
|
|
513
514
|
const traceStart = stackLines.findIndex(line => line.trimStart().startsWith('at '))
|
|
514
515
|
const stackTrace = traceStart >= 0 ? stackLines.slice(traceStart).join('\n') : ''
|
|
515
|
-
|
|
516
|
+
|
|
517
|
+
// Resolve source maps for better error locations
|
|
518
|
+
const resolvedStackTrace = stackTrace ? resolveStackTrace(stackTrace) : ''
|
|
519
|
+
const formattedError = resolvedStackTrace ? `${errorMessage}\n${resolvedStackTrace}` : errorMessage
|
|
516
520
|
return {
|
|
517
521
|
success: false,
|
|
518
522
|
error: formattedError,
|
|
@@ -553,7 +557,10 @@ export async function buildCommand(opts: BuildOptions, _folder?: string, silent
|
|
|
553
557
|
const stackLines = cleanedStack.split('\n')
|
|
554
558
|
const traceStart = stackLines.findIndex(line => line.trimStart().startsWith('at '))
|
|
555
559
|
const stackTrace = traceStart >= 0 ? stackLines.slice(traceStart).join('\n') : ''
|
|
556
|
-
|
|
560
|
+
|
|
561
|
+
// Resolve source maps for better error locations
|
|
562
|
+
const resolvedStackTrace = stackTrace ? resolveStackTrace(stackTrace) : ''
|
|
563
|
+
const formattedError = resolvedStackTrace ? `${errorMessage}\n${resolvedStackTrace}` : errorMessage
|
|
557
564
|
if (!silent) {
|
|
558
565
|
log(chalk.bgRed.white('BuildError') + chalk.gray(':'), formattedError)
|
|
559
566
|
process.exit(1)
|
package/src/commands/create.ts
CHANGED
|
@@ -130,7 +130,7 @@ export async function createCommand(_project: string, opts: CreateOptions) {
|
|
|
130
130
|
|
|
131
131
|
const sv = (v: string) => new SemVer(v)
|
|
132
132
|
|
|
133
|
-
const versions = [[sv('1.0.0-beta.
|
|
133
|
+
const versions = [[sv('1.0.0-beta.5'), sv(CLI_VERSION)]] as const
|
|
134
134
|
|
|
135
135
|
const version = await select({
|
|
136
136
|
message: 'Which version of Sandstone do you want to use? These are the only supported versions for new projects.',
|
|
File without changes
|
package/src/commands/index.ts
CHANGED
|
File without changes
|
package/src/commands/watch.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { WatchUI, getWatchUIAPI } from '../ui/WatchUI.js'
|
|
|
9
9
|
import { initLogger, log, logInfo, logWarn, logError, logDebug, logTrace, setLiveLogCallback } from '../ui/logger.js'
|
|
10
10
|
import type { TrackedChange, ChangeCategory } from '../ui/types.js'
|
|
11
11
|
import { hot } from '@sandstone-mc/hot-hook'
|
|
12
|
+
import { resolveStackTrace } from '../utils/source-map.js'
|
|
12
13
|
import fs from 'fs-extra'
|
|
13
14
|
import { join, relative } from 'node:path'
|
|
14
15
|
|
|
@@ -33,7 +34,14 @@ function enableConsoleCapture() {
|
|
|
33
34
|
.replace(/^Error\n/, '')
|
|
34
35
|
.replace(/\?hot-hook=\d+/g, '')
|
|
35
36
|
.replace(/file:\/\/\/?/g, '')
|
|
36
|
-
|
|
37
|
+
|
|
38
|
+
// Resolve source maps for stack frames
|
|
39
|
+
const stackLines = cleanedStack.split('\n')
|
|
40
|
+
const traceStart = stackLines.findIndex(line => line.trimStart().startsWith('at '))
|
|
41
|
+
const stackTrace = traceStart >= 0 ? stackLines.slice(traceStart).join('\n') : ''
|
|
42
|
+
const resolvedStack = stackTrace ? resolveStackTrace(stackTrace) : cleanedStack
|
|
43
|
+
|
|
44
|
+
logTrace(...args, '\n' + resolvedStack)
|
|
37
45
|
}
|
|
38
46
|
}
|
|
39
47
|
|
package/src/create.ts
CHANGED
|
File without changes
|
package/src/index.ts
CHANGED
|
File without changes
|
package/src/shared.ts
CHANGED
|
File without changes
|
package/src/ui/logger.ts
CHANGED
|
@@ -88,13 +88,14 @@ async function logWorkerMain(level: string | false, ...args: unknown[]) {
|
|
|
88
88
|
const chunks: (string | Buffer | Uint8Array)[] = []
|
|
89
89
|
|
|
90
90
|
// Timestamp and level prefix
|
|
91
|
-
|
|
91
|
+
const prefix = `[${new Date().toISOString()}]${level !== false ? ` [${level}]` : ''} `
|
|
92
|
+
chunks.push(prefix)
|
|
92
93
|
|
|
93
94
|
// Process each argument
|
|
94
95
|
for (let i = 0; i < args.length; i++) {
|
|
95
96
|
const arg = args[i]
|
|
96
97
|
if (typeof arg === 'string') {
|
|
97
|
-
chunks.push(stripVTControlCharacters(arg))
|
|
98
|
+
chunks.push(stripVTControlCharacters(arg).replaceAll('\n', `\n${' '.repeat(prefix.length)}`))
|
|
98
99
|
} else if (Buffer.isBuffer(arg) || arg instanceof Uint8Array) {
|
|
99
100
|
chunks.push(arg)
|
|
100
101
|
} else if (arg instanceof ArrayBuffer) {
|
|
@@ -103,7 +104,7 @@ async function logWorkerMain(level: string | false, ...args: unknown[]) {
|
|
|
103
104
|
chunks.push(new Uint8Array(await arg.arrayBuffer()))
|
|
104
105
|
} else {
|
|
105
106
|
// Use util.format for objects, numbers, etc.
|
|
106
|
-
chunks.push(format('%O', arg))
|
|
107
|
+
chunks.push(stripVTControlCharacters(format('%O', arg)).replaceAll('\n', `\n${' '.repeat(prefix.length)}`))
|
|
107
108
|
}
|
|
108
109
|
// Add space between args (but not after last)
|
|
109
110
|
if (i < args.length - 1) {
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source map resolution for stack traces.
|
|
3
|
+
*
|
|
4
|
+
* Bun doesn't automatically resolve source maps for bundled dependencies,
|
|
5
|
+
* so we manually parse and resolve them for better error messages.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { SourceMapConsumer, type RawSourceMap } from 'source-map-js'
|
|
9
|
+
import { readFileSync } from 'fs'
|
|
10
|
+
import { dirname, resolve } from 'path'
|
|
11
|
+
|
|
12
|
+
// Cache for loaded source map consumers
|
|
13
|
+
const sourceMapCache = new Map<string, SourceMapConsumer | null>()
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Synchronously load a source map for a given JS file.
|
|
17
|
+
* Returns null if no source map is found or it's invalid.
|
|
18
|
+
*/
|
|
19
|
+
function loadSourceMapSync(jsFilePath: string): SourceMapConsumer | null {
|
|
20
|
+
// Check cache first
|
|
21
|
+
if (sourceMapCache.has(jsFilePath)) {
|
|
22
|
+
return sourceMapCache.get(jsFilePath) ?? null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
// Read the JS file to find the sourceMappingURL
|
|
27
|
+
const jsContent = readFileSync(jsFilePath, 'utf8')
|
|
28
|
+
|
|
29
|
+
// Look for sourceMappingURL comment
|
|
30
|
+
const match = jsContent.match(/\/\/[#@]\s*sourceMappingURL=(.+)$/m)
|
|
31
|
+
if (!match) {
|
|
32
|
+
sourceMapCache.set(jsFilePath, null)
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const sourceMappingURL = match[1].trim()
|
|
37
|
+
let mapPath: string
|
|
38
|
+
let mapContent: string
|
|
39
|
+
|
|
40
|
+
if (sourceMappingURL.startsWith('data:')) {
|
|
41
|
+
// Inline source map (base64 encoded)
|
|
42
|
+
const base64Match = sourceMappingURL.match(/base64,(.+)/)
|
|
43
|
+
if (!base64Match) {
|
|
44
|
+
sourceMapCache.set(jsFilePath, null)
|
|
45
|
+
return null
|
|
46
|
+
}
|
|
47
|
+
mapContent = Buffer.from(base64Match[1], 'base64').toString('utf8')
|
|
48
|
+
} else {
|
|
49
|
+
// External source map file
|
|
50
|
+
mapPath = resolve(dirname(jsFilePath), sourceMappingURL)
|
|
51
|
+
mapContent = readFileSync(mapPath, 'utf8')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const rawMap: RawSourceMap = JSON.parse(mapContent)
|
|
55
|
+
const consumer = new SourceMapConsumer(rawMap)
|
|
56
|
+
sourceMapCache.set(jsFilePath, consumer)
|
|
57
|
+
return consumer
|
|
58
|
+
} catch {
|
|
59
|
+
sourceMapCache.set(jsFilePath, null)
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface StackFrame {
|
|
65
|
+
original: string
|
|
66
|
+
filePath?: string
|
|
67
|
+
line?: number
|
|
68
|
+
column?: number
|
|
69
|
+
functionName?: string
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Parse a single stack trace line.
|
|
74
|
+
*/
|
|
75
|
+
function parseStackLine(line: string): StackFrame {
|
|
76
|
+
// Match patterns like:
|
|
77
|
+
// " at functionName (/path/to/file.js:123:45)"
|
|
78
|
+
// " at /path/to/file.js:123:45"
|
|
79
|
+
// " at async functionName (/path/to/file.js:123:45)"
|
|
80
|
+
const patterns = [
|
|
81
|
+
// Standard format: at functionName (file:line:col)
|
|
82
|
+
/^\s*at\s+(?:async\s+)?(.+?)\s+\((.+?):(\d+):(\d+)\)$/,
|
|
83
|
+
// Anonymous format: at file:line:col
|
|
84
|
+
/^\s*at\s+(?:async\s+)?(.+?):(\d+):(\d+)$/,
|
|
85
|
+
// Format with <anonymous>: at <anonymous> (file:line:col)
|
|
86
|
+
/^\s*at\s+<anonymous>\s+\((.+?):(\d+):(\d+)\)$/,
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
for (const pattern of patterns) {
|
|
90
|
+
const match = line.match(pattern)
|
|
91
|
+
if (match) {
|
|
92
|
+
if (match.length === 5) {
|
|
93
|
+
// Pattern with function name
|
|
94
|
+
return {
|
|
95
|
+
original: line,
|
|
96
|
+
functionName: match[1],
|
|
97
|
+
filePath: match[2],
|
|
98
|
+
line: parseInt(match[3], 10),
|
|
99
|
+
column: parseInt(match[4], 10),
|
|
100
|
+
}
|
|
101
|
+
} else if (match.length === 4) {
|
|
102
|
+
// Pattern without function name or <anonymous>
|
|
103
|
+
return {
|
|
104
|
+
original: line,
|
|
105
|
+
filePath: match[1],
|
|
106
|
+
line: parseInt(match[2], 10),
|
|
107
|
+
column: parseInt(match[3], 10),
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return { original: line }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Resolve a stack frame using source maps (synchronous).
|
|
118
|
+
*/
|
|
119
|
+
function resolveStackFrame(frame: StackFrame): string {
|
|
120
|
+
if (!frame.filePath || !frame.line || !frame.column) {
|
|
121
|
+
return frame.original
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Skip native or internal frames
|
|
125
|
+
if (frame.filePath.includes('(native)') || frame.filePath === 'native') {
|
|
126
|
+
return frame.original
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
const consumer = loadSourceMapSync(frame.filePath)
|
|
131
|
+
if (!consumer) {
|
|
132
|
+
return frame.original
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const pos = consumer.originalPositionFor({
|
|
136
|
+
line: frame.line,
|
|
137
|
+
column: frame.column - 1, // source-map uses 0-based columns
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
if (pos.source && pos.line !== null) {
|
|
141
|
+
// Resolve the source path relative to the JS file
|
|
142
|
+
const sourceDir = dirname(frame.filePath)
|
|
143
|
+
const originalPath = resolve(sourceDir, pos.source)
|
|
144
|
+
|
|
145
|
+
// Use source map name if available, then fall back to frame's function name
|
|
146
|
+
// The frame's function name comes from the runtime stack and is often correct
|
|
147
|
+
// even when the source map doesn't have name mappings
|
|
148
|
+
const functionPart = pos.name ?? frame.functionName ?? '<anonymous>'
|
|
149
|
+
const location = `${originalPath}:${pos.line}:${(pos.column ?? 0) + 1}`
|
|
150
|
+
|
|
151
|
+
if (functionPart) {
|
|
152
|
+
return ` at ${functionPart} (${location})`
|
|
153
|
+
}
|
|
154
|
+
return ` at ${location}`
|
|
155
|
+
}
|
|
156
|
+
} catch {
|
|
157
|
+
// If resolution fails, return original
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return frame.original
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Resolve source maps in a stack trace string (synchronous).
|
|
165
|
+
* Returns the stack trace with original source locations where possible.
|
|
166
|
+
*/
|
|
167
|
+
export function resolveStackTrace(stack: string): string {
|
|
168
|
+
const lines = stack.split('\n')
|
|
169
|
+
const resolvedLines: string[] = []
|
|
170
|
+
|
|
171
|
+
for (const line of lines) {
|
|
172
|
+
// Only process lines that look like stack frames
|
|
173
|
+
if (line.trimStart().startsWith('at ')) {
|
|
174
|
+
const frame = parseStackLine(line)
|
|
175
|
+
const resolved = resolveStackFrame(frame)
|
|
176
|
+
resolvedLines.push(resolved)
|
|
177
|
+
} else {
|
|
178
|
+
resolvedLines.push(line)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return resolvedLines.join('\n')
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Clear the source map cache.
|
|
187
|
+
* Call this between builds if source maps may have changed.
|
|
188
|
+
*/
|
|
189
|
+
export function clearSourceMapCache(): void {
|
|
190
|
+
sourceMapCache.clear()
|
|
191
|
+
}
|
package/src/utils.ts
CHANGED
|
File without changes
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = '2.
|
|
1
|
+
export const CLI_VERSION = '2.4.1'
|
package/tsconfig.json
CHANGED
|
File without changes
|