This repository was archived by the owner on Apr 26, 2021. It is now read-only.
v1.0.0
🎉 The first major release of neodoc.
Where the project is at
As a run up to v1, I decided to spend a lot of my time refactoring the code-base
for various reasons. Primarily the core data structures that were employed prior
to the refactor were insufficiently flexible and, looking back, clearly the
wrong choice. The new core data structure, which resembles a tree, is by far
more elegant and flexible, allows transformations and traversals and is more
obviously "correct". Secondly, I acknowledged that the code was hard to follow
and hindered adoption / contributors from getting into the code base. The most
important pieces of the codebase are now documented and hopefully approachable
enough.
New features
- Neodoc now sports a couple of hooks that allow devs to hook into the
transformation of the spec. Seeopts.transformsin the README for more
information. --versionwill now simply return the version as a string ifopts.dontExit
is true.--helpwill now simply return the help as a string ifopts.dontExitis
true.- A new option
options.repeatableOptionsis introduced that allows consuming
excess options. Many command line utilities do not care about excess options,
so now neodoc can be told to not care either. This means that after
successfully parsing a bunch of options, any option may-reoccur again. - Better error reporting. The parser now tracks the deepest error across all
branches, making for more intuitive error messages. - The spec is now being canonicalised internally which helps create (a) better
error messages and (b) to speed up the parser. - considerably better performance under difficult configurations and edge
cases, i.e. when combiningopts.laxPlacementwithopts.requiredFlagsand
so on.
Changes
- The "specification" format has changed drastically. If you've been using
neodoc.parse, it's output is now entirely different and likewise the input
to run expects the newneodoc.parseoutput. If you used this method to
change the spec on-the-fly, you should have a look at the new
opts.transformsoption which allows you to easily hook into the
transformation of the neodoc spec.
Internals
- Major overhaul of the internals. The core data structures have changed and
are now more composable.- The arg parser has been rewritten from the ground up, with next to none code
sharing. The goal was a more efficient, simpler and better documented
solution that is easier to reason about and debug. - Instead of representing a group as an argument, we now have a
Layoutdata
type which looks more like a classical tree:
haskell data Layout a = Group IsOptional IsRepeatable Branches | Elem a
It turns out that this structure holds true throught all the various stages
of transformation. - There's finally a
Specdatatype that formalises what a specification is:
haskell type Branch a = NonEmpty List a type Toplevel a = List (Branch a) newtype Spec a = Spec { program :: String , layouts :: NonEmpty List (Toplevel a) , descriptions :: List Description , helpText :: String , shortHelp :: String } - A custom parser monad for arg-parsing that does not use monad
transformers. It enables neodoc to better handle errors and should generally
run faster. It allows the parser to keep read-only state, state that
isolated in alternatives and when backtracking, as well as state that is
"mutable", i.e. state that survives failures. In terms of running faster,
the worst case that previously required adding in a cache now runs fine and
the cache was removed. - Branches in groupings as well as top-levels are now encoded at the type
level asNonEmpty - Move away from records to ADTs for speed and ease of use in many scenarios
- Use
AsForeignandIsForeignfor FFI needs - Improve test bed readability all over, make it more easy to add tests
- Overall add more comments and document entire modules in an effort to make
the code "contributable"
- The arg parser has been rewritten from the ground up, with next to none code