Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Sign in
Toggle navigation
easy
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Container Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
200ok
easy
Commits
6cfd61ee
Commit
6cfd61ee
authored
Sep 30, 2019
by
phil
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
new bin `collect`, replaces yq, annotates events with source-path, applys frontmatter templates
parent
13f96dcd
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
124 additions
and
27 deletions
+124
-27
.gitignore
.gitignore
+2
-0
README.org
README.org
+3
-3
bin/collect
bin/collect
+18
-0
src/easy/collect.cljs
src/easy/collect.cljs
+43
-0
src/easy/common.cljs
src/easy/common.cljs
+2
-12
src/easy/templating.cljs
src/easy/templating.cljs
+2
-2
src/easy/util.cljs
src/easy/util.cljs
+54
-10
No files found.
.gitignore
View file @
6cfd61ee
/.cpcache
/node_modules
/.classpath
/.lumo_cache/
README.org
View file @
6cfd61ee
* Welcome to EASY - Evented Accounting Sourced from Yaml
** Introduction
s
** Introduction
=easy= is a command line utility which generates artifacts typically
used in accounting (but also other fields of business like invoicing)
...
...
@@ -8,7 +8,7 @@ based on events provided as [[https://yaml.org/][YAML]] files.
** Overview
In principle
easy
is used to transform the business events given in
In principle
=easy=
is used to transform the business events given in
YAML into other business artifacts like invoices (PDF documents) or
journal files for use with [[https://www.ledger-cli.org/][ledger]] (a command line utility for plain
text accounting.) Processing of events happens in 5 steps:
...
...
@@ -16,7 +16,7 @@ text accounting.) Processing of events happens in 5 steps:
1. Read input events
2. Check input events against spec
3. Augment input events
3.1. Calculate drived values
3.1. Calculate d
e
rived values
3.2. Resolve related events
4. Check augmented event against spec
5. Render event(s) through templates
...
...
bin/collect
0 → 100755
View file @
6cfd61ee
#!/bin/sh
# the classpath usually doesn't change, hence it can be cached, which
# saves quite some time, because we don't need to fire up a jvm just
# to establish a classpath
BASEDIR
=
$(
dirname
"
$0
"
)
/..
KLASSPATHFILE
=
./.classpath
if
[
!
-f
$KLASSPATHFILE
]
;
then
KLASSPATH
=
$(
cd
"
$BASEDIR
"
||
exit
1
;
clj
-Spath
)
echo
"
${
BASEDIR
}
/src:
${
KLASSPATH
}
"
>
$KLASSPATHFILE
fi
KLASSPATH
=
$(
cat
$KLASSPATHFILE
)
export
NODE_PATH
=
$BASEDIR
/node_modules
exec
$BASEDIR
/node_modules/.bin/lumo
-K
-c
"
$KLASSPATH
"
-m
easy.collect
$@
src/easy/collect.cljs
0 → 100644
View file @
6cfd61ee
(
ns
easy.collect
(
:require
[
lumo.util
:as
lumo
]
[
easy.util
:as
util
]
[
easy.log
:as
log
]
[
clojure.tools.cli
:refer
[
parse-opts
]]
[
cljs.pprint
:refer
[
pprint
]]
[
cljs.spec.alpha
:as
s
]
[
clojure.string
:refer
[
join
]]))
(
def
cli-options
[
;; ["-d" "--debug" "Debug output"]
])
(
defn-
read-and-parse
"Reads & parses YAML files (incl. applying any frontmatter event
templates & source annotation)."
[
path
]
(
->
path
util/slurp
util/parse-yaml
(
util/annotate
path
)))
(
defn-
harmonize
[
events
]
(
map
(
partial
util/harmonize-date-field
:date
)
events
))
(
defn
-main
[
&
args
]
(
let
[
cli
(
parse-opts
args
cli-options
)
path
(
or
(
->
cli
:arguments
first
)
"."
)
options
(
->
cli
:options
)]
(
->>
path
lumo/file-seq
(
filter
#
(
re-matches
#
".+\.yml$"
%
))
(
map
read-and-parse
)
(
apply
concat
)
harmonize
(
sort-by
:date
)
util/write-yaml
println
)))
src/easy/common.cljs
View file @
6cfd61ee
...
...
@@ -40,16 +40,6 @@
;; helpers
(
defn
harmonize-date-field
[
field
evt
]
(
if-let
[
date
(
field
evt
)]
(
if
(
string?
date
)
;; NOTE don't use this, this does not return an instance of Date
;; (assoc evt field (time/parse util/iso-formatter date))
(
assoc
evt
field
(
js/Date.
date
))
evt
)
evt
))
(
defn
ignore-warning?
"Checks if `evt` has `:ignore-warnings` set for `key`."
[
evt
key
]
...
...
@@ -59,9 +49,9 @@
(
defn
harmonize
[
evt
]
(
->>
evt
(
harmonize-date-field
:date
)
(
util/
harmonize-date-field
:date
)
;; TODO: remove, we don' use `:settled` anymore
(
harmonize-date-field
:settled
)))
(
util/
harmonize-date-field
:settled
)))
(
defn
validate!
...
...
src/easy/templating.cljs
View file @
6cfd61ee
...
...
@@ -16,9 +16,9 @@
;; TODO: don't read and parse the same template over and over again
(
defn-
apply-template
[
template-key
event
]
;; (println (:type event))
;; (println (:type event)
" " (:source event)
)
(
let
[
path
(
template-key
event
)
;; _ (println path)
;; _ (println
"hello"
path)
source
(
util/slurp
path
)
renderer
(
hbs/compile
source
)]
(
renderer
(
clj->js
event
))))
...
...
src/easy/util.cljs
View file @
6cfd61ee
...
...
@@ -55,6 +55,15 @@
(
.writeFileSync
fs
path
content
))
(
defn
exit
[
c
]
(
.exit
js/process
(
or
c
0
)))
(
defn
die
[
s
]
(
warn
s
)
(
exit
1
))
(
defn
indent
"Indents a multiline string `s` by `n` spaces."
[
s
n
]
...
...
@@ -69,9 +78,43 @@
(
indent
2
)))
(
defn
parse-yaml
[
string
]
(
->
(
yaml/load
string
)
(
js->clj
:keywordize-keys
true
)))
(
defn
apply-frontmatter-template
"Takes a vector of documents. Dies if the vector has 0 or more than 2
entries. If it has 1 entry it will just return that entry. If it
finds 2 entries it will use the first doc as a event template (with
defaults) for the list of events found in the 2nd entry. It returns
then the list of events found in the 2nd entry merged into the
defaults of the event template found in the 1st entry."
[
doc
]
(
case
(
count
doc
)
;; zero docs? something went wrong
0
(
die
"No document?"
)
;; one doc, the regular case, just unwrap it from the docs vector
1
(
first
doc
)
;; two docs: the first is an event template (with defaults), which
;; is used as a basis for the list of events in the 2nd doc
2
(
map
#
(
merge
(
first
doc
)
%
)
(
second
doc
))
;; else
;; TODO: this could be used to have templates and event lists in
;; alternating fashion
(
die
"Sorry, don't know how to handle more then two docs."
)))
(
defn
annotate
"Annotates all events with `:source-path '<path>:e<index>'`, where
index is the position of the event in the source file."
[
events
path
]
(
map-indexed
#
(
assoc
%2
:source-path
(
str
path
":e"
%1
))
events
))
(
defn
parse-yaml
"Parses YAML, applys any YAML frontmatter event templates
and annotates the events with their `:source`."
[
string
]
(
->
string
yaml/loadAll
(
js->clj
:keywordize-keys
true
)
apply-frontmatter-template
))
(
def
date?
(
partial
instance?
js/Date
))
...
...
@@ -131,10 +174,11 @@
x
))
(
defn
exit
[
c
]
(
.exit
js/process
(
or
c
0
)))
(
defn
die
[
s
]
(
warn
s
)
(
exit
1
))
(
defn
harmonize-date-field
[
field
evt
]
(
if-let
[
date
(
field
evt
)]
(
if
(
string?
date
)
;; NOTE don't use this, this does not return an instance of Date
;; (assoc evt field (time/parse util/iso-formatter date))
(
assoc
evt
field
(
js/Date.
date
))
evt
)
evt
))
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment