Skip to content

feat: use serde to build package json and check npm package name#2428

Open
mootz12 wants to merge 1 commit intomainfrom
sanitize-js-bindings-output-dir
Open

feat: use serde to build package json and check npm package name#2428
mootz12 wants to merge 1 commit intomainfrom
sanitize-js-bindings-output-dir

Conversation

@mootz12
Copy link
Contributor

@mootz12 mootz12 commented Mar 5, 2026

What

Use serde to modify package.json file during typescript binding generation. And check that the npm package name is valid.

Why

Fixes the issue where users can create invalid package.json files

Known limitations

None

Copilot AI review requested due to automatic review settings March 5, 2026 21:11
@github-project-automation github-project-automation bot moved this to Backlog (Not Ready) in DevX Mar 5, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens TypeScript bindings project generation by validating the generated npm package name and updating package.json via JSON parsing/serialization (instead of raw string replacement) to prevent invalid or injectable package.json output.

Changes:

  • Add validate_npm_package_name (with tests) to enforce npm naming rules, including scoped names.
  • Validate the --output-dir basename / contract name before generating the TS bindings project.
  • Update TS project template handling to set package.json.name through serde_json, enabling preserve_order.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
cmd/soroban-cli/src/commands/contract/bindings/typescript.rs Validates --output-dir basename as an npm package name and introduces a new CLI error variant.
cmd/crates/soroban-spec-typescript/src/lib.rs Adds npm package name validation helper and unit tests.
cmd/crates/soroban-spec-typescript/src/boilerplate.rs Switches package.json update to serde_json parsing/serialization; adds tests for name setting and invalid input.
cmd/crates/soroban-spec-typescript/Cargo.toml Enables serde_json’s preserve_order feature to keep template key ordering stable.
Cargo.lock Updates lockfile to include new transitive dependency introduced by preserve_order.

Comment on lines +87 to +88
soroban_spec_typescript::validate_npm_package_name(contract_name)
.map_err(Error::InvalidContractName)?;
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validate_npm_package_name returns an error reason string, but it’s being passed directly into Error::InvalidContractName. As a result, the error message will print the reason where it claims to print the --output-dir basename, and it won’t include the actual invalid basename. Consider changing InvalidContractName to carry both the basename and the validation reason (or format them together) and map the error with a closure so the message is accurate.

Copilot uses AI. Check for mistakes.
obj.insert(
"name".to_string(),
serde_json::Value::String(contract_name.to_string()),
);
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If package.json parses successfully but isn’t a JSON object, this silently skips updating the name field and writes the file back unchanged. Since the template is expected to be an object, it would be safer to return an InvalidData error when json.as_object_mut() is None so template regressions are caught early.

Suggested change
);
);
} else {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"package.json template must be a JSON object",
));

Copilot uses AI. Check for mistakes.
Comment on lines +251 to +254
for key in obj.keys() {
assert!(
expected_keys.contains(&key.as_str()),
"unexpected key in package.json: {key}"
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test hard-codes the complete set of top-level keys in package.json and will fail if the template is legitimately extended (e.g., adding license, files, keywords). To reduce brittleness, consider asserting that the expected keys are present (and/or that key count is unchanged) rather than rejecting any new keys.

Suggested change
for key in obj.keys() {
assert!(
expected_keys.contains(&key.as_str()),
"unexpected key in package.json: {key}"
for key in expected_keys {
assert!(
obj.contains_key(key),
"missing expected key in package.json: {key}"

Copilot uses AI. Check for mistakes.
let contract_name = &file_name
.to_str()
.ok_or_else(|| Error::NotUtf8(file_name.to_os_string()))?;
soroban_spec_typescript::validate_npm_package_name(contract_name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validate_npm_package_name is called here and then again in boilerplate.rs::init(). Not a big deal, but we'll hit it twice.

})
}

fn replace_package_json(&self, root: &Path, contract_name: &str) -> std::io::Result<()> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't use self, so maybe we could extract it as a static function?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog (Not Ready)

Development

Successfully merging this pull request may close these issues.

3 participants