From 84787b6b7b60da36ed9d23808d45f6bda19b8b1c Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Fri, 6 Sep 2024 00:55:14 -0700 Subject: [PATCH] feat: support glob paths + support positional file arguments in CLI --- Readme.md | 30 ++++++++++++------ dub.sdl | 7 +++-- dub.selections.json | 3 ++ src/native/cli.d | 77 +++++++++++++++++++++++++++------------------ src/native/lib.d | 55 ++++++++++++++++++++++++++++++-- src/node/lib.ts | 2 +- 6 files changed, 129 insertions(+), 45 deletions(-) diff --git a/Readme.md b/Readme.md index cf8c359..3135d85 100644 --- a/Readme.md +++ b/Readme.md @@ -32,21 +32,33 @@ dub build --config=executable --build=release-nobounds --compiler=ldc2 ### CLI Usage ```shell -❯ minijson --help +> minijson --help + +Usage: minijson [--files FILES ...] [--comment] [--str STR ...] [--file FILE ...] [-h] minijson: minify json files with support for comments - minijson --file file1.json --file file2.json - minijson --file file1_with_comment.json --file file2_with_comment.json --comment - minijson --string '{"some_json": "string_here"}' - minijson --string '{"some_json": "string_here"} //comment' --comment + # Minify the specified files + minijson ./dist/**/*.json ./build/a.json + + # Minify the specified files (supports comments) + minijson --comment file1_with_comment.json file2_with_comment.json + + # Minify the specified json string + minijson --str '{"some_json": "string_here"}' + + # Minify the specified json string (supports comments) + minijson --comment --str '{"some_json": "string_here"} //comment' More information at https://github.com/aminya/minijson - --file an array of files to minify - --string a json string to minify - --comment a flag to support comments in json --h --help This help information. + +Optional arguments: + --files FILES ... + --comment + --str STR ... + --file FILE ... + -h, --help Show this help message and exit ``` ### Node API diff --git a/dub.sdl b/dub.sdl index bdbb23f..2552b9a 100644 --- a/dub.sdl +++ b/dub.sdl @@ -10,8 +10,11 @@ sourcePaths "./src/native" importPaths "./src/native" dependency "automem" version="0.6.7" -preGenerateCommands "git submodule update --init" # despacer download dependency "despacer" path="despacer" +dependency "d-glob" version="~>0.4.0" +dependency "argparse" version="~>1.3.0" + +preGenerateCommands "git submodule update --init" # despacer download configuration "executable" { targetType "executable" @@ -32,7 +35,7 @@ configuration "benchmark" { # -------- Build Options and configurations -------- -dflags "-vgc" +// dflags "-vgc" buildType "release-nobounds" { buildOptions "releaseMode" "optimize" "inline" "noBoundsCheck" diff --git a/dub.selections.json b/dub.selections.json index f9bacd1..8396bed 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -1,7 +1,10 @@ { "fileVersion": 1, "versions": { + "argparse": "1.3.0", "automem": "0.6.7", + "bdd": "1.3.0", + "d-glob": "0.4.0", "despacer": {"path":"despacer/"}, "test_allocator": "0.3.4", "unit-threaded": "2.2.0" diff --git a/src/native/cli.d b/src/native/cli.d index 296acd4..3bd0d17 100644 --- a/src/native/cli.d +++ b/src/native/cli.d @@ -1,48 +1,65 @@ module minijson.cli; -import minijson.lib : minifyFiles, minifyString; +import minijson.lib : minifyFiles, minifyStrings; +import argparse; -import std.getopt : getopt, defaultGetoptPrinter, GetoptResult; +@(Command("minijson") + .Description(`minijson: minify json files with support for comments -/** Print help */ -void printHelp(GetoptResult optResult) @trusted -{ - return defaultGetoptPrinter(`minijson: minify json files with support for comments - minijson --file file1.json --file file2.json - minijson --file file1_with_comment.json --file file2_with_comment.json --comment + # Minify the specified files + minijson ./dist/**/*.json ./build/a.json + + # Minify the specified files (supports comments) + minijson --comment file1_with_comment.json file2_with_comment.json + + # Minify the specified json string + minijson --str '{"some_json": "string_here"}' - minijson --string '{"some_json": "string_here"}' - minijson --string '{"some_json": "string_here"} //comment' --comment + # Minify the specified json string (supports comments) + minijson --comment --str '{"some_json": "string_here"} //comment' More information at https://github.com/aminya/minijson - `, optResult.options); + `) +) +struct Options +{ + @TrailingArguments string[] files; + bool comment = false; + string[] str; + // (Deprecated) A list of files to minify (for backwards compatiblitity with getopt) + string[] file; } -void main(string[] args) @trusted +int actualMain(Options opts) @trusted { - string[] files; - string jsonString; - bool hasComment = false; + try + { + // minify the given files + if (opts.files.length > 0 || opts.file.length > 0) + { + const auto files = opts.files ~ opts.file; + minifyFiles(files, opts.comment); + } - auto optResult = getopt(args, "file", "an array of files to minify", &files, "string", - "a json string to minify", &jsonString, "comment", "a flag to support comments in json", &hasComment); + // minify the given string and print to stdout + if (opts.str) + { + import std.algorithm : each; + import std.stdio : writeln; - if (optResult.helpWanted || (!files && !jsonString)) - { - return printHelp(optResult); - } + minifyStrings(opts.str, opts.comment).each!writeln; - // minify the given files - if (files) - { - minifyFiles(files, hasComment); + } } - - // minify the given string and print to stdout - if (jsonString) + catch (Exception e) { - import std : write; + import std.stdio : stderr; - write(minifyString(jsonString, hasComment)); + stderr.writeln("Error: ", e.msg); + return 1; } + + return 0; } + +mixin CLI!Options.main!((args) { return actualMain(args); }); diff --git a/src/native/lib.d b/src/native/lib.d index 813f1fa..906745a 100644 --- a/src/native/lib.d +++ b/src/native/lib.d @@ -162,17 +162,66 @@ private bool hasNoSpace(const ref string str) @trusted } } +/** + Minify the given JSON strings in parallel + + Params: + jsonStrings = the json strings you want to minify + hasComment = a boolean to support comments in json. Default: `false`. + + Return: + the minified json strings +*/ +string[] minifyStrings(in string[] jsonStrings, in bool hasComment = false) @trusted +{ + import std.algorithm: map; + import std.array: array; + + return jsonStrings.map!(jsonString => minifyString(jsonString, hasComment)).array(); +} + /** Minify the given files in place. It minifies the files in parallel. Params: - files = the paths to the files. + paths = the paths to the files. It could be glob patterns. hasComment = a boolean to support comments in json. Default: `false`. */ -void minifyFiles(in string[] files, in bool hasComment = false) +void minifyFiles(in string[] paths, in bool hasComment = false) @trusted { import std.parallelism : parallel; - import std.file : readText, write; + import std.algorithm; + import std.array; + import std.file : dirEntries, SpanMode, readText, write, isFile, isDir, exists; + import std.path : globMatch; + import glob : glob; + import std.stdio : writeln; + + // get the files from the given paths (resolve glob patterns) + auto files = paths + .map!((path) { + if (path.exists) + { + if (path.isFile) + { + return [path]; + } + else if (path.isDir) + { + return glob(path ~ "/**/*.json"); + } + else + { + throw new Exception("The given path is not a file or a directory: " ~ path); + } + } + else + { + return glob(path); + } + }) + .joiner() + .array(); foreach (file; files.parallel()) { diff --git a/src/node/lib.ts b/src/node/lib.ts index 41f1f89..667fc50 100644 --- a/src/node/lib.ts +++ b/src/node/lib.ts @@ -51,7 +51,7 @@ export async function minifyFiles(files: string[], hasComment = false): Promise< * @throws {Promise} The promise is rejected with the reason for failure */ export async function minifyString(jsonString: string, hasComment = false): Promise { - const args = ["--string", jsonString] + const args = ["--str", jsonString] if (hasComment) { args.push("--comment") }