Contribute to jqnpm
February 24, 2021 ยท View on GitHub
This is experimental software, so feedback is most appreciated!
- You can open an issue for your problem or suggestion.
- Learn how to create your own package.
- Learn how to contribute code to
jqnpm.
Known issues
- The package names are currently duplicated between
./jq.jsonand./jq/main.jq. This is due to two things:jqis unaware of each dependency's subdirectory.jqnpmuses only./jq/main.jqat the moment. Themainresponsibility might end up injqinstead.
- Packages are not recursively resolved during execution. This is due to relative module paths starting with
./only being resolved against the initialjq/main.jq, not subsequently called dependencies.
Additional features
- Dependencies are stored in
./.jq/packages/per package. - A local cache in
~/.jq/stores remote repositories. - No centrally managed server side package repository is needed to publish your packages -- just create a repository on github!
- As packages are stored on github.com (by default), an account there is required for
jqnpm. Because github allows private repositories, you can usejqnpmfor private packages; this has not been tested yet. - Can also use bitbucket and other online services, where usernames or organization names act as namespaces.
TODO
Patches/pull requests welcome!
- Write additional tests, and add relevant asserts to current tests.
- Split up files into smaller parts.
Ideas
- Implement user-global storage of executable jq scripts in
~/.jq/bin/, which can be added to$PATH. - Enforce
jq.json'sengineproperty version range forjqandjqnpm.
Background
In order to understand the direction of the development, you could spend an hour or two reading all of this. If you are already familiar with npm, you might actually be able to skip all of the reading.
jq's modules
jq is a lightweight and flexible command-line JSON processor.
- Built to satisfy the need for a package manager to handle jq's (future, v1.4+) module system.
- stedolan/jq#491 Enhancement request: integrated package manager
- stedolan/jq#566 Semantic version utility
- stedolan/jq#535 List of publicly released modules?
Style
- Based on Node Package Manager's style.
- All package versions follow the Semantic Versioning scheme strictly.
- Version parsing and matching aims to follow node-semver.
- Written in bash shell scripts, but it might not be the optimal choice in the long run.
Requirements for the jq binary
- Implement a simple package directory finding logic in
jq, like how modules installed bynpmare resolved bynode. - No
modulestatement is necessary. It only clutters jq script files, as metadata is best kept in./jq.jsonper package. - A simple
importstatement accepting a string and an alias:import "<package>" as <alias>;.- No other configuration, such as versions, goes in the
importstatement. - The
<package>is defined as (or at least parsed as) a string.
- No other configuration, such as versions, goes in the
- The package root is defined as the current/first parent directory with a
.jq/subdirectory. Only one is allowed per package. - Implement a simple per-package
./jq.jsonlookup for the"main": "./some-path/completely-separate-from-module-name.jq"property, or fall back to./jq/main.jq.
Example import resolving algorithm
- Here
Pmeans the package root: the first of the current or any parent directory which contains a directory.jq/. - Here
Dmeans a directory referenced during the lookups. - Here
Fmeans the file used byjqfor further parsing of the contents.
For import "<package>" as <alias>; follow these steps to find D:
<package>strings exactly matching packages/modules internal to the currentjqbuild are loaded with priority.<package>strings starting with./,../or/are treated as paths.- Absolute paths starting with
/:- Start in the (file) system root
/on non-Windows systems. - Are used as
file://paths on Windows systems:file://+/c:/dev/directory/->file:///c:/dev/directory/.
- Start in the (file) system root
- Relative paths starting with
./or../are relative to:- The directory containging the jq script file which used the
importstatement. - The current directory
$PWDif the script is given on the command line:jq 'import ...'.
- The directory containging the jq script file which used the
<package>strings which are paths can point to:- A file path which becomes
F. - A directory path which becomes
Dand used the directory lookup steps below.
- A file path which becomes
- Absolute paths starting with
- Other strings are treated as package names:
- Package names can use
/as directory delimiters. - Package names are relative to
P/.jq/packages/. - Let
DbeP/.jq/packages/<package>/and used the directory lookup steps.
- Package names can use
- If
Dis set, follow these directory lookup steps:- A path
D/jq/main.jq, which if it exists becomesF. - A path
D/data/main.json, which if it exists becomesF. - If
D/jq.jsonis a file which exists:
- Use the
mainproperty pathcat D/jq.json | jq '.main'asF.
- A path
- Treating
F:- If the file
Fisnullor doesn't exist, throw an error. - If the file extensions is
.jq, it's a jq script:./more/code-goes-here.jq(for example). - If the file extension is
.json, it's data:../data/data-goes-here.json(for example). - If the file extensions is anything else, throw an error.
- If the file
- If nothing could be resolved, throw an error.
The resulting file F should now have been resolved, and the import ... statement can continue with file parsing.
Alternative solutions
- Store all packages user-globally in
~/.jq/packages/with~/.jq/packages/<package>/<semantic version>/subdirectories.- Positive:
- Makes it easier to re-use packages across projects.
- Globally installed packages are less different from locally/per-project dependencies.
- Negative:
- Dependencies would no longer be fully private to each package in a private
./jq/packagesdirectory. - Harder to export a fully functioning jq-dependent project as-is to another machine without accessing/affecting user-global directories.
- Requires version names in the directory structure, which would require changes to the jq core.
- Requires the
jqbinary to look up version numbers to match between./jq.jsondependency ranges and~/.jq/packages/<package>/<semantic version>/lists.- Can be solved with symbolic links from a local
./.jq/packages/<package>/to a user-global~/.jq/packages/<package>/<semantic version>/. - Symbolic links may be too error-prone for cross-platform code.
- Can be solved with symbolic links from a local
- Dependencies would no longer be fully private to each package in a private
- Positive:
- Store all packages in a flat hierarchy per project, in
./.jq/packages/with./.jq/packages/<package>/<semantic version>/subdirectories.- Positive:
- Would still allow easy export of the project directory as-is to another machine.
- Negative:
- Dependencies would no longer be fully private to each package in a private
./jq/packagesdirectory. - Requires version names in the directory structure, which would require changes to the jq core.
- Dependencies would no longer be fully private to each package in a private
- Positive:
- Using a subdirectory for the main jq file,
./jq/main.jq, can be discussed. At least it separates code files from the ordinary readme/license/metadata file clutter.
Original purpose
The library was built awaiting and expecting a complete jq package system, and to show how I expect the import statement to be used.