feat: add shell script formatting support & rebrand to cc-format#33
feat: add shell script formatting support & rebrand to cc-format#33wysaid wants to merge 1 commit into
Conversation
- Add @cc-format/shell package with hybrid shfmt/WASM formatting engine - Uses local shfmt binary when available, falls back to sh-syntax WASM - Supports POSIX, Bash, mksh, Bats shell variants - Fix: skip LangAuto when calling WASM parser (causes runtime panic) - Fix: use 'export type' for TypeScript-only types in index.ts - Rebrand from clion-cmake-format to cc-format (multi-language formatter) - Package name: cc-format (VS Code), @cc-format/cli, @cc-format/core, @cc-format/shell - Config namespace: clionCMakeFormatter.* -> ccFormat.cmake.* + ccFormat.shell.* - Command IDs: clion-cmake-format.* -> cc-format.* - Repository URL: wysaid/cc-format - Extend CLI (@cc-format/cli) for shell formatting - Auto-detect language by file extension - New options: --language, --shfmt-path, --shell-indent, --shell-variant, --shell-bn/ci/sr/kp/fn - Extend VS Code extension with shellscript language support - Register shellscript document formatting provider - Add ccFormat.shell.* configuration options - Update activationEvents for onLanguage:shellscript - Update cc-format.schema.json and sample.cc-format.jsonc with shell options - Add shell formatter unit tests (test/shell.test.ts, 17 test cases) - Update CLI test assertion to match new multi-language description
WalkthroughThis PR rebrands the project from ChangesShell Formatting & cc-format Rebranding
Sequence Diagram(s)sequenceDiagram
participant User
participant CLI
participant Lang as Language<br/>Detector
participant CMake as CMake<br/>Formatter
participant Shell as Shell<br/>Formatter
User->>CLI: run with files
CLI->>Lang: detectLanguage(file)
alt CMake file
Lang-->>CLI: cmake
CLI->>CMake: formatCMake(text, opts)
CMake-->>CLI: formatted
else Shell file
Lang-->>CLI: shell
CLI->>Shell: formatShell(text, opts)
Shell-->>CLI: formatted
else Unknown
Lang-->>CLI: unknown
CLI->>CMake: formatCMake(text, opts)
CMake-->>CLI: formatted
end
CLI-->>User: output (file/stdout)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/vscode/src/configEditorProvider.ts (2)
410-410:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winFix inconsistent configuration namespace in global settings.
The global settings panel still reads from and writes to the old
clionCMakeFormatterconfiguration namespace instead of the newccFormat.cmakenamespace.🔧 Proposed fix
- const config = vscode.workspace.getConfiguration('clionCMakeFormatter'); + const config = vscode.workspace.getConfiguration('ccFormat.cmake');Apply the same fix at lines 521 and 529:
- const config = vscode.workspace.getConfiguration('clionCMakeFormatter'); + const config = vscode.workspace.getConfiguration('ccFormat.cmake');Also applies to: 521-521, 529-529
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/vscode/src/configEditorProvider.ts` at line 410, The global settings are still using the old configuration namespace 'clionCMakeFormatter'; update the calls to vscode.workspace.getConfiguration and any get/set usages that reference 'clionCMakeFormatter' to use the new namespace 'ccFormat.cmake' instead (for example replace the declaration const config = vscode.workspace.getConfiguration('clionCMakeFormatter') and the similar occurrences referenced around the identifiers at the locations associated with lines 521 and 529), ensuring all reads and writes target 'ccFormat.cmake' consistently.
363-363:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winFix inconsistent command ID.
The command ID still uses the old
clion-cmake-format.*namespace instead of the newcc-format.*namespace.🐛 Proposed fix
- await vscode.commands.executeCommand('clion-cmake-format.createConfig'); + await vscode.commands.executeCommand('cc-format.createConfig');🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/vscode/src/configEditorProvider.ts` at line 363, Update the inconsistent command ID used in the call to vscode.commands.executeCommand: locate the invocation that currently calls 'clion-cmake-format.createConfig' (in configEditorProvider.ts where vscode.commands.executeCommand is invoked) and change the command string to the new namespace 'cc-format.createConfig' so the command matches the renamed extension commands.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/package.json`:
- Line 4: Update the "description" field in package.json to remove the phrase
"zero-dependency" and reflect that the CLI has runtime dependencies (e.g.,
`@cc-format/core`, `@cc-format/shell`, commander); edit the description string in
packages/cli's package.json (the "description" field) to a concise accurate
message such as mentioning it is a "fast, zero-configuration" or "lightweight"
CLI instead of "zero-dependency" so npm metadata is not misleading.
- Line 2: The package.json for the scoped package "@cc-format/cli" lacks an
explicit publishConfig, so npm will default to restricted access; add a
publishConfig object with access set to "public" (i.e., add the "publishConfig"
key at the top-level of package.json for "@cc-format/cli" and set
publishConfig.access to "public") to ensure the package is published with public
visibility.
In `@packages/shell/package.json`:
- Line 2: Add an explicit publishConfig to the package.json for the scoped
package "@cc-format/shell" so it will publish as public; specifically, update
the package.json (where "name": "@cc-format/shell" appears) to include
"publishConfig": { "access": "public" } and apply the same change to the other
scoped package manifests referenced in the diff (the blocks around lines 38-48)
to prevent accidental private publishing in CI/release workflows.
In `@test/shell.test.ts`:
- Around line 70-75: The tests for formatShell currently only check presence of
'esac' and not that options change formatting; update the 'should indent case
bodies when caseIndent=true' test (and the related binaryNextLine test) to
assert the actual formatting changes by calling formatShell(input, { caseIndent:
true }) and asserting the case body line is indented (e.g., output contains a
newline + two or more spaces or a tab before echo "a"), and for binaryNextLine
call formatShell with { binaryNextLine: true } and assert the operator and its
right-hand operand are split onto different lines; locate and update the tests
referencing formatShell, caseIndent, and binaryNextLine to include these
stronger assertions.
---
Outside diff comments:
In `@packages/vscode/src/configEditorProvider.ts`:
- Line 410: The global settings are still using the old configuration namespace
'clionCMakeFormatter'; update the calls to vscode.workspace.getConfiguration and
any get/set usages that reference 'clionCMakeFormatter' to use the new namespace
'ccFormat.cmake' instead (for example replace the declaration const config =
vscode.workspace.getConfiguration('clionCMakeFormatter') and the similar
occurrences referenced around the identifiers at the locations associated with
lines 521 and 529), ensuring all reads and writes target 'ccFormat.cmake'
consistently.
- Line 363: Update the inconsistent command ID used in the call to
vscode.commands.executeCommand: locate the invocation that currently calls
'clion-cmake-format.createConfig' (in configEditorProvider.ts where
vscode.commands.executeCommand is invoked) and change the command string to the
new namespace 'cc-format.createConfig' so the command matches the renamed
extension commands.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0bada28f-a233-40ef-9bd1-5432d2a77590
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (25)
package.jsonpackages/cli/package.jsonpackages/cli/src/cli.tspackages/core/package.jsonpackages/shell/CHANGELOG.mdpackages/shell/LICENSEpackages/shell/README.mdpackages/shell/package.jsonpackages/shell/src/config.tspackages/shell/src/formatter.tspackages/shell/src/index.tspackages/shell/src/shfmt.tspackages/shell/src/wasm.tspackages/shell/tsconfig.jsonpackages/vscode/package.jsonpackages/vscode/package.nls.jsonpackages/vscode/package.nls.zh-cn.jsonpackages/vscode/resources/cc-format.schema.jsonpackages/vscode/resources/sample.cc-format.jsoncpackages/vscode/src/configEditorProvider.tspackages/vscode/src/extension.tspackages/vscode/webpack.config.jstest/cli.test.tstest/shell.test.tstsconfig.json
| @@ -1,7 +1,7 @@ | |||
| { | |||
| "name": "cc-format", | |||
| "name": "@cc-format/cli", | |||
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
For npm scoped packages, what is the default publish access, and when should package.json include "publishConfig": { "access": "public" }?
💡 Result:
For npm scoped packages, the default publish access is restricted [1][2][3]. This means that by default, scoped packages are not publicly viewable or installable by the general public [2][4]. You should include "publishConfig": { "access": "public" } in your package.json when you intend for your scoped package to be publicly accessible on the npm registry [5][2][6]. Including this configuration ensures that the package is published with public visibility during the initial publish, eliminating the need to manually pass the --access public flag via the command line [2][6]. Key points to remember: - The --access flag (or the publishConfig equivalent) only applies to the initial publish of a package [2][3]. - To change the access level of a package after it has already been published, you must use the npm access command (e.g., npm access public ) [1][2][3]. - If you are using a free npm account, you must explicitly set the access to public when publishing scoped packages, as restricted access is typically a feature associated with paid organization plans [1][3].
Citations:
- 1: https://docs.npmjs.com/cli/v8/commands/npm-access/
- 2: https://docs.npmjs.com/cli/v11/using-npm/scope/
- 3: https://docs.npmjs.com/cli/v7/commands/npm-publish
- 4: https://vgpena.github.io/private-vs-restricted-node-packages-what-s-the-diff/
- 5: https://docs.npmjs.com/creating-and-publishing-scoped-public-packages/
- 6: How to run [ npm publish --acess public] in the new version semantic-release/semantic-release#510
🏁 Script executed:
cat packages/cli/package.jsonRepository: wysaid/clion-cmake-format
Length of output: 1517
🏁 Script executed:
fd package.json packages/ | head -10 | xargs -I {} sh -c 'echo "=== {} ===" && grep -A 2 "\"name\":" {}'Repository: wysaid/clion-cmake-format
Length of output: 764
🏁 Script executed:
cat packages/core/package.json | grep -A 5 '"publishConfig"'
cat packages/shell/package.json | grep -A 5 '"publishConfig"'Repository: wysaid/clion-cmake-format
Length of output: 51
🏁 Script executed:
cat packages/core/package.jsonRepository: wysaid/clion-cmake-format
Length of output: 989
🏁 Script executed:
cat packages/shell/package.jsonRepository: wysaid/clion-cmake-format
Length of output: 1235
Add explicit public publish config for scoped package.
Scoped packages default to restricted access on npm. Without publishConfig.access: "public" in package.json, this package will publish as private/restricted instead of public. Add this configuration to ensure the package is published with public visibility:
"publishConfig": {
"access": "public"
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/package.json` at line 2, The package.json for the scoped package
"@cc-format/cli" lacks an explicit publishConfig, so npm will default to
restricted access; add a publishConfig object with access set to "public" (i.e.,
add the "publishConfig" key at the top-level of package.json for
"@cc-format/cli" and set publishConfig.access to "public") to ensure the package
is published with public visibility.
| "name": "@cc-format/cli", | ||
| "version": "1.5.0", | ||
| "description": "Professional CMake formatter with CLion-compatible style - Fast, zero-dependency command line tool for CMakeLists.txt formatting", | ||
| "description": "Professional code formatter for CMake and Shell scripts — Fast, zero-dependency command line tool", |
There was a problem hiding this comment.
Description is inaccurate about dependency model.
Line 4 says “zero-dependency”, but this package has runtime dependencies (@cc-format/core, @cc-format/shell, commander). Please update the description to avoid misleading npm metadata.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/package.json` at line 4, Update the "description" field in
package.json to remove the phrase "zero-dependency" and reflect that the CLI has
runtime dependencies (e.g., `@cc-format/core`, `@cc-format/shell`, commander); edit
the description string in packages/cli's package.json (the "description" field)
to a concise accurate message such as mentioning it is a "fast,
zero-configuration" or "lightweight" CLI instead of "zero-dependency" so npm
metadata is not misleading.
| @@ -0,0 +1,49 @@ | |||
| { | |||
| "name": "@cc-format/shell", | |||
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Does npm publish default scoped packages to restricted access, and is "publishConfig.access": "public" the recommended setting for open-source scoped packages?
💡 Result:
Yes, npm scoped packages are restricted by default [1][2][3]. When you publish a scoped package for the first time, it is private and not publicly viewable unless you explicitly configure it otherwise [4][1][5]. For open-source scoped packages, setting "publishConfig": { "access": "public" } in your package.json is the standard and recommended approach [6]. This configuration ensures that every time you publish, the package is correctly set to public, preventing it from defaulting to restricted access or reverting to private if you have previously modified its visibility [7]. Key points regarding scoped package access: - Default Behavior: Scoped packages are private by default to prevent accidental exposure of internal or proprietary code [1][8][5]. - Explicit Configuration: To make a scoped package public, you must use the --access public flag during the initial publish command [4][3] or include the "publishConfig": { "access": "public" } setting in your package.json [6]. - Persistence: Once a package is published as public, subsequent updates generally maintain that visibility [3], but including the configuration in package.json is considered best practice to ensure consistent behavior across different environments and automated release workflows [6][7].
Citations:
- 1: https://docs.npmjs.org/about-scopes
- 2: https://docs.npmjs.com/cli/v8/commands/npm-access/
- 3: https://docs.npmjs.com/cli/v8/using-npm/scope/
- 4: http://docs.npmjs.com/creating-and-publishing-scoped-public-packages
- 5: https://docs.npmjs.com/about-scopes/
- 6: How to run [ npm publish --acess public] in the new version semantic-release/semantic-release#510
- 7: https://stackoverflow.com/questions/78085574/npm-package-becomes-private-every-time-i-publish
- 8: publishConfig.access is, by default, set to public when running lerna create! lerna/lerna#2144
Add explicit public publish access for @cc-format/shell.
Scoped packages default to private on npm. Add "publishConfig": { "access": "public" } to ensure this package publishes as public and prevent accidental restriction in automated release workflows.
Proposed patch
{
"name": "@cc-format/shell",
@@
"scripts": {
"build": "tsc",
"clean": "rm -rf dist",
"prepublishOnly": "pnpm run build"
},
+ "publishConfig": {
+ "access": "public"
+ },
"dependencies": {
"sh-syntax": "^0.5.8"
},Also applies to: 38-48
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/shell/package.json` at line 2, Add an explicit publishConfig to the
package.json for the scoped package "@cc-format/shell" so it will publish as
public; specifically, update the package.json (where "name": "@cc-format/shell"
appears) to include "publishConfig": { "access": "public" } and apply the same
change to the other scoped package manifests referenced in the diff (the blocks
around lines 38-48) to prevent accidental private publishing in CI/release
workflows.
| it('should indent case bodies when caseIndent=true', async () => { | ||
| const input = 'case $x in\na)\necho "a"\n;;\nesac'; | ||
| const output = await formatShell(input, { caseIndent: true }); | ||
| // With caseIndent, the body inside case patterns is indented | ||
| assert.ok(output.includes('esac')); | ||
| }); |
There was a problem hiding this comment.
Strengthen option-behavior assertions for caseIndent and binaryNextLine.
Line 74 and Line 82 currently don’t verify that these options actually change formatting, so regressions could slip through.
Proposed test-strengthening diff
describe('caseIndent option', () => {
it('should indent case bodies when caseIndent=true', async () => {
const input = 'case $x in\na)\necho "a"\n;;\nesac';
const output = await formatShell(input, { caseIndent: true });
- // With caseIndent, the body inside case patterns is indented
- assert.ok(output.includes('esac'));
+ assert.match(output, /a\)\n[ \t]+echo "a"\n[ \t]*;;/);
});
});
describe('binaryNextLine option', () => {
it('should move binary operators to next line when binaryNextLine=true', async () => {
- const input = 'echo a && echo b';
- const output = await formatShell(input, { binaryNextLine: true });
- assert.ok(typeof output === 'string');
+ const input = 'if true &&\nfalse; then\necho ok\nfi';
+ const withOption = await formatShell(input, { binaryNextLine: true });
+ const withoutOption = await formatShell(input, { binaryNextLine: false });
+ assert.notStrictEqual(withOption, withoutOption, 'binaryNextLine should affect output');
});
});As per coding guidelines, test/**: "Add or adjust test cases when fixing bugs or adding features".
Also applies to: 79-83
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/shell.test.ts` around lines 70 - 75, The tests for formatShell currently
only check presence of 'esac' and not that options change formatting; update the
'should indent case bodies when caseIndent=true' test (and the related
binaryNextLine test) to assert the actual formatting changes by calling
formatShell(input, { caseIndent: true }) and asserting the case body line is
indented (e.g., output contains a newline + two or more spaces or a tab before
echo "a"), and for binaryNextLine call formatShell with { binaryNextLine: true }
and assert the operator and its right-hand operand are split onto different
lines; locate and update the tests referencing formatShell, caseIndent, and
binaryNextLine to include these stronger assertions.
Summary
This PR expands the project from a CMake-only formatter to a multi-language code formatter (
cc-format), adding shell script formatting support.Inspired by the abandoned vs-shell-format extension.
Changes
New Package:
@cc-format/shellA new shell formatting engine using a hybrid strategy:
shfmtbinary when configured and available (faster, native)Supports: POSIX shell, Bash, Zsh (mksh), Bats
Bug fixes in WASM integration:
LangAuto(value 4) causes a runtime panic in the sh-syntax WASM parser — skip passingvariantwhen set toautoexport typefor TypeScript-only types (ShellFormatOptions,ShellVariant) to avoid webpack warningsRebranding:
clion-cmake-format→cc-formatclion-cmake-formatcc-formatcc-format(unchanged)cc-formatclionCMakeFormatter.*ccFormat.cmake.*ccFormat.shell.*clion-cmake-format.*cc-format.*CLI (
@cc-format/cli) Extensions.sh,.bash,.zsh,.bats→ shell)--language,--shfmt-path,--shell-indent,--shell-variant,--shell-bn/ci/sr/kp/fnVS Code Extension
shellscriptdocument formatting providerccFormat.shell.indent,ccFormat.shell.variant,ccFormat.shell.shfmtPath, etc.activationEventsupdated foronLanguage:shellscriptSchema & Config
cc-format.schema.json: addedshellobject with all shfmt optionssample.cc-format.jsonc: added Shell Formatting Options sectionTests
test/shell.test.tswith 17 test cases covering:DEFAULT_SHELL_OPTIONSvalues,isShellFile()detectionTest Results
Summary by CodeRabbit
Release Notes
New Features
--languageoptionUpdates