Skip to content

Commit

Permalink
Merge pull request #360 from replit/bm/format-using-unified-interface
Browse files Browse the repository at this point in the history
Introduce unified formatter interface; Use for `gofmt` and `prettier`
  • Loading branch information
bradymadden97 committed Jun 25, 2024
2 parents 2d491ec + 898d10a commit 1835908
Show file tree
Hide file tree
Showing 3 changed files with 280 additions and 5 deletions.
165 changes: 165 additions & 0 deletions pkgs/formatter/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
{ pkgs }:

pkgs.writeShellApplication {
name = "parse-formatter-options";
runtimeInputs = [ pkgs.bash ];
text = ''
#!/bin/bash
# Initialize variables
apply="false"
file=""
insertFinalNewline="false"
insertSpaces="false"
rangeStart=""
rangeEnd=""
stdinMode="false"
tabSize=""
trimFinalNewlines="false"
trimTrailingWhitespace="false"
# Function to print usage
print_usage() {
echo "Usage: $0 [-a|--apply] -f|--file <filename> [--stdin] [--range-start <offset>] [--range-end <offset>] [--tab-size <number>] [--insert-spaces] [--trim-trailing-whitespace] [--insert-final-newline] [--trim-final-newlines]"
echo
echo "Options:"
echo " -h, --help Show this help message and exit"
echo " -a, --apply Apply edits directly to the file (optional)"
echo " -f, --file <filename> Specify the file to be formatted (required)"
echo " --stdin Read file input from stdin (optional)"
echo " --insert-final-newline Insert a newline at the end of the file if one does not exist (optional)"
echo " --insert-spaces Prefer spaces over tabs (optional)"
echo " --range-start <offset> Specify the character offset for formatting (optional, requires --range-end)"
echo " --range-end <offset> Specify the character offset for formatting (optional, requires --range-start)"
echo " --tab-size <number> Size of a tab in spaces (optional)"
echo " --trim-final-newlines Trim all newlines after the final newline at the end of the file (optional)"
echo " --trim-trailing-whitespace Trim trailing whitespace on a line (optional)"
}
# Function to check if a value is a number
is_number() {
[[ "$1" =~ ^[0-9]+$ ]]
}
# Parse command-line arguments
while [[ "$#" -gt 0 ]]; do
case $1 in
-a|--apply)
apply="true"
shift
;;
-f|--file)
file="$2"
shift 2
;;
-h|--help)
print_usage
exit 0
;;
--stdin)
stdinMode="true"
shift
;;
--range-start)
if is_number "$2"; then
rangeStart="$2"
else
echo "Error: --range-start must be a number."
print_usage
exit 1
fi
shift 2
;;
--range-end)
if is_number "$2"; then
rangeEnd="$2"
else
echo "Error: --range-end must be a number."
print_usage
exit 1
fi
shift 2
;;
--tab-size)
if is_number "$2"; then
tabSize="$2"
else
echo "Error: --tab-size must be a number."
print_usage
exit 1
fi
shift 2
;;
--insert-spaces)
insertSpaces="true"
shift
;;
--trim-trailing-whitespace)
trimTrailingWhitespace="true"
shift
;;
--insert-final-newline)
insertFinalNewline="true"
shift
;;
--trim-final-newlines)
trimFinalNewlines="true"
shift
;;
# TODO: Legacy from frontend, clean up
--tab-width)
if is_number "$2"; then
tabSize="$2"
fi
shift 2
;;
--use-tabs)
if "$2"; then
insertSpaces="false"
else
insertSpaces="true"
fi
shift 2
;;
--stdin-filepath)
stdinMode="true"
shift
;;
# Ignore all other arguments
*)
shift
;;
esac
done
# Validate required arguments
if [[ -z "$file" ]]; then
echo "Error: File argument is required."
print_usage
exit 1
fi
# Further validate that both rangeStart and rangeEnd are provided together, if at all
if [[ -n "$rangeStart" && -z "$rangeEnd" ]] || [[ -z "$rangeStart" && -n "$rangeEnd" ]]; then
echo "Error: Both --range-start and --range-end must be provided together."
print_usage
exit 1
fi
# Export for use in sub-scripts
export apply
export file
export insertFinalNewline
export insertSpaces
export rangeStart
export rangeEnd
export stdinMode
export tabSize
export trimFinalNewlines
export trimTrailingWhitespace
'';
}
52 changes: 49 additions & 3 deletions pkgs/modules/go/default.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,52 @@
{ go, gopls }:
{ lib, ... }:
{ pkgs, lib, ... }:
let
goversion = lib.versions.majorMinor go.version;

