Skip to content

Fix PackageToJS plugin wasm-opt fallback when output file exists #401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Plugins/PackageToJS/Sources/PackageToJS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,11 @@ extension PackagingSystem {
final class DefaultPackagingSystem: PackagingSystem {

private let printWarning: (String) -> Void
private let which: (String) throws -> URL

init(printWarning: @escaping (String) -> Void) {
init(printWarning: @escaping (String) -> Void, which: @escaping (String) throws -> URL = which(_:)) {
self.printWarning = printWarning
self.which = which
}

func npmInstall(packageDir: String) throws {
Expand All @@ -309,6 +311,10 @@ final class DefaultPackagingSystem: PackagingSystem {
func wasmOpt(_ arguments: [String], input: String, output: String) throws {
guard let wasmOpt = try? which("wasm-opt") else {
_ = warnMissingWasmOpt
// Remove existing output file if it exists (to match wasm-opt behavior)
if FileManager.default.fileExists(atPath: output) {
try FileManager.default.removeItem(atPath: output)
}
try FileManager.default.copyItem(atPath: input, toPath: output)
return
}
Expand Down
60 changes: 60 additions & 0 deletions Plugins/PackageToJS/Tests/DefaultPackagingSystemTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Foundation
import Testing

@testable import PackageToJS

@Suite struct DefaultPackagingSystemTests {

@Test func wasmOptFallbackHandlesNewOutputFile() throws {
try withTemporaryDirectory { tempDir, _ in
let inputFile = tempDir.appendingPathComponent("input.wasm")
let outputFile = tempDir.appendingPathComponent("output.wasm")
let inputContent = Data("input wasm content".utf8)
try inputContent.write(to: inputFile)

var warnings: [String] = []
// Create system with mock which function that always fails to find wasm-opt
let system = DefaultPackagingSystem(
printWarning: { warnings.append($0) },
which: { _ in throw PackageToJSError("wasm-opt not found") }
)

// This should work - fallback should copy file
try system.wasmOpt(["-Os"], input: inputFile.path, output: outputFile.path)

// Verify the output file was created with input content
let finalContent = try Data(contentsOf: outputFile)
#expect(finalContent == inputContent)
#expect(warnings.contains { $0.contains("wasm-opt is not installed") })
}
}

@Test func wasmOptFallbackHandlesExistingOutputFile() throws {
try withTemporaryDirectory { tempDir, _ in
let inputFile = tempDir.appendingPathComponent("input.wasm")
let outputFile = tempDir.appendingPathComponent("output.wasm")
let inputContent = Data("input wasm content".utf8)
let existingContent = Data("existing output content".utf8)

// Create input file and existing output file
try inputContent.write(to: inputFile)
try existingContent.write(to: outputFile)

var warnings: [String] = []
// Create system with mock which function that always fails to find wasm-opt
let system = DefaultPackagingSystem(
printWarning: { warnings.append($0) },
which: { _ in throw PackageToJSError("wasm-opt not found") }
)

// This should work - fallback should overwrite existing file
try system.wasmOpt(["-Os"], input: inputFile.path, output: outputFile.path)

// Verify the output file was overwritten with input content
let finalContent = try Data(contentsOf: outputFile)
#expect(finalContent == inputContent)
#expect(finalContent != existingContent)
#expect(warnings.contains { $0.contains("wasm-opt is not installed") })
}
}
}