This commit is contained in:
chaos 2024-11-07 21:45:22 +00:00
parent 87e114d76d
commit d2da9e1af4
14 changed files with 123 additions and 62 deletions

3
.gitignore vendored
View file

@ -1 +1,2 @@
export.json export.json
.dev.env

15
run.sh
View file

@ -3,6 +3,17 @@
set -eu set -eu
SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)" SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
cd "$SCRIPT_DIR" cd "$SCRIPT_DIR/tool"
JQ=${JQ:-jq}
export JQ_FLAVOR=${JQ_FLAVOR:-${JQ}}
run() {
${JQ} -rn -L "$(realpath .)" -L "$(realpath lib)" -L "$(realpath dropins)/${JQ_FLAVOR}" \
--slurpfile exportFile "${EXPORT_FILE:-export.json}" \
'include "main"; main' \
--args -- "$@"
}
run "$@"
${JQ:-jq} ${JQ_ARGS:-} -L "tool" -f tool/main.jq -Cr "${EXPORT_FILE:-export.json}" --args -- "$@"

View file

@ -1,11 +1,19 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -eu
SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)" SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
cd "$SCRIPT_DIR" cd "${SCRIPT_DIR}/tool" || return
export TYPECHECKING=1 export JQ_TYPECHECKING=1
${JQ:-jq} -n -r -L tool -L . "include \"testLib\"; testLibMain" runTests() {
${JQ:-jq} -n -r -L tool -L . "include \"tests\"; testsMain" JQ=${JQ:-jq}
export JQ_FLAVOR=${JQ_FLAVOR:-jq}
echo "Running Tests with JQ=${JQ}"
${JQ} -n -r -L . -L "dropins/${JQ_FLAVOR}" "include \"tests\"; testsMain"
}
runTests
if command -v gojq 2>/dev/null >/dev/null; then
JQ=gojq JQ_FLAVOR=gojq runTests
fi

View file

View file

View file

@ -1,3 +1,4 @@
include "dropins";
include "utils"; include "utils";
def formatExperienceTitle: def formatExperienceTitle:
@ -47,7 +48,7 @@ def formatIngestionROA($customUnits; $substitutions):
(if (if
$substitutions | has($roa) $substitutions | has($roa)
then then
$substitutions.[$roa] $substitutions | .[$roa]
else else
$roa | titleCase $roa | titleCase
end) as $roaText | end) as $roaText |
@ -104,8 +105,7 @@ def experienceStats($customUnits):
. | ingestionUnit($customUnits) as $unit | . | ingestionUnit($customUnits) as $unit |
(.consumerName // "default") as $consumerName | (.consumerName // "default") as $consumerName |
$stats | $stats | .[$consumerName].[$name].[$administrationRoute] |=
.[$consumerName].[$name].[$administrationRoute]|=
($stats.[$consumerName].[$name].[$administrationRoute] // { ($stats.[$consumerName].[$name].[$administrationRoute] // {
unit: "", unit: "",
# null because null+null = null for ingestions with unknown dose which .dose is null # null because null+null = null for ingestions with unknown dose which .dose is null
@ -117,8 +117,8 @@ def experienceStats($customUnits):
def calculateCombinedDose($substanceName; $consumerName): def calculateCombinedDose($substanceName; $consumerName):
. as $stats | . as $stats |
($stats.[$consumerName].[$substanceName] | [to_entries[] | .value.dose] | add)| . as $combinedDose | (.[$consumerName].[$substanceName] | [to_entries[] | .value.dose] | add) as $combinedDose |
($stats.[$consumerName].[$substanceName] | to_entries[0] | .value.unit) as $combinedDoseUnit | (.[$consumerName].[$substanceName] | to_entries[0] | .value.unit) as $combinedDoseUnit |
{dose: $combinedDose, unit: $combinedDoseUnit}; {dose: $combinedDose, unit: $combinedDoseUnit};
def experienceByTitle($name): def experienceByTitle($name):

View file

@ -16,8 +16,11 @@ def parseArgBool:
def parseArgs: def parseArgs:
. as $args | . as $args |
if
($args.named | has("argsJson"))
then $args.named.argsJson[0] else $args.positional end | . as $args |
reduce $args.positional[] as $arg ({ reduce $args[] as $arg ({
shortArgs: [], shortArgs: [],
longArgs: {}, longArgs: {},
nonArgs: [] nonArgs: []

View file

@ -1,12 +1,12 @@
include "testLib"; import "testLib" as testLib;
def typecheckingEnabled: def typecheckingEnabled:
if $ENV["TYPECHECKING"] != null and (["1", "true", "on"] | any(index($ENV["TYPECHECKING"]))) then if $ENV["JQ_TYPECHECKING"] != null and (["true", "1", "debug"] | any(index($ENV["JQ_TYPECHECKING"]))) then
true true
else false end; else false end;
def typecheckingDebug: def typecheckingDebug:
if $ENV["TYPECHECKING_DEBUG"] != "" and $ENV["TYPECHECKING_DEBUG"] != null then if $ENV["JQ_TYPECHECKING"] == "debug" then
true true
else false end; else false end;
@ -59,21 +59,26 @@ def ensureKey($value; $type; $key): $value | ensureKey($type; $key);
def ensureWrapError($newType; ensureType): def ensureWrapError($newType; ensureType):
. as $value | . as $value |
try (. | ensureType) catch (error(typeErrorText($newType))); try (. | ensureType)
catch (
. as $prevError |
if typecheckingDebug then debug({$newType, $prevError}) end |
error(typeErrorText($newType))
);
def ensureWrapError($value; $newType; ensureType): def ensureWrapError($value; $newType; ensureType):
$value | ensureWrapError($newType; ensureType); $value | ensureWrapError($newType; ensureType);
# TYPECHECKING=1 required for tests # JQ_TYPECHECKING=true required for tests
def typeLibTests: def typeLibTests:
expectPassed(runTest( testLib::expectPassed(testLib::runTest(
"null is null"; "null is null";
(null | ensureNull); (null | ensureNull);
true; true;
false false
)) | )) |
expectPassed(runTest( testLib::expectPassed(testLib::runTest(
"boolean is not null"; "boolean is not null";
(true | ensureNull); (true | ensureNull);
(. == typeErrorText("null")); (. == typeErrorText("null"));

View file

@ -1,10 +1,11 @@
# run as: jq export.json -f tool.jq -Cr --args -- include "dropins";
import "lib/typeLib" as typeLib;
import "lib/argsLib" as argsLib;
include "utils"; include "utils";
include "argsLib";
include "journalUtils"; include "journalUtils";
import "types" as types; import "types" as types;
import "typeLib" as typeLib;
def printExperienceStats($stats; $substanceFilter; $consumerFilter; $withTitle): def printExperienceStats($stats; $substanceFilter; $consumerFilter; $withTitle):
. as $experience | . as $experience |
@ -244,17 +245,17 @@ def printExperiencesAdvanced($customUnits; $substanceFilter; $consumerFilter; $s
)) + "\n"; )) + "\n";
def main($ARGS): def main:
def usage: def usage:
[ [
"psychonaut_journal_stats {printExperience,printExperiencesAdvanced}", "psychonaut_journal_stats {printExperience,printExperiencesAdvanced}",
"" ""
] | join("\n") | halt_error(1); ] | join("\n") | halt_error(1);
. as $exportData | $ARGS.named["exportFile"][0] as $exportData |
$exportData | types::ensureExportData | $exportData | types::ensureExportData |
($ARGS | parseArgs) as $parsedArgs | ($ARGS | argsLib::parseArgs) as $parsedArgs |
$parsedArgs.nonArgs[0] as $program | $parsedArgs.nonArgs[0] as $program |
($parsedArgs | .nonArgs |= $parsedArgs.nonArgs[1:]) as $parsedArgs | ($parsedArgs | .nonArgs |= $parsedArgs.nonArgs[1:]) as $parsedArgs |
@ -292,13 +293,13 @@ def main($ARGS):
$longArg.value as $value | $longArg.value as $value |
if $arg == "pretty" then if $arg == "pretty" then
.pretty |= (ifNullDefault($value; $defaultOptions.pretty) | parseArgBool) .pretty |= (ifNullDefault($value; $defaultOptions.pretty) | argsLib::parseArgBool)
end | end |
if $arg == "title" then if $arg == "title" then
.withTitle |= (ifNullDefault($value; $defaultOptions.withTitle) | parseArgBool) .withTitle |= (ifNullDefault($value; $defaultOptions.withTitle) | argsLib::parseArgBool)
end | end |
if $arg == "stats" then if $arg == "stats" then
.withStats |= (ifNullDefault($value; $defaultOptions.withStats) | parseArgBool) .withStats |= (ifNullDefault($value; $defaultOptions.withStats) | argsLib::parseArgBool)
end | end |
if $arg == "substance-filter" then if $arg == "substance-filter" then
.substanceFilter |= ($parsedArgs.longArgs.["substance-filter"] | split(",")) .substanceFilter |= ($parsedArgs.longArgs.["substance-filter"] | split(","))
@ -390,5 +391,3 @@ def main($ARGS):
else else
usage usage
end; end;
main($ARGS)

View file

@ -1,27 +1,32 @@
import "./testdata/tests_export" as $exportDataArray; include "dropins";
include "journalUtils";
include "testLib"; import "lib/testLib" as testLib;
import "typeLib" as typeLib; import "lib/typeLib" as typeLib;
import "journalUtils" as journalUtils;
import "testdata/tests_export" as $exportDataArray;
def journalUtilsTests: def journalUtilsTests:
expectPassed(runTest( testLib::expectPassed(testLib::runTest(
"invalid input to experienceByTitle"; "invalid input to experienceByTitle";
( (
null | experienceByTitle("Test") null | journalUtils::experienceByTitle("Test")
); );
. == "experienceByTitle takes a array of experiences as input"; . == "experienceByTitle takes a array of experiences as input";
true true
)) | )) |
expectPassed(runTest( testLib::expectPassed(testLib::runTest(
"experience not found"; "experience not found";
( (
$exportDataArray[0].experiences | experienceByTitle("Test") $exportDataArray[0].experiences | journalUtils::experienceByTitle("Test")
); );
. == null; . == null;
false false
)); ));
def testsMain: def testsMain:
journalUtilsTests | testLib::testTests |
typeLib::typeLibTests | typeLib::typeLibTests |
journalUtilsTests |
"Tests Passed\n" | halt_error(0); "Tests Passed\n" | halt_error(0);

View file

@ -1,34 +1,61 @@
import "typeLib" as typeLib; include "dropins";
import "lib/typeLib" as typeLib;
#["DEBUG:",{"creationDate":"number","ingestions":[{"administrationRoute":"string","consumerName":"null","creationDate":"number","customUnitId":"null","dose":"number","estimatedDoseStandardDeviation":"null","isDoseAnEstimate":"boolean","notes":"string","stomachFullness":"null","substanceName":"string","time":"number","units":"string"}],"isFavorite":"boolean","location":"null","ratings":"array:empty/unknown","sortDate":"number","text":"string","timedNotes":"array:empty/unknown","title":"string"}] #["DEBUG:",{"creationDate":"number","ingestions":[{"administrationRoute":"string","consumerName":"null","creationDate":"number","customUnitId":"null","dose":"number","estimatedDoseStandardDeviation":"null","isDoseAnEstimate":"boolean","notes":"string","stomachFullness":"null","substanceName":"string","time":"number","units":"string"}],"isFavorite":"boolean","location":"null","ratings":"array:empty/unknown","sortDate":"number","text":"string","timedNotes":"array:empty/unknown","title":"string"}]
def ensureExperience: def ensureIngestion:
. as $experience | . as $ingestion |
typeLib::ensureObject | typeLib::ensureObject |
debug(. | typeLib::dumpType) | $ingestion | typeLib::ensureKey("ingestion"; "substanceName") |
.substanceName | typeLib::ensureWrapError("experience:substanceName"; typeLib::ensureString);
$experience | def ensureTimedNote:
typeLib::ensureKey("experience"; "title") | . as $timedNote |
.title | typeLib::ensureWrapError("experience:title"; typeLib::ensureString) | if typeLib::typecheckingEnabled then
$timedNote | typeLib::ensureObject |
$timedNote | typeLib::ensureKey("timedNote"; "color") |
$timedNote.color | typeLib::ensureWrapError("timedNote:color"; typeLib::ensureString) |
$timedNote | typeLib::ensureKey("timedNote"; "creationDate") |
$timedNote.creationDate | typeLib::ensureWrapError("timedNote:creationDate"; typeLib::ensureNumber) |
$timedNote | typeLib::ensureKey("timedNote"; "isPartOfTimeline") |
$timedNote.isPartOfTimeline | typeLib::ensureWrapError("timedNote:isPartOfTimeline"; typeLib::ensureBool) |
$timedNote | typeLib::ensureKey("timedNote"; "note") |
$timedNote.note | typeLib::ensureWrapError("timedNote:note"; typeLib::ensureString) |
$timedNote | typeLib::ensureKey("timedNote"; "time") |
$timedNote.time | typeLib::ensureWrapError("timedNote:time"; typeLib::ensureNumber)
end;
$experience | def ensureExperience:
typeLib::ensureKey("experience"; "text") | . as $experience |
.text | typeLib::ensureWrapError("experience:text"; typeLib::ensureString) | if typeLib::typecheckingEnabled then
$experience | typeLib::ensureObject |
$experience | $experience | typeLib::ensureKey("experience"; "title") |
typeLib::ensureKey("experience"; "creationDate") | $experience.title | typeLib::ensureWrapError("experience:title"; typeLib::ensureString) |
.creationDate | typeLib::ensureWrapError("experience:creationDate"; typeLib::ensureNumber) |
$experience | $experience | typeLib::ensureKey("experience"; "text") |
typeLib::ensureKey("experience"; "sortDate") | $experience.text | typeLib::ensureWrapError("experience:text"; typeLib::ensureString) |
.sortDate | typeLib::ensureWrapError("experience:sortDate"; typeLib::ensureNumber) |
$experience | $experience | typeLib::ensureKey("experience"; "creationDate") |
typeLib::ensureKey("experience"; "isFavorite") | $experience.creationDate | typeLib::ensureWrapError("experience:creationDate"; typeLib::ensureNumber) |
.isFavorite | typeLib::ensureWrapError("experience:isFavorite"; typeLib::ensureBool)
; $experience | typeLib::ensureKey("experience"; "sortDate") |
$experience.sortDate | typeLib::ensureWrapError("experience:sortDate"; typeLib::ensureNumber) |
$experience | typeLib::ensureKey("experience"; "isFavorite") |
$experience.isFavorite | typeLib::ensureWrapError("experience:isFavorite"; typeLib::ensureBool) |
$experience | typeLib::ensureKey("experience"; "timedNotes") |
$experience.timedNotes | typeLib::ensureWrapError("experience:timedNotes"; typeLib::ensureArray) |
(reduce $experience.timedNotes[] as $timedNote (null; $timedNote | ensureTimedNote)) |
$experience | typeLib::ensureKey("experience"; "ingestions") |
$experience.ingestions | typeLib::ensureWrapError("experience:ingestions"; typeLib::ensureArray) |
(reduce $experience.ingestions[] as $ingestion (null; $ingestion | ensureIngestion))
end;
def ensureExportData: def ensureExportData:
. as $exportData | . as $exportData |

View file

@ -1,3 +1,5 @@
include "dropins";
def debugLog($target; $value): def debugLog($target; $value):
if if
($ENV["JQ_DEBUG"] == $target) ($ENV["JQ_DEBUG"] == $target)