formatter = import ../../formatter {
inherit pkgs;
};
run-gofmt = pkgs.writeShellApplication {
name = "run-gofmt";
runtimeInputs = [ pkgs.bash go ];
extraShellCheckFlags = [ "-x" ];
text = ''
#!/bin/bash
# Source the shared options parsing script
source ${formatter}/bin/parse-formatter-options "$@"
# Translate parsed arguments into gofmt options
gofmt_args=()
# Apply edit flag
if [[ "$apply" == "true" ]]; then
gofmt_args+=("-w")
fi
# Append the file path
gofmt_args+=("$file")
# Execute the command
gofmt "''${gofmt_args[@]}"
'';
checkPhase = ''
cat > main.go << EOF
package main
func main ( ){
fmt.Println( "hello world" )
}
EOF
$out/bin/run-gofmt -f main.go > output.go
printf 'package main\n\nfunc main() {\n\tfmt.Println("hello world")\n}\n'> expected.go
if ! diff expected.go output.go; then
echo "format output doesn't match expectation"
exit 1
fi
'';
};

in
{
id = "go-${goversion}";
Expand Down Expand Up @@ -30,8 +75,9 @@ in
replit.dev.formatters.go-fmt = {
name = "go fmt";
language = "go";

start = "${go}/bin/go fmt";
start = {
args = [ "${run-gofmt}/bin/run-gofmt" "-f" "$file" ];
};
stdin = false;
};

Expand Down
68 changes: 66 additions & 2 deletions pkgs/modules/nodejs/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,71 @@ let
${nodejs-wrapped}/bin/npx "$@"
'';
};

formatter = import ../../formatter {
inherit pkgs;
};
run-prettier = pkgs.writeShellApplication {
name = "run-prettier";
runtimeInputs = [ pkgs.bash nodepkgs.prettier ];
extraShellCheckFlags = [ "-x" ];
text = ''
#!/bin/bash
# Source the shared options parsing script
source ${formatter}/bin/parse-formatter-options "$@"
# Translate parsed arguments into prettier options
prettier_args=()
# Apply edit flag
if [[ "''${apply:=false}" == "true" ]]; then
prettier_args+=("--write")
fi
# Range options
if [[ -n "$rangeStart" && -n "$rangeEnd" ]]; then
prettier_args+=("--range-start" "$rangeStart" "--range-end" "$rangeEnd")
fi
# Tab size
if [[ -n "$tabSize" ]]; then
prettier_args+=("--tab-width" "$tabSize")
fi
# Insert spaces over tabs
if [[ "''${insertSpaces:=false}" == "true" ]]; then
prettier_args+=("--use-tabs" "false")
else
prettier_args+=("--use-tabs" "true")
fi
# Read file content from stdin if stdinMode is enabled
if [[ "''${stdinMode:=false}" == "true" ]]; then
prettier_args+=("--stdin-filepath")
fi
# Append the file path
prettier_args+=("$file")
# Execute the command
# Resolve to first prettier in path
prettier "''${prettier_args[@]}"
'';
checkPhase = ''
cat > index.ts << EOF
function foo() { return 10}
EOF
$out/bin/run-prettier -f index.ts > output.ts
printf 'function foo() {\n\treturn 10;\n}\n'> expected.ts
if ! diff expected.ts output.ts; then
echo "format output doesn't match expectation"
exit 1
fi
'';
};


in

{
Expand Down Expand Up @@ -105,8 +170,7 @@ in
language = "javascript";
extensions = [ ".js" ".jsx" ".ts" ".tsx" ".json" ".html" ];
start = {
# Resolve to first prettier in path
args = [ "prettier" "--stdin-filepath" "$file" ];
args = [ "${run-prettier}/bin/run-prettier" "--stdin-filepath" "-f" "$file" ];
};
stdin = true;
};
Expand Down

0 comments on commit 1835908

Please sign in to comment.