diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d667af7..db56a44 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.10", "3.11", "3.12"] + python-version: ["3.11", "3.12", "3.13", "3.14"] # Steps represent a sequence of tasks that will be executed as part of the job diff --git a/README.md b/README.md index ae77eb5..2a9301f 100644 --- a/README.md +++ b/README.md @@ -6,50 +6,37 @@ clean. * [jdlint \[N14.0001\]](#jdlint-n140001) * [Installation/Requirements](#installationrequirements) * [Usage](#usage) - * [With a JDex/Index](#with-a-jdexindex) - * [JDex Formats](#jdex-formats) - * [Alternative Layout for the Standard Zeros](#alternative-layout-for-the-standard-zeros) - * [Ignoring Files](#ignoring-files) - * [Disabling Specific Rules](#disabling-specific-rules) - * [I Am a Robot and Want Something Machine-Readable](#i-am-a-robot-and-want-something-machine-readable) - * [File Errors](#file-errors) - * [`AREA_DIFFERENT_FROM_JDEX`](#area_different_from_jdex) - * [`AREA_NOT_IN_JDEX`](#area_not_in_jdex) - * [`CATEGORY_DIFFERENT_FROM_JDEX`](#category_different_from_jdex) - * [`CATEGORY_IN_WRONG_AREA`](#category_in_wrong_area) - * [`CATEGORY_NOT_IN_JDEX`](#category_not_in_jdex) - * [`DUPLICATE_AREA`](#duplicate_area) - * [`DUPLICATE_CATEGORY`](#duplicate_category) + * [Config File](#config-file) + * [Ignoring Files](#ignoring-files) + * [Disabling Specific Rules](#disabling-specific-rules) + * [I Am a Robot and Want Something Machine-Readable](#i-am-a-robot-and-want-something-machine-readable) + * [Errors](#errors) + * [`ARBITRARY_CONTENT_WHERE_NOT_ALLOWED`](#arbitrary_content_where_not_allowed) * [`DUPLICATE_ID`](#duplicate_id) - * [`FILE_OUTSIDE_ID`](#file_outside_id) - * [`ID_DIFFERENT_FROM_JDEX`](#id_different_from_jdex) - * [`ID_IN_WRONG_CATEGORY`](#id_in_wrong_category) + * [`EMPTY_FOLDER`](#empty_folder) + * [`ENCOUNTERED_FORBIDDEN_FOLDER`](#encountered_forbidden_folder) + * [`FILE_WHERE_FOLDER_EXPECTED`](#file_where_folder_expected) + * [`FOLDER_SHOULD_BE_EMPTY`](#folder_should_be_empty) * [`ID_NOT_IN_JDEX`](#id_not_in_jdex) - * [`INVALID_AREA_NAME`](#invalid_area_name) - * [`INVALID_CATEGORY_NAME`](#invalid_category_name) - * [`INVALID_ID_NAME`](#invalid_id_name) - * [`NONEMPTY_INBOX`](#nonempty_inbox) + * [`ID_DIFFERENT_FROM_JDEX`](#id_different_from_jdex) * [JDex Errors](#jdex-errors) - * [`JDEX_AREA_HEADER_DIFFERENT_FROM_AREA`](#jdex_area_header_different_from_area) - * [`JDEX_AREA_HEADER_WITHOUT_AREA`](#jdex_area_header_without_area) - * [`JDEX_CATEGORY_IN_WRONG_AREA`](#jdex_category_in_wrong_area) - * [`JDEX_DUPLICATE_AREA`](#jdex_duplicate_area) - * [`JDEX_DUPLICATE_AREA_HEADER`](#jdex_duplicate_area_header) - * [`JDEX_DUPLICATE_CATEGORY`](#jdex_duplicate_category) + * [`JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED`](#jdex_arbitrary_content_where_not_allowed) * [`JDEX_DUPLICATE_ID`](#jdex_duplicate_id) - * [`JDEX_FILE_OUTSIDE_CATEGORY`](#jdex_file_outside_category) - * [`JDEX_ID_IN_WRONG_CATEGORY`](#jdex_id_in_wrong_category) - * [`JDEX_INVALID_AREA_NAME`](#jdex_invalid_area_name) - * [`JDEX_INVALID_CATEGORY_NAME`](#jdex_invalid_category_name) - * [`JDEX_INVALID_ID_NAME`](#jdex_invalid_id_name) + * [`JDEX_EMPTY_FOLDER`](#jdex_empty_folder) + * [`JDEX_ENCOUNTERED_FORBIDDEN_FOLDER`](#jdex_encountered_forbidden_folder) + * [`JDEX_ENCOUNTERED_FORBIDDEN_NOTE`](#jdex_encountered_forbidden_note) + * [`JDEX_FILE_WHERE_FOLDER_EXPECTED`](#jdex_file_where_folder_expected) + * [`JDEX_FOLDER_WHERE_NOTE_EXPECTED`](#jdex_folder_where_note_expected) + * [Does This Modify My Files?](#does-this-modify-my-files) * [Why Doesn't This Check For-](#why-doesnt-this-check-for-) + * [This Doesn't Work with My System Because-](#this-doesnt-work-with-my-system-because-) * [Acknowledgments](#acknowledgments) ## Installation/Requirements Install a fairly recent version of [Python 3](https://www.python.org/downloads/); `jdlint` is tested to work on -Python 3.10 and up. Python 3.9 and earlier is not supported. +Python 3.11 and up. That's it! There are no other dependencies. @@ -60,290 +47,187 @@ That's it! There are no other dependencies. The script itself is executable (you should be able to just run `./jdlint.py`), or you can explicitly point python at it, like `python3 jdlint.py`. -You'll need to pass the script the root folder of your JD-organized filesystem, -e.g. - -```bash -./jdlint.py ~/Documents -``` - -### With a JDex/Index - -If you have your JDex/Index stored as files, you can improve the number of -detected issues by passing that root path along as well, e.g. +You'll need to provide it wit a config file. By default, it looks for +`jdlint.toml` in the working directory; you may specify a different config file +with the `-c` flag, e.g. ```bash -./jdlint.py --jdex ~/"Knowledge/00.00 πŸ“‡ System Index" ~/Documents +./jdlint.py -c ~/my_jdlint_config.toml ``` -#### JDex Formats - -This supports three possible JDex formats: - -* Single file, as specified [here](https://github.com/johnnydecimal/index-spec). - Note that strict adherence to the spec is not checked, because I personally do - not use this method and am lazy, so don't expect linter errors for your JDex - if you use this format. -* Nested files in folders, e.g. - -```text -. -└── 00-09 System - └── 01 System Stuff - β”œβ”€β”€ 01.02 A Name.md - └── 01.03 Another ID.md -``` - -* Flat files, e.g. - -```tree -. -β”œβ”€β”€ 00.00 System Area Management.md -β”œβ”€β”€ 01.00 System Stuff Category Management.md -β”œβ”€β”€ 01.02 A Name.md -└── 01.03 Another ID.md -``` - -Note that in the flat case, `N0.00` is taken as the JDex entry for area `N0-N9`, -and `AC.00` is taken as the JDex entry for category `AC`. - -In all cases, any `.md` file extension will be stripped, should one exist. +Everything the script needs is specified in the config file. -A trailing `area management` or `category management` or `index` will also be -stripped, if one exists, to derive the "canonical" name for the area/category. +## Config File -For example: +Several config files are provided in this repository, matching the various +JDex/JD standards. You can of course customize it to your liking. -* `10.00 Life Admin` -* `10.00 Life Admin.md` -* `10.00 Life Admin Area Management` -* `10.00 Life Admin Index` -* `10.00 Life Admin Area Management Index.md` +It's recommended you read the [Config README](./configs/README.md) for +information on the format, and check out the provided example configs in that +folder, which are (hopefully) well-documented. If you have questions/need help, +please feel free to poke me on the JD Discord. -are all equivalent, and will lead to `jdlint` expecting an area named -`10-19 Life Admin` in your files. +## Ignoring Files -#### Alternative Layout for the Standard Zeros +If you wish to ignore files/folders, patterns can be added globally to +`linter.ignore`, to a single root's `.ignore`, or to `system.jdex.ignore`. -For a more complete treatment of this topic, see the original post -[here](https://forum.johnnydecimal.com/t/the-standard-zeros/1558/12). - -This moves the expected area management zeros into the system management area. -For example, the management category for area `10-19` will be category `01`, -instead of the typical `10`. This increases the available number of categories -per area and makes greater use of the reserved `00-09` area. - -To specify that you're using this format, pass `jdlint` the `--altzeros` flag. - -This causes two changes in behavior if you are using the flat files JDex -structure: - -* The linter will treat `10.00` as the note for category `10`, and `01.00` as - the note for area `10-19`, etc. -* The area management notes (`0N.00`) will additionally create categories in the - `00-09` area, for those standard zeros. -* The linter will check for optional "header" files. This is not an official - Johnny Decimal thing, just something I use to visually separate notes in the - JDex. They are named e.g. `10. Life Admin` for the `10-19 Life Admin` area. - - ![An image showing how `40. Improvement` nicely shows `20.00 Education` as nested under it.](images/header_note.png) - - If you don't use them, there will be no complaints from the linter; it just - ensures their names stay in sync with the area if they do already exist. - -### Ignoring Files - -You may have files outside of IDs that have to be there; if so, you can ignore -them, e.g. +Additionally, you can ignore them just for one run with: ```bash -./jdlint.py ~/Documents --ignore .st* +./jdlint.py --ignore .st* ``` +This option may be specified more than once. + This option supports some basic glob-style patterns. (It uses [`PurePath.match()`](https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.match).) -### Disabling Specific Rules +## Disabling Specific Rules -Maybe you disagree with a specific issue detected by this linter or have reason -to break the rules. If so, you can disable a rule, e.g. +If you wish to disable a specific rule, it can be added globally to +`linter.disable_rules`. -```bash -./jdlint.py ~/Documents --disable NONEMPTY_INBOX -``` - -### I Am a Robot and Want Something Machine-Readable - -Ask nicely for JSON output instead! +Additionally, you can ignore them just for one run with: ```bash -./jdlint.py ~/Documents --json +./jdlint.py --disable DUPLICATE_ID ``` -## File Errors - -These are errors that can be generated for your files. Some of them require you -passing your JDex via the `--jdex` argument to be detected. +This option may be specified more than once. -### `AREA_DIFFERENT_FROM_JDEX` +## I Am a Robot and Want Something Machine-Readable -An area with a differently-named JDex entry, e.g. +Either set `linter.json_output = true` in the config file, or force JSON output +just once with the flag: -```text -. -β”œβ”€β”€ files -β”‚Β Β  └── 00-09 Systme <-- This is a typo, oops! -β”‚Β Β  └── 01 System Stuff -β”‚Β Β  β”œβ”€β”€ 01.00 An ID -β”‚Β Β  β”œβ”€β”€ 01.02 A Name -β”‚Β Β  └── 01.03 Another ID -└── jdex - Β  └── 00-09 System - Β Β  └── 01 System Stuff - Β Β  β”œβ”€β”€ 01.00 An ID.md - Β Β  β”œβ”€β”€ 01.02 A Name.md - Β Β  └── 01.03 Another ID.md +```bash +./jdlint.py --json ``` -### `AREA_NOT_IN_JDEX` +Note that these JSON results additionally contain complete information about the +structure of your system that jdlint had to scan, if that information if of use +to you. This structure only returns portions of the system that are at least +possibly valid; it will not return forbidden files/folders, or files where +folders are required, for example. -An area without a corresponding JDex entry, e.g. +## Errors -```text -. -β”œβ”€β”€ files -β”‚Β Β  β”œβ”€β”€ 00-09 System -β”‚Β Β  β”‚Β Β  └── 01 System Stuff -β”‚Β Β  β”‚Β Β  β”œβ”€β”€ 01.02 A Name -β”‚Β Β  β”‚Β Β  └── 01.03 Another ID -β”‚Β Β  └── 10-19 Oops <-- This area has no corresponding entry in the JDex/index -β”‚Β Β  └── 11 Cat -β”‚Β Β  └── 11.12 ID -└──jdex - Β Β  β”œβ”€β”€ 00.00 System.md - Β Β  β”œβ”€β”€ 01.00 System Stuff.md - Β Β  β”œβ”€β”€ 01.02 A Name.md - Β Β  β”œβ”€β”€ 01.03 Another ID.md - Β Β  β”œβ”€β”€ 11.00 Cat.md - Β Β  └── 11.12 ID.md -``` +These are errors that can be generated for your files; some of them may require +the JDex to determine. -### `CATEGORY_DIFFERENT_FROM_JDEX` +### `ARBITRARY_CONTENT_WHERE_NOT_ALLOWED` -A category with a differently-named JDex entry, e.g. +A file or folder was found that didn't match you specified format, e.g. ```text . -β”œβ”€β”€ files -β”‚Β Β  └── 00-09 System -β”‚Β Β  └── 01 System Stuf <-- This is a typo, oops! -β”‚Β Β  β”œβ”€β”€ 01.00 An ID -β”‚Β Β  β”‚Β Β  └── Other File -β”‚Β Β  β”œβ”€β”€ 01.02 A Name -β”‚Β Β  └── 01.03 Another ID -└── jdex - Β  └── 00-09 System - Β Β  └── 01 System Stuff - Β Β  β”œβ”€β”€ 01.00 An ID.md - Β Β  β”œβ”€β”€ 01.02 A Name.md - Β Β  └── 01.03 Another ID.md +β”œβ”€β”€ 10-19 Life +β”‚ β”œβ”€β”€ 11 Me, Myself, & I +β”‚ β”‚Β Β  β”œβ”€β”€ 11.11 Me +β”‚ β”‚Β Β  β”œβ”€β”€ 11.12 Myself +β”‚ β”‚Β Β  └── Not An Id <-- These don't belong here +β”‚ └── 21 You <-- These don't belong here +└── Stuff <-- These don't belong here ``` -### `CATEGORY_IN_WRONG_AREA` +### `DUPLICATE_ID` -A category that, by its number, has been put in the wrong area, e.g. +An ID that has been used multiple times, e.g. ```text . -└── 00-09 System - β”œβ”€β”€ 01 System Stuff - β”‚Β Β  └── 01.00 An ID - └── 11 Whoops <-- This is in the wrong area - └── 11.01 Inbox +β”œβ”€β”€ 00-09 System <-- 00-09 has been used twice! +β”‚ β”œβ”€β”€ 01 System Stuff <-- 01 has been used twice! +β”‚ β”‚ β”œβ”€β”€ 01.11 An ID <-- 01.11 has been used twice! +β”‚ β”‚ └── 01.11 A Reuse <-- 01.11 has been used twice! +β”‚ └── 01 A Reuse <-- 01 has been used twice! +β”‚ └── 01.02 Another ID +└── 00-09 A Reuse <-- 00-09 has been used twice! + └── 02 Another Category + └── 02.00 An ID ``` -### `CATEGORY_NOT_IN_JDEX` +### `EMPTY_FOLDER` -A category without a corresponding JDex entry, e.g. +A completely empty folder was found; you shouldn't have folders that clutter +things up if they aren't actually serving a purpose. ```text . -β”œβ”€β”€ files -β”‚Β Β  └── 00-09 System -β”‚Β Β  └── 01 System Stuff <-- This category has no corresponding entry in the JDex -β”‚Β Β  β”œβ”€β”€ 01.02 An ID -β”‚Β Β  └── 01.03 Another ID -└── jdex - Β Β  β”œβ”€β”€ 00.00 System.md - Β Β  β”œβ”€β”€ 01.00 An ID.md - Β Β  └── 01.03 Another ID.md +β”œβ”€β”€ 00-09 System +β”‚ β”œβ”€β”€ 01 System Stuff +β”‚ β”‚ └── 01.11 Empty <-- These are all empty folders (just suppose there's no content it here) +β”‚ └── 02 Empty Category <-- These are all empty folders +└── 10-19 Empty Area <-- These are all empty folders ``` -### `DUPLICATE_AREA` +### `ENCOUNTERED_FORBIDDEN_FOLDER` -An area that has been used multiple times, e.g. +A folder that was specified as forbidden in the config was encountered. (These +can be used to ensure that naming schemes are followed.) ```text . -β”œβ”€β”€ 00-09 An Area <-- 00-09 has been used twice! -β”‚Β Β  └── 01 A Category -β”‚Β Β  └── 01.00 An ID -└── 00-09 A Reuse <-- 00-09 has been used twice! - └── 02 Another Category - └── 02.00 An ID +└── 10-19 Life + └── 11 Me, Myself, & I + Β Β  β”œβ”€β”€ 11.01 Meh <-- This should be called AC.01 Inbox + Β Β  └── 11.11 Me ``` -### `DUPLICATE_CATEGORY` +### `FILE_WHERE_FOLDER_EXPECTED` -A category that has been used multiple times, e.g. +A file was found with the name of something that should have been a folder. ```text . -└── 00-09 System - β”œβ”€β”€ 01 A Category <-- 01 has been used twice! - β”‚Β Β  └── 01.00 An ID - └── 01 A Reuse <-- 01 has been used twice! - └── 01.02 Another ID +└── 10-19 Life + β”œβ”€β”€ 11 Me, Myself, & I + β”‚Β Β  β”œβ”€β”€ 11.11 Me + β”‚Β Β  β”œβ”€β”€ 11.12 Myself + β”‚Β Β  └── 11.13 I + └── 12 You <-- This is a file that looks like a category folder ``` -### `DUPLICATE_ID` +### `FOLDER_SHOULD_BE_EMPTY` -An ID that has been used multiple times, e.g. +A folder that should be empty per the config (e.g. inboxes and headers) wasn't. ```text . -└── 00-09 System - └── 01 System Stuff - β”œβ”€β”€ 01.11 An ID <-- 01.11 has been used twice! - └── 01.11 A Reuse <-- 01.11 has been used twice! +└── 10-19 Life + └── 11 Me, Myself, & I + Β Β  β”œβ”€β”€ 11.01 Inbox <-- These shouldn't have files in them + β”‚Β Β  └── Some file + Β Β  β”œβ”€β”€ 11.10 β–  The Me's <-- These shouldn't have files in them + β”‚Β Β  └── Some file + Β Β  └── 11.11 Me ``` -### `FILE_OUTSIDE_ID` +### `ID_NOT_IN_JDEX` -A file that is located somewhere higher up than in an ID folder, e.g. +An ID without a corresponding JDex entry, e.g. ```text . -β”œβ”€β”€ 00-09 System -β”‚Β Β  β”œβ”€β”€ 01 System Stuff -β”‚Β Β  β”‚Β Β  β”œβ”€β”€ 01.00 An ID -β”‚Β Β  β”‚Β Β  └── File Outside Id <-- -β”‚Β Β  └── File Outside Category <-- All of these should only be in IDs -└── File Outside Area <-- +β”œβ”€β”€ files +β”‚Β Β  └── 00-09 System <-- This Area has no corresponding entry in the JDex +β”‚Β Β  └── 01 System Stuff <-- This Category has no corresponding entry in the JDex +β”‚Β Β  β”œβ”€β”€ 01.02 Missing ID <-- This ID has no corresponding entry in the JDex +β”‚Β Β  └── 01.03 Another ID +└── jdex + Β Β  └── 01.03 Another ID.md ``` -Use the `--ignore FILE_NAME` option if you have files that *have* to be there, -e.g. `.stignore` is you use Syncthing. - ### `ID_DIFFERENT_FROM_JDEX` An ID with a differently-named JDex entry, e.g. ```text β”œβ”€β”€ files -β”‚Β Β  └── 00-09 System -β”‚Β Β  └── 01 System Stuff -β”‚Β Β  β”œβ”€β”€ 01.02 A Naem <-- This is a typo, oops! +β”‚Β Β  └── 00-09 Systm <-- This is a typo, oops! +β”‚Β Β  └── 01 System Stuf <-- This is a typo, oops! +β”‚Β Β  β”œβ”€β”€ 01.02 A Naem <-- This is a typo, oops! β”‚Β Β  β”œβ”€β”€ 01.03 Another ID β”‚Β Β  └── 01.04 An ID └── jdex @@ -354,262 +238,119 @@ An ID with a differently-named JDex entry, e.g. Β Β  └── 01.04 An ID.md ``` -### `ID_IN_WRONG_CATEGORY` +## JDex Errors -An ID that, by its number, has been put in the wrong category, e.g. +These are errors that are only generated about the state of your JDex, not your +files. -```text -. -└── 00-09 System - └── 01 System Stuff - β”œβ”€β”€ 01.00 An ID - └── 11.01 Whoops <-- This is in the wrong category -``` + | JDexIssueEncounteredForbiddenFolder + | JDexIssueEncounteredForbiddenNote -### `ID_NOT_IN_JDEX` +### `JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED` -An ID without a corresponding JDex entry, e.g. +A file or folder was found that didn't match you specified format, e.g. ```text . -β”œβ”€β”€ files -β”‚Β Β  └── 00-09 System -β”‚Β Β  └── 01 System Stuff -β”‚Β Β  β”œβ”€β”€ 01.00 An ID -β”‚Β Β  β”œβ”€β”€ 01.02 Missing ID <-- This ID has no corresponding entry in the JDex/index -β”‚Β Β  └── 01.03 Another ID -└── jdex - Β Β  β”œβ”€β”€ 01.00 An ID.md - Β Β  └── 01.03 Another ID.md +β”œβ”€β”€ 10-19 Life +β”‚ β”œβ”€β”€ 11 Me, Myself, & I +β”‚ β”‚Β Β  β”œβ”€β”€ 11.11 Me.md +β”‚ β”‚Β Β  β”œβ”€β”€ 11.12 Myself.md +β”‚ β”‚Β Β  └── Not An Id.md <-- These don't belong here +β”‚ └── 21 You <-- These don't belong here +└── Stuff <-- These don't belong here ``` -### `INVALID_AREA_NAME` +### `JDEX_DUPLICATE_ID` -A directory was found at the area level that doesn't begin with `00-09` or the -like, e.g. +An ID that has been used multiple times, e.g. ```text . -β”œβ”€β”€ 00-09 System -β”‚Β Β  └── 01 System Stuff -β”‚Β Β  └── 01.00 An ID -β”œβ”€β”€ 10-18 Malformed <-- This has numbers that were typo'd. -└── No ID <-- This doesn't have numbers at all +β”œβ”€β”€ 01.11 An ID.md <-- 01.11 has been used twice! +└── 01.11 A Reuse.md <-- 01.11 has been used twice! ``` -### `INVALID_CATEGORY_NAME` +### `JDEX_EMPTY_FOLDER` -A directory was found at the category level that doesn't begin with `11` or the -like, e.g. +A completely empty folder was found; you shouldn't have folders that clutter +things up if they aren't actually serving a purpose. ```text . -└── 00-09 System - β”œβ”€β”€ 01 System Stuff - β”‚Β Β  └── 01.00 An ID - β”œβ”€β”€ 2 Malformed <-- This has numbers that were typo'd. - └── No ID <-- This doesn't have numbers at all +β”œβ”€β”€ 00-09 System +β”‚ β”œβ”€β”€ 01 System Stuff +β”‚ β”‚ └── 01.11 Me.md +β”‚ └── 02 Empty Category <-- These are all empty folders +└── 10-19 Empty Area <-- These are all empty folders ``` -### `INVALID_ID_NAME` +### `JDEX_ENCOUNTERED_FORBIDDEN_FOLDER` -A directory was found at the ID level that doesn't begin with `11.12` or the -like, e.g. +A folder that was specified as forbidden in the config was encountered. (These +can be used to ensure that naming schemes are followed.) ```text . -└── 00-09 System - └── 01 System Stuff - β”œβ”€β”€ 01.00 An ID - β”œβ”€β”€ 01.1 Malformed <-- This has numbers that were typo'd. - └── No ID <-- This doesn't have numbers at all +└── 10-19 Life + └── 11 Me, Myself, & I + Β Β  └── 11.00 Meh <-- This should be called AC.00 Index + Β Β  └── 11.11 Me.md ``` -### `NONEMPTY_INBOX` +### `JDEX_ENCOUNTERED_FORBIDDEN_NOTE` -An inbox (AC.01) that contains items, e.g. +A note that was specified as forbidden in the config was encountered. (These can +be used to ensure that naming schemes are followed.) ```text . -└── 01 System Stuff - β”œβ”€β”€ 01.01 Inbox - β”‚ └── This is something you meant to sort that you never got around to... - └── 01.11 An ID -``` - -## JDex Errors - -These are errors that are only generated with the `--jdex` argument and concern -the state of your JDex, not your organized files. - -### `JDEX_AREA_HEADER_DIFFERENT_FROM_AREA` - -An (optional) area header with a differently-named JDex entry, e.g. - -```text -jdex -β”œβ”€β”€ 00.00 System Area Management.md -β”œβ”€β”€ 01.00 Life Admin Area Management.md -β”œβ”€β”€ 01.03 Area Standard Zero.md -β”œβ”€β”€ 10. Life Adminn.md <-- This is a typo, oops! -β”œβ”€β”€ 10.00 Me, Myself, and I.md -└── 10.02 An ID.md -``` - -### `JDEX_AREA_HEADER_WITHOUT_AREA` - -An (optional) area header without any corresponding JDex entry, e.g. - -```text -jdex -β”œβ”€β”€ 00.00 System Area Management.md -β”œβ”€β”€ 01.00 Life Admin Area Management.md -β”œβ”€β”€ 01.03 Area Standard Zero.md -β”œβ”€β”€ 10. Life Admin.md -β”œβ”€β”€ 10.00 Me, Myself, and I.md -β”œβ”€β”€ 10.02 An ID.md -└── 20. Digital Stuff.md <- There is no corresponding area -``` - -### `JDEX_CATEGORY_IN_WRONG_AREA` - -A JDex category that, by its number, has been put in the wrong area, e.g. - -```text -jdex -└── 00-09 System - β”œβ”€β”€ 01 System Stuff - β”‚Β Β  └── 01.00 An ID - └── 11 Whoops <-- This is in the wrong area - └── 11.01 Inbox -``` - -### `JDEX_DUPLICATE_AREA` - -A JDex area that has been used multiple times, e.g. - -```text -jdex -β”œβ”€β”€ 00-09 An Area <-- 00-09 has been used twice! -β”‚Β Β  └── 01 A Category -β”‚Β Β  └── 01.00 An ID -└── 00-09 A Reuse <-- 00-09 has been used twice! - └── 02 Another Category - └── 02.00 An ID -``` - -### `JDEX_DUPLICATE_AREA_HEADER` - -An (optional) area header that has been used multiple times, e.g. - -```text -jdex -β”œβ”€β”€ 00.00 System Area Management.md -β”œβ”€β”€ 01.00 An Area.md -β”œβ”€β”€ 01.03 Area Standard Zero.md -β”œβ”€β”€ 10. An Area.md <-- These are both for 10-19 -β”œβ”€β”€ 10. A Reuse.md <-- These are both for 10-19 -β”œβ”€β”€ 10.00 Me, Myself, and I.md -└── 10.02 An ID.md -``` - -### `JDEX_DUPLICATE_CATEGORY` - -A JDex category that has been used multiple times, e.g. - -```text -jdex -└── 00-09 System - β”œβ”€β”€ 01 A Category <-- 01 has been used twice! - β”‚Β Β  └── 01.00 An ID - └── 01 A Reuse <-- 01 has been used twice! - └── 01.02 Another ID -``` - -### `JDEX_DUPLICATE_ID` - -A JDex ID that has been used multiple times, e.g. - -```text -jdex -└── 00-09 System - └── 01 System Stuff - β”œβ”€β”€ 01.11 An ID <-- 01.11 has been used twice! - └── 01.11 A Reuse <-- 01.11 has been used twice! +└── 10-19 Life + └── 11 Me, Myself, & I + Β Β  β”œβ”€β”€ 11.01 Meh.md <-- This should be called AC.01 Inbox + Β Β  └── 11.11 Me.md ``` -### `JDEX_FILE_OUTSIDE_CATEGORY` +### `JDEX_FILE_WHERE_FOLDER_EXPECTED` -A file that is located at the area or category level in a nested JDex, e.g. +A file was found with the name of something that should have been a folder. ```text -jdex -β”œβ”€β”€ 00-09 System -β”‚Β Β  β”œβ”€β”€ 01 System Stuff -β”‚Β Β  β”‚Β Β  β”œβ”€β”€ 01.02 A Name.md -β”‚Β Β  β”‚Β Β  └── 01.03 Another ID.md -β”‚Β Β  └── Nor here <-- Both of these should only be in categories -└── Not here <-- -``` - -### `JDEX_ID_IN_WRONG_CATEGORY` - -A JDex ID that, by its number, has been put in the wrong category in a nested -structure, e.g. - -```text -jdex -└── 00-09 System - └── 01 System Stuff - β”œβ”€β”€ 01.00 An ID - └── 02.01 Whoops <-- This is in the wrong category +. +└── 10-19 Life + β”œβ”€β”€ 11 Me, Myself, & I + β”‚Β Β  β”œβ”€β”€ 11.11 Me.md + β”‚Β Β  β”œβ”€β”€ 11.12 Myself.md + β”‚Β Β  └── 11.13 I.md + └── 12 You <-- This is a file that looks like a category folder ``` -### `JDEX_INVALID_AREA_NAME` +### `JDEX_FOLDER_WHERE_NOTE_EXPECTED` -A directory was found at the area level in the JDex that doesn't begin with -`00-09` or the like, e.g. +A folder was found with the name of something that should have been a file. ```text -jdex -β”œβ”€β”€ 00-09 System -β”‚Β Β  └── 01 System Stuff -β”‚Β Β  └── 01.02 An ID -β”œβ”€β”€ 10-18 Malformed <-- This has numbers that were typo'd. -└── No ID <-- This doesn't have numbers at all +. +└── 10-19 Life + β”œβ”€β”€ 11 Me, Myself, & I + Β Β  β”œβ”€β”€ 11.11 Me.md + Β Β  β”œβ”€β”€ 11.12 Myself.md + Β Β  └── 11.13 I.md <-- This is a file that looks like a category folder + Β Β  └── Some file ``` -### `JDEX_INVALID_CATEGORY_NAME` +## Does This Modify My Files? -A directory was found at the category level in the JDex that doesn't begin with -`11` or the like, e.g. +No. jdlint makes no changes to your files; you have to fix the problems it finds +yourself. We also think that's a good thing. -```text -jdex -└── 00-09 System - β”œβ”€β”€ 01 System Stuff - β”‚Β Β  └── 01.02 An ID - β”œβ”€β”€ 2 Malformed <-- This has numbers that were typo'd. - └── No ID <-- This doesn't have numbers at all -``` - -### `JDEX_INVALID_ID_NAME` +## Why Doesn't This Check For- -A JDex note was found at the ID level that doesn't begin with `11.12` or the -like, e.g. +Because we didn't think of it. Open an issue and maybe it will get added. -```text -. -└── 00-09 System - └── 01 System Stuff - β”œβ”€β”€ 01.00 An ID - β”œβ”€β”€ 01.1 Malformed <-- This has numbers that were typo'd. - └── No ID <-- This doesn't have numbers at all -``` - -## Why Doesn't This Check For- +## This Doesn't Work with My System Because- -Because I didn't think of it. Open an issue and maybe it will get added! +Open an issue, and if it's reasonable, we can try to support it. ## Acknowledgments diff --git a/configs/README.md b/configs/README.md new file mode 100644 index 0000000..8cdcaed --- /dev/null +++ b/configs/README.md @@ -0,0 +1,175 @@ +# jdlint.toml + +* [jdlint.toml](#jdlinttoml) + * [Introduction](#introduction) + * [JDex Structure](#jdex-structure) + * [Notes on Disk](#notes-on-disk) + * [Single File](#single-file) + * [None](#none) + * ["SiriusStarr"](#siriusstarr) + * [Formats](#formats) + * [Literal Segments](#literal-segments) + * [Variable Segments](#variable-segments) + * [Numeric Segments](#numeric-segments) + * [Wildcard Segments](#wildcard-segments) + * [Bound Segments](#bound-segments) + * [Segment Identifiers](#segment-identifiers) + +## Introduction + +This folder has some example configs for jdlint. They are (hopefully) +well-documented with comments and demonstrate the full range of capabilities. + +You're strongly encouraged to read through the entirety of one of the configs + +## JDex Structure + +### Notes on Disk + +[Partially-nested](./partially_nested_jdex.toml) should work mostly +out-of-the-box with the Life Admin System or Small Business System. You'll need +to set your paths, and there are one or two features that are turned on to +demonstrate the existence of certain options. + +[Fully-nested](./fully_nested_jdex.toml) and [flat](./flat_jdex.toml) JDex's no +longer have "canon" downloads available for them, so they will likely need more +tweaking to make work. + +### Single File + +jdlint supports the official index specification as defined +[here](https://github.com/johnnydecimal/index-spec). + +[JSON JDex](./json_jdex.toml) and [Plaintext JDex](./plaintext_jdex.toml) +demonstrate loading from (respectively) the JSON and plaintext standards. + +If you have your JDex stored in e.g. some database, but are capable of getting +them exported to the JSON standard, this will allow you to still use jdlint. + +Note that this format is extremely restrictive to the exact standard, as the +standard lacks expressiveness for alternative formats. + +Additionally, note that jdlint does not check for adherence *to* the standard +and assumes any file you give it complies with it. It thus does not check for, +for example, orphans. + +### None + +[No JDex](./no_jdex.toml) is exactly what it says on the label; this is +generally an inferior mode to run jdlint in, since it many checks are +impossible, but it may be necessary depending on how you store your JDex. + +### "SiriusStarr" + +[SiriusStarr](./SiriusStarr.toml) is an example config for a very non-standard +system that showcases the ability of jdlint to adapt to flexible system +structures. Probably don't look at it if you're running a very standard JD +system, but if you're trying to fit an odd system of your own, it might be +helpful to look at. + +## Formats + +This section provides an overview of the simple markup used for defining the +format of folders and notes by jdlint. A format can consist of three different +segments: literal segments, variable segments, and bound segments. + +### Literal Segments + +Literal segments match exactly what you type. For example, the format +`format = "My Note.md"` will match a file or folder called exactly `My Note.md` +and nothing else. + +### Variable Segments + +Variable segments, on the other hand, can match a range of values. They are +delimited with `/`, since the slash character cannot appear in filenames +anyways. There are two different kinds, numeric segments and wildcard segments. + +#### Numeric Segments + +Numeric Segments match an exact number of digits and are denoted by one or more +`#` symbols, followed by the name to bind the match to. + +For example, `format = "/##AC/./#Tens/0"` will match all of the following: + +* `00.10` +* `19.70` +* `99.20` + +It will *not* match the following: + +* `0.10` -- (Too few leading digits; matches exactly 2) +* `999.10` -- (Too many leading digits; matches exactly 2) +* `19.710` -- (Too many digits after the decimal; matches exactly 1 followed by + a 0) + +#### Wildcard Segments + +Wildcard segments match 1 or more of *any* character and are denoted by the `*` +symbol, followed by the name to bind the match to. + +For example, `format = "12.35 /*Name/.md"` will match all of the following: + +* `12.35` A.md +* `12.35` This is a long title woooooo.md +* `12.35` This title with 1946 digits and 🐦️ emoji.md + +It will *not* match the following: + +* `12.35A.md` -- (Missing the literal space before the variable segment) +* `12.35 A.m` -- (Missing the `d` on the end of the literal `.md`) +* `12.35 .md` -- (Wildcard segments must match at least 1 character, not + nothing) + +**Note:** If you know regex, this is equivalent to `.+?` under the hood, i.e. +lazily matching one or more character. + +### Bound Segments + +Bound segments refer to variable segments that were defined earlier in the +format **or in an ancestor format** (e.g. a parent folder). They match exactly +the content that matched the variable segment the first time. They are delimited +with `/` and denoted by `=` followed by the alphabetic name of the variable +segment they reference. + +For example, you can define an area folder with +`format = "/#A/0-/=A/9 /*Name/"`, which will match all of the following: + +* `00-09 System` +* `90-99 Archive Stuff` +* `10-19 Life Admin` + +It will *not* match the following: + +* `00-19 System` -- (`A` is bound to be `0` by the first match, which means the + `1` does not then match it) + +Alternately, assuming we are defining a child folder of the above area format, +we could define a category folder with: `format = "/=A//#C/ /*CategoryName/"` +Note that this refers to the variable segment `A`, which isn't defined in this +format but rather in its ancestor. This would then match: + +```text +. +β”œβ”€β”€ 00-09 System +β”‚ └── 01 System Stuff +└── 10-19 Life + └── 11 Me, Myself, & I +``` + +It will *not* match: + +```text +. +β”œβ”€β”€ 00-09 System +β”‚ └── 11 Me, Myself, & I <--- "A" is bound to 0 +└── 10-19 Life + └── 01 System Stuff <--- "A" is bound to 1 +``` + +### Segment Identifiers + +The names used to define variable segments and refer to them in bound segments +must consist only of letters. They may not be reused, since it would be +ambiguous what a bound segment referred to then (this will throw an error if you +try). diff --git a/configs/flat_jdex.toml b/configs/flat_jdex.toml new file mode 100644 index 0000000..e317c17 --- /dev/null +++ b/configs/flat_jdex.toml @@ -0,0 +1,191 @@ +## ############################################################################# +# The linter section handles global settings +## ############################################################################# +[linter] +# Globally disable one or more rules by name, e.g. with `disable_rules = ["ID_DIFFERENT_FROM_JDEX"]` +disable_rules = [] +# Output machine-readable JSON instead of human-readable terminal output +json_output = false +# File patterns to ignore anywhere they appear; these support rudimentary globbing +ignore = [".stignore", ".stfolder", ".git*"] + +## ############################################################################# +# The system section handles defining your system format +## ############################################################################# +[system] +## ############################################################################# +# The system.jdex section defines how your JDex is stored on the disk +## ############################################################################# +[system.jdex] +# The path to begin JDex structure within; if you have a flat structure, this +# can just be whatever folder it's in. +path = "~/Obsidian/00-09 System/00 System Management/00.00 System Index" +# File patterns to ignore just in the JDex +ignore = ["Attachments"] + +# `notes` specifies files on the disk (generally they are going to be Markdown +# notes, but they don't have to be) that make up the JDex. +# +# Note that notes are always matched sequentially as they are defined in the +# config file, meaning you can define a more narrow case first and then a more +# broad case later, as is done with Area notes before Category notes here (as +# Area notes would match the Category format). +[[system.jdex.notes]] +# The name to refer to the note type as in errors/JSON output +name = "JDex Area Note" +# The expected format of the note +format = "/#A/0.00 /*Name/.md" + +# `ids` specifies what IDs a note creates, and what their full "name" is. Note +# that a note *can* allow more than one, e.g. 10.00 allows Area 10-19, Category +# 10, and ID 10.00 to exist. Note that you can use bound segments in this. +[[system.jdex.notes.ids]] +id = "/=A/0-/=A/9" +entry = "/=A/0-/=A/9 /=Name/" + +[[system.jdex.notes.ids]] +id = "/=A/0" +entry = "/=A/0 management for /=Name/" + +[[system.jdex.notes.ids]] +id = "/=A/0.00" +entry = "/=A/0.00 index for /=Name/" + +[[system.jdex.notes]] +name = "JDex Category Note" +format = "/#A//#C/.00 /*Name/.md" + +[[system.jdex.notes.ids]] +id = "/=A//=C/" +entry = "/=A//=C/ /=Name/" + +[[system.jdex.notes.ids]] +id = "/=A//=C/.00" +entry = "/=A//=C/.00 JDex for /=Name/" + +[[system.jdex.notes]] +name = "JDex Id Note" +format = "/#A//#C/./##ID/ /*Name/.md" + +[[system.jdex.notes.ids]] +id = "/=A//=C/./=ID/" +entry = "/=A//=C/./=ID/ /=Name/" + +[[system.jdex.notes]] +name = "JDex Work Package Id Note" +format = "W/####WPID/~/##AC/./##ID/ /*WPName/.md" + +[[system.jdex.notes.ids]] +id = "W/=WPID/" +entry = "W/=WPID/~/=AC/./=ID/ /=WPName/" + +## ############################################################################# +# system.default defines the *default* structure used by any roots to check +## ############################################################################# +[system.default] +# At any level, we can define ".children" to specify one or more formats of +# folders to be allowed within the current level; here, we are defining the +# topmost level. +# +# Note that children are always matched sequentially as they are defined in the +# config file, meaning you can define a more narrow case first and then a more +# broad case later. +[[system.default.children]] +# The name to refer to the folder type as in errors/JSON output +name = "Area" +# The expected format of the folder +format = "/#A/0-/=A/9 /*Area/" +# The ID of this entry; this will be checked for uniqueness and matched to the +# JDex. Note that you can use bound segments in this. +id = "/=A/0-/=A/9" + +# Here we are defining the child folders of the top-level area folders +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" # Note that we're using bound segments from the parent area +id = "/=A//=C/" + +# Here, we define a folder without any children; that tells jdlint that it +# should be empty. This is useful for Headers and Inboxes. +[[system.default.children.children.children]] +name = "Header" +format = "/=A//=C/./#I/0 β–  /*Header/" +id = "/=A//=C/./=I/0" + +[[system.default.children.children.children]] +name = "Inbox" +format = "00.01 Inbox for the /*System/ System πŸ“₯" +id = "00.01" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A/0.01 Inbox for area /=A/0-/=A/9 πŸ“₯" +id = "/=A/0.01" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A//=C/.01 Inbox for category /=A//=C/" +id = "/=A//=C/.01" + +# Here, we're disallowing inboxes (AC.01) that don't match the exact naming scheme above. +[[system.default.children.children.children]] +name = "Invalid Inbox" +format = "/=A//=C/.01 /*Inbox/" +id = "/=A//=C/.01" +forbidden = true # This just causes jdlint to fail anything that matches the format + +# Here, we're defining our terminal ID folders +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true # This allows us to have a file as a terminal folder; you might like this for notes, for example +allow_arbitrary_contents = true # This tells jdlint to tolerate absolutely anything in this folder + +# Defining a top-level folder for work packages +[[system.default.children]] +name = "Work Packages Area" +format = "W0000-W9999 /*Area/" +id = "W0000-W9999" + +# And terminal work package folders +[[system.default.children.children]] +name = "Work Package" +format = "W/####WPID/~/##AC/./##ID/ /*WPName/" +id = "W/=WPID/" +allow_arbitrary_contents = true + +## ############################################################################# +# system.roots define folders that should be organized according to your JD +# system; for example, you might have ~/Documents as one root and ~/Dropbox +# as another. +## ############################################################################# +[[system.roots]] +# The name to refer to the root as in errors/JSON output +name = "Documents" +# The path to the files +path = "~/Documents" +# Any ignore patterns that apply only to that set of files +ignore = [".trash"] + +[[system.roots]] +name = "Dropbox" +path = "~/Dropbox" +ignore = [] + +# You can override the default structure for just *one* location if you want, +# e.g. if you only wanted work packages and nothing else in your dropbox +[[system.roots.children]] +name = "Work Packages Area" +format = "W0000-W9999 /*Area/" +id = "W0000-W9999" +# This allows us to not need a JDex entry for something +no_jdex_entry = true + +[[system.roots.children.children]] +name = "Work Package" +format = "W/####WPID/~/##AC/./##ID/ /*WPName/" +# You can override an expected JDex entry with `jdex_entry` +jdex_entry = "Something wildly arbitrary for /=WPID/; you should change this" +id = "W/=WPID/" +allow_arbitrary_contents = true diff --git a/configs/fully_nested_jdex.toml b/configs/fully_nested_jdex.toml new file mode 100644 index 0000000..819f7b7 --- /dev/null +++ b/configs/fully_nested_jdex.toml @@ -0,0 +1,215 @@ +## ############################################################################# +# The linter section handles global settings +## ############################################################################# +[linter] +# Globally disable one or more rules by name, e.g. with `disable_rules = ["ID_DIFFERENT_FROM_JDEX"]` +disable_rules = [] +# Output machine-readable JSON instead of human-readable terminal output +json_output = false +# File patterns to ignore anywhere they appear; these support rudimentary globbing +ignore = [".stignore", ".stfolder", ".git*"] + +## ############################################################################# +# The system section handles defining your system format +## ############################################################################# +[system] +## ############################################################################# +# The system.jdex section defines how your JDex is stored on the disk +## ############################################################################# +[system.jdex] +# The path to begin JDex structure within. +path = "~/Obsidian" +# File patterns to ignore just in the JDex +ignore = ["Attachments"] + +# `children` specifies folders on the disk that are expected in the JDex. These +# may then define `notes`, which specify files on the disk (generally they are +# going to be Markdown notes, but they don't have to be) that make up the JDex. +[[system.jdex.children]] +# The name to refer to the note type as in errors/JSON output +name = "JDex Area Folder" +# The expected format of the note +format = "/#A/0-/=A/9 /*Area/" + +[[system.jdex.children.children]] +name = "JDex Category Folder" +format = "/=A//#C/ /*Category/" + +[[system.jdex.children.children.children]] +name = "JDex ID Folder" +format = "/=A//=C/./##ID/ /*IDName/" +# Since ID notes are alongside content notes, we allow arbitrary content to exist here +allow_arbitrary_contents = true + +# Note that notes are always matched sequentially as they are defined in the +# config file, meaning you can define a more narrow case first and then a more +# broad case later, as is done with Area notes before Category notes here (as +# Area notes would match the Category format). +[[system.jdex.children.children.children.notes]] +name = "JDex Area Note" +format = "/=A/0.00 /*Name/.md" + +# `ids` specifies what IDs a note creates, and what their full "name" is. Note +# that a note *can* allow more than one, e.g. 10.00 allows Area 10-19, Category +# 10, and ID 10.00 to exist. Note that you can use bound segments in this. +[[system.jdex.children.children.children.notes.ids]] +id = "/=A/0-/=A/9" +entry = "/=A/0-/=A/9 /=Area/" + +[[system.jdex.children.children.children.notes.ids]] +id = "/=A/0" +entry = "/=A/0 /=Category/" + +[[system.jdex.children.children.children.notes.ids]] +id = "/=A/0.00" +entry = "/=A/0.00 /=Name/" + +[[system.jdex.children.children.children.notes]] +name = "JDex Category Note" +format = "/=A//=C/.00 /*Name/.md" + +[[system.jdex.children.children.children.notes.ids]] +id = "/=A//=C/" +entry = "/=A//=C/ /=Category/" + +[[system.jdex.children.children.children.notes.ids]] +id = "/=A//=C/.00" +entry = "/=A//=C/.00 /=Name/" + +[[system.jdex.children.children.children.notes]] +name = "JDex Id Note" +format = "/=A//=C/./=ID/ /*Name/.md" + +[[system.jdex.children.children.children.notes.ids]] +id = "/=A//=C/./=ID/" +entry = "/=A//=C/./=ID/ /=Name/" + +# Defining a top-level folder for work packages +[[system.jdex.children]] +name = "JDex Work Packages Folder" +format = "W0000-W9999 /*Area/" + +[[system.jdex.children.children]] +name = "JDex Work Package Id Folder" +format = "W/####WPID/~/##AC/./##ID/ /*WPName/" +# Since ID notes are alongside content notes, we allow arbitrary content to exist here +allow_arbitrary_contents = true + +[[system.jdex.children.children.notes]] +name = "JDex Work Package Id Note" +format = "W/=WPID/~/=AC/./=ID/ /=WPName/.md" + +[[system.jdex.children.children.notes.ids]] +id = "W/=WPID/" +entry = "W/=WPID/~/=AC/./=ID/ /=WPName/" + +## ############################################################################# +# system.default defines the *default* structure used by any roots to check +## ############################################################################# +[system.default] +# At any level, we can define ".children" to specify one or more formats of +# folders to be allowed within the current level; here, we are defining the +# topmost level. +# +# Note that children are always matched sequentially as they are defined in the +# config file, meaning you can define a more narrow case first and then a more +# broad case later. +[[system.default.children]] +# The name to refer to the folder type as in errors/JSON output +name = "Area" +# The expected format of the folder +format = "/#A/0-/=A/9 /*Area/" +# The ID of this entry; this will be checked for uniqueness and matched to the +# JDex. Note that you can use bound segments in this. +id = "/=A/0-/=A/9" + +# Here we are defining the child folders of the top-level area folders +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" # Note that we're using bound segments from the parent area +id = "/=A//=C/" + +# Here, we define a folder without any children; that tells jdlint that it +# should be empty. This is useful for Headers and Inboxes. +[[system.default.children.children.children]] +name = "Header" +format = "/=A//=C/./#I/0 β–  /*Header/" +id = "/=A//=C/./=I/0" + +[[system.default.children.children.children]] +name = "Inbox" +format = "00.01 Inbox for the /*System/ System πŸ“₯" +id = "00.01" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A/0.01 Inbox for area /=A/0-/=A/9 πŸ“₯" +id = "/=A/0.01" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A//=C/.01 Inbox for category /=A//=C/" +id = "/=A//=C/.01" + +# Here, we're disallowing inboxes (AC.01) that don't match the exact naming scheme above. +[[system.default.children.children.children]] +name = "Invalid Inbox" +format = "/=A//=C/.01 /*Inbox/" +id = "/=A//=C/.01" +forbidden = true # This just causes jdlint to fail anything that matches the format + +# Here, we're defining our terminal ID folders +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true # This allows us to have a file as a terminal folder; you might like this for notes, for example +allow_arbitrary_contents = true # This tells jdlint to tolerate absolutely anything in this folder + +# Defining a top-level folder for work packages +[[system.default.children]] +name = "Work Packages Area" +format = "W0000-W9999 /*Area/" +id = "W0000-W9999" + +# And terminal work package folders +[[system.default.children.children]] +name = "Work Package" +format = "W/####WPID/~/##AC/./##ID/ /*WPName/" +id = "W/=WPID/" +allow_arbitrary_contents = true + +## ############################################################################# +# system.roots define folders that should be organized according to your JD +# system; for example, you might have ~/Documents as one root and ~/Dropbox +# as another. +## ############################################################################# +[[system.roots]] +# The name to refer to the root as in errors/JSON output +name = "Documents" +# The path to the files +path = "~/Documents" +# Any ignore patterns that apply only to that set of files +ignore = [".trash"] + +[[system.roots]] +name = "Dropbox" +path = "~/Dropbox" +ignore = [] + +# You can override the default structure for just *one* location if you want, +# e.g. if you only wanted work packages and nothing else in your dropbox +[[system.roots.children]] +name = "Work Packages Area" +format = "W0000-W9999 /*Area/" +id = "W0000-W9999" +# This allows us to not need a JDex entry for something +no_jdex_entry = true + +[[system.roots.children.children]] +name = "Work Package" +format = "W/####WPID/~/##AC/./##ID/ /*WPName/" +# You can override an expected JDex entry with `jdex_entry` +jdex_entry = "Something wildly arbitrary for /=WPID/; you should change this" +id = "W/=WPID/" +allow_arbitrary_contents = true diff --git a/configs/json_jdex.toml b/configs/json_jdex.toml new file mode 100644 index 0000000..a2b4519 --- /dev/null +++ b/configs/json_jdex.toml @@ -0,0 +1,110 @@ +## ############################################################################# +# The linter section handles global settings +## ############################################################################# +[linter] +# Globally disable one or more rules by name, e.g. with `disable_rules = ["ID_DIFFERENT_FROM_JDEX"]` +disable_rules = [] +# Output machine-readable JSON instead of human-readable terminal output +json_output = false +# File patterns to ignore anywhere they appear; these support rudimentary globbing +ignore = [".stignore", ".stfolder", ".git*"] + +## ############################################################################# +# The system section handles defining your system format +## ############################################################################# +[system] +## ############################################################################# +# The system.jdex section defines how your JDex is stored on the disk +## ############################################################################# +[system.jdex] +# The path that the JSON file is located at. jdlint will automatically detect +# that it is a file, not a folder. +path = "~/jdex.jd.json" + +# Only one configuration option is available for single-file JDexes, which is a +# format for how to create entries out of the data in the file. Only two bound +# segments will be available, `/=id/` and `/=title`. You may use this to e.g. +# replace the space that normally comes between an ID and its title with an +# underscore, should you do that. +entry = "/=id/ /=title/" + +## ############################################################################# +# system.default defines the *default* structure used by any roots to check +## ############################################################################# +[system.default] +# At any level, we can define ".children" to specify one or more formats of +# folders to be allowed within the current level; here, we are defining the +# topmost level. +# +# Note that children are always matched sequentially as they are defined in the +# config file, meaning you can define a more narrow case first and then a more +# broad case later. +[[system.default.children]] +# The name to refer to the folder type as in errors/JSON output +name = "Area" +# The expected format of the folder +format = "/#A/0-/=A/9 /*Area/" +# The ID of this entry; this will be checked for uniqueness and matched to the +# JDex. Note that you can use bound segments in this. +id = "/=A/0-/=A/9" + +# Here we are defining the child folders of the top-level area folders +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" # Note that we're using bound segments from the parent area +id = "/=A//=C/" + +# Here, we define a folder without any children; that tells jdlint that it +# should be empty. This is useful for Headers and Inboxes. +[[system.default.children.children.children]] +name = "Header" +format = "/=A//=C/./#I/0 β–  /*Header/" +id = "/=A//=C/./=I/0" + +[[system.default.children.children.children]] +name = "Inbox" +format = "00.01 Inbox for the /*System/ System πŸ“₯" +id = "00.01" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A/0.01 Inbox for area /=A/0-/=A/9 πŸ“₯" +id = "/=A/0.01" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A//=C/.01 Inbox for category /=A//=C/" +id = "/=A//=C/.01" + +# Here, we're disallowing inboxes (AC.01) that don't match the exact naming scheme above. +[[system.default.children.children.children]] +name = "Invalid Inbox" +format = "/=A//=C/.01 /*Inbox/" +id = "/=A//=C/.01" +forbidden = true # This just causes jdlint to fail anything that matches the format + +# Here, we're defining our terminal ID folders +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true # This allows us to have a file as a terminal folder; you might like this for notes, for example +allow_arbitrary_contents = true # This tells jdlint to tolerate absolutely anything in this folder + +## ############################################################################# +# system.roots define folders that should be organized according to your JD +# system; for example, you might have ~/Documents as one root and ~/Dropbox +# as another. +## ############################################################################# +[[system.roots]] +# The name to refer to the root as in errors/JSON output +name = "Documents" +# The path to the files +path = "~/Documents" +# Any ignore patterns that apply only to that set of files +ignore = [".trash"] + +[[system.roots]] +name = "Dropbox" +path = "~/Dropbox" +ignore = [] diff --git a/configs/no_jdex.toml b/configs/no_jdex.toml new file mode 100644 index 0000000..decbf8c --- /dev/null +++ b/configs/no_jdex.toml @@ -0,0 +1,125 @@ +## ############################################################################# +# The linter section handles global settings +## ############################################################################# +[linter] +# Globally disable one or more rules by name, e.g. with `disable_rules = ["DUPLICATE_ID"]` +disable_rules = [] +# Output machine-readable JSON instead of human-readable terminal output +json_output = false +# File patterns to ignore anywhere they appear; these support rudimentary globbing +ignore = [".stignore", ".stfolder", ".git*"] + +## ############################################################################# +# The system section handles defining your system format +## ############################################################################# +[system] +## ############################################################################# +# system.default defines the *default* structure used by any roots to check +## ############################################################################# +[system.default] +# At any level, we can define ".children" to specify one or more formats of +# folders to be allowed within the current level; here, we are defining the +# topmost level. +# +# Note that children are always matched sequentially as they are defined in the +# config file, meaning you can define a more narrow case first and then a more +# broad case later. +[[system.default.children]] +# The name to refer to the folder type as in errors/JSON output +name = "Area" +# The expected format of the folder +format = "/#A/0-/=A/9 /*Area/" +# The ID of this entry; this will be checked for uniqueness and matched to the +# JDex. Note that you can use bound segments in this. +id = "/=A/0-/=A/9" + +# Here we are defining the child folders of the top-level area folders +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" # Note that we're using bound segments from the parent area +id = "/=A//=C/" + +# Here, we define a folder without any children; that tells jdlint that it +# should be empty. This is useful for Headers and Inboxes. +[[system.default.children.children.children]] +name = "Header" +format = "/=A//=C/./#I/0 β–  /*Header/" +id = "/=A//=C/./=I/0" + +[[system.default.children.children.children]] +name = "Inbox" +format = "00.01 Inbox for the /*System/ System πŸ“₯" +id = "00.01" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A/0.01 Inbox for area /=A/0-/=A/9 πŸ“₯" +id = "/=A/0.01" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A//=C/.01 Inbox for category /=A//=C/" +id = "/=A//=C/.01" + +# Here, we're disallowing inboxes (AC.01) that don't match the exact naming scheme above. +[[system.default.children.children.children]] +name = "Invalid Inbox" +format = "/=A//=C/.01 /*Inbox/" +id = "/=A//=C/.01" +forbidden = true # This just causes jdlint to fail anything that matches the format + +# Here, we're defining our terminal ID folders +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true # This allows us to have a file as a terminal folder; you might like this for notes, for example +allow_arbitrary_contents = true # This tells jdlint to tolerate absolutely anything in this folder + +# Defining a top-level folder for work packages +[[system.default.children]] +name = "Work Packages Area" +format = "W0000-W9999 /*Area/" +id = "W0000-W9999" + +# And terminal work package folders +[[system.default.children.children]] +name = "Work Package" +format = "W/####WPID/~/##AC/./##ID/ /*WPName/" +id = "W/=WPID/" +allow_arbitrary_contents = true + +## ############################################################################# +# system.roots define folders that should be organized according to your JD +# system; for example, you might have ~/Documents as one root and ~/Dropbox +# as another. +## ############################################################################# +[[system.roots]] +# The name to refer to the root as in errors/JSON output +name = "Documents" +# The path to the files +path = "~/Documents" +# Any ignore patterns that apply only to that set of files +ignore = [".trash"] + +[[system.roots]] +name = "Dropbox" +path = "~/Dropbox" +ignore = [] + +# You can override the default structure for just *one* location if you want, +# e.g. if you only wanted work packages and nothing else in your dropbox +[[system.roots.children]] +name = "Work Packages Area" +format = "W0000-W9999 /*Area/" +id = "W0000-W9999" +# This allows us to not need a JDex entry for something +no_jdex_entry = true + +[[system.roots.children.children]] +name = "Work Package" +format = "W/####WPID/~/##AC/./##ID/ /*WPName/" +# You can override an expected JDex entry with `jdex_entry` +jdex_entry = "Something wildly arbitrary for /=WPID/; you should change this" +id = "W/=WPID/" +allow_arbitrary_contents = true diff --git a/configs/partially_nested_jdex.toml b/configs/partially_nested_jdex.toml new file mode 100644 index 0000000..2575e24 --- /dev/null +++ b/configs/partially_nested_jdex.toml @@ -0,0 +1,203 @@ +## ############################################################################# +# The linter section handles global settings +## ############################################################################# +[linter] +# Globally disable one or more rules by name, e.g. with `disable_rules = ["ID_DIFFERENT_FROM_JDEX"]` +disable_rules = [] +# Output machine-readable JSON instead of human-readable terminal output +json_output = false +# File patterns to ignore anywhere they appear; these support rudimentary globbing +ignore = [".stignore", ".stfolder", ".git*"] + +## ############################################################################# +# The system section handles defining your system format +## ############################################################################# +[system] +## ############################################################################# +# The system.jdex section defines how your JDex is stored on the disk +## ############################################################################# +[system.jdex] +# The path to begin JDex structure within. +path = "~/Obsidian/00-09 System/00 System Management/00.00 System Index" +# File patterns to ignore just in the JDex +ignore = [".obsidian"] + +# `children` specifies folders on the disk that are expected in the JDex. These +# may then define `notes`, which specify files on the disk (generally they are +# going to be Markdown notes, but they don't have to be) that make up the JDex. +[[system.jdex.children]] +# The name to refer to the note type as in errors/JSON output +name = "JDex Area Folder" +# The expected format of the note +format = "/#A/0-/=A/9 /*Area/" + +[[system.jdex.children.children]] +name = "JDex Category Folder" +format = "/=A//#C/ /*Category/" + +# Note that notes are always matched sequentially as they are defined in the +# config file, meaning you can define a more narrow case first and then a more +# broad case later, as is done with Area notes before Category notes here (as +# Area notes would match the Category format). +[[system.jdex.children.children.notes]] +name = "JDex Area Note" +format = "/=A/0.00 /*Name/.md" + +# `ids` specifies what IDs a note creates, and what their full "name" is. Note +# that a note *can* allow more than one, e.g. 10.00 allows Area 10-19, Category +# 10, and ID 10.00 to exist. Note that you can use bound segments in this. +[[system.jdex.children.children.notes.ids]] +id = "/=A/0-/=A/9" +entry = "/=A/0-/=A/9 /=Area/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/0" +entry = "/=A/0 /=Category/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/0.00" +entry = "/=A/0.00 /=Name/" + +[[system.jdex.children.children.notes]] +name = "JDex Category Note" +format = "/=A//=C/.00 /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/" +entry = "/=A//=C/ /=Category/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/.00" +entry = "/=A//=C/.00 /=Name/" + +[[system.jdex.children.children.notes]] +name = "JDex Id Note" +format = "/=A//=C/./##ID/ /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/./=ID/" +entry = "/=A//=C/./=ID/ /=Name/" + +# Defining a top-level folder for work packages +[[system.jdex.children]] +name = "JDex Work Packages Folder" +format = "W0000-W9999 /*Area/" + +[[system.jdex.children.notes]] +name = "JDex Work Package Id Note" +format = "W/####WPID/~/##AC/./##ID/ /*WPName/.md" + +[[system.jdex.children.notes.ids]] +id = "W/=WPID/" +entry = "W/=WPID/~/=AC/./=ID/ /=WPName/" + +## ############################################################################# +# system.default defines the *default* structure used by any roots to check +## ############################################################################# +[system.default] +# At any level, we can define ".children" to specify one or more formats of +# folders to be allowed within the current level; here, we are defining the +# topmost level. +# +# Note that children are always matched sequentially as they are defined in the +# config file, meaning you can define a more narrow case first and then a more +# broad case later. +[[system.default.children]] +# The name to refer to the folder type as in errors/JSON output +name = "Area" +# The expected format of the folder +format = "/#A/0-/=A/9 /*Area/" +# The ID of this entry; this will be checked for uniqueness and matched to the +# JDex. Note that you can use bound segments in this. +id = "/=A/0-/=A/9" + +# Here we are defining the child folders of the top-level area folders +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" # Note that we're using bound segments from the parent area +id = "/=A//=C/" + +# Here, we define a folder without any children; that tells jdlint that it +# should be empty. This is useful for Headers and Inboxes. +[[system.default.children.children.children]] +name = "Header" +format = "/=A//=C/./#I/0 β–  /*Header/" +id = "/=A//=C/./=I/0" + +[[system.default.children.children.children]] +name = "Inbox" +format = "00.01 Inbox for the /*System/ System πŸ“₯" +id = "00.01" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A/0.01 Inbox for area /=A/0-/=A/9 πŸ“₯" +id = "/=A/0.01" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A//=C/.01 Inbox for category /=A//=C/" +id = "/=A//=C/.01" + +# Here, we're disallowing inboxes (AC.01) that don't match the exact naming scheme above. +[[system.default.children.children.children]] +name = "Invalid Inbox" +format = "/=A//=C/.01 /*Inbox/" +id = "/=A//=C/.01" +forbidden = true # This just causes jdlint to fail anything that matches the format + +# Here, we're defining our terminal ID folders +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true # This allows us to have a file as a terminal folder; you might like this for notes, for example +allow_arbitrary_contents = true # This tells jdlint to tolerate absolutely anything in this folder + +# Defining a top-level folder for work packages +[[system.default.children]] +name = "Work Packages Area" +format = "W0000-W9999 /*Area/" +id = "W0000-W9999" + +# And terminal work package folders +[[system.default.children.children]] +name = "Work Package" +format = "W/####WPID/~/##AC/./##ID/ /*WPName/" +id = "W/=WPID/" +allow_arbitrary_contents = true + +## ############################################################################# +# system.roots define folders that should be organized according to your JD +# system; for example, you might have ~/Documents as one root and ~/Dropbox +# as another. +## ############################################################################# +[[system.roots]] +# The name to refer to the root as in errors/JSON output +name = "Documents" +# The path to the files +path = "~/Documents" +# Any ignore patterns that apply only to that set of files +ignore = [".trash"] + +[[system.roots]] +name = "Dropbox" +path = "~/Dropbox" +ignore = [] + +# You can override the default structure for just *one* location if you want, +# e.g. if you only wanted work packages and nothing else in your dropbox +[[system.roots.children]] +name = "Work Packages Area" +format = "W0000-W9999 /*Area/" +id = "W0000-W9999" +# This allows us to not need a JDex entry for something +no_jdex_entry = true + +[[system.roots.children.children]] +name = "Work Package" +format = "W/####WPID/~/##AC/./##ID/ /*WPName/" +# You can override an expected JDex entry with `jdex_entry` +jdex_entry = "Something wildly arbitrary for /=WPID/; you should change this" +id = "W/=WPID/" +allow_arbitrary_contents = true diff --git a/configs/plaintext_jdex.toml b/configs/plaintext_jdex.toml new file mode 100644 index 0000000..3f345c2 --- /dev/null +++ b/configs/plaintext_jdex.toml @@ -0,0 +1,110 @@ +## ############################################################################# +# The linter section handles global settings +## ############################################################################# +[linter] +# Globally disable one or more rules by name, e.g. with `disable_rules = ["ID_DIFFERENT_FROM_JDEX"]` +disable_rules = [] +# Output machine-readable JSON instead of human-readable terminal output +json_output = false +# File patterns to ignore anywhere they appear; these support rudimentary globbing +ignore = [".stignore", ".stfolder", ".git*"] + +## ############################################################################# +# The system section handles defining your system format +## ############################################################################# +[system] +## ############################################################################# +# The system.jdex section defines how your JDex is stored on the disk +## ############################################################################# +[system.jdex] +# The path that the JSON file is located at. jdlint will automatically detect +# that it is a file, not a folder. +path = "~/jdex.txt" + +# Only one configuration option is available for single-file JDexes, which is a +# format for how to create entries out of the data in the file. Only two bound +# segments will be available, `/=id/` and `/=title`. You may use this to e.g. +# replace the space that normally comes between an ID and its title with an +# underscore, should you do that. +entry = "/=id/ /=title/" + +## ############################################################################# +# system.default defines the *default* structure used by any roots to check +## ############################################################################# +[system.default] +# At any level, we can define ".children" to specify one or more formats of +# folders to be allowed within the current level; here, we are defining the +# topmost level. +# +# Note that children are always matched sequentially as they are defined in the +# config file, meaning you can define a more narrow case first and then a more +# broad case later. +[[system.default.children]] +# The name to refer to the folder type as in errors/JSON output +name = "Area" +# The expected format of the folder +format = "/#A/0-/=A/9 /*Area/" +# The ID of this entry; this will be checked for uniqueness and matched to the +# JDex. Note that you can use bound segments in this. +id = "/=A/0-/=A/9" + +# Here we are defining the child folders of the top-level area folders +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" # Note that we're using bound segments from the parent area +id = "/=A//=C/" + +# Here, we define a folder without any children; that tells jdlint that it +# should be empty. This is useful for Headers and Inboxes. +[[system.default.children.children.children]] +name = "Header" +format = "/=A//=C/./#I/0 β–  /*Header/" +id = "/=A//=C/./=I/0" + +[[system.default.children.children.children]] +name = "Inbox" +format = "00.01 Inbox for the /*System/ System πŸ“₯" +id = "00.01" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A/0.01 Inbox for area /=A/0-/=A/9 πŸ“₯" +id = "/=A/0.01" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A//=C/.01 Inbox for category /=A//=C/" +id = "/=A//=C/.01" + +# Here, we're disallowing inboxes (AC.01) that don't match the exact naming scheme above. +[[system.default.children.children.children]] +name = "Invalid Inbox" +format = "/=A//=C/.01 /*Inbox/" +id = "/=A//=C/.01" +forbidden = true # This just causes jdlint to fail anything that matches the format + +# Here, we're defining our terminal ID folders +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true # This allows us to have a file as a terminal folder; you might like this for notes, for example +allow_arbitrary_contents = true # This tells jdlint to tolerate absolutely anything in this folder + +## ############################################################################# +# system.roots define folders that should be organized according to your JD +# system; for example, you might have ~/Documents as one root and ~/Dropbox +# as another. +## ############################################################################# +[[system.roots]] +# The name to refer to the root as in errors/JSON output +name = "Documents" +# The path to the files +path = "~/Documents" +# Any ignore patterns that apply only to that set of files +ignore = [".trash"] + +[[system.roots]] +name = "Dropbox" +path = "~/Dropbox" +ignore = [] diff --git a/configs/siriusstarr.toml b/configs/siriusstarr.toml new file mode 100644 index 0000000..c423b69 --- /dev/null +++ b/configs/siriusstarr.toml @@ -0,0 +1,319 @@ +## ############################################################################# +# The linter section handles global settings +## ############################################################################# +[linter] +# Globally disable one or more rules by name, e.g. with `disable_rules = ["ID_DIFFERENT_FROM_JDEX"]` +disable_rules = [] +# Output machine-readable JSON instead of human-readable terminal output +json_output = false +# File patterns to ignore anywhere they appear; these support rudimentary globbing +ignore = [".stignore", ".stfolder", ".git*"] + +## ############################################################################# +# The system section handles defining your system format +## ############################################################################# +[system] +## ############################################################################# +# The system.jdex section defines how your JDex is stored on the disk +## ############################################################################# +[system.jdex] +# The path to begin JDex structure within. +path = "~/Knowledge" +# File patterns to ignore just in the JDex +ignore = [".obsidian", ".trash"] + +# `children` specifies folders on the disk that are expected in the JDex. These +# may then define `notes`, which specify files on the disk (generally they are +# going to be Markdown notes, but they don't have to be) that make up the JDex. +[[system.jdex.children]] +# The name to refer to the note type as in errors/JSON output +name = "JDex Branch Folder" +# The expected format of the note +format = "B/##BB/ /*Branch/" + +[[system.jdex.children.children]] +name = "JDex Branch Index Folder" +format = "C/=BB/.00 πŸ“‡ Index" + +[[system.jdex.children.children.notes]] +name = "JDex Branch Note" +format = "B/=BB/ /=Branch/.md" + +# `ids` specifies what IDs a note creates, and what their full "name" is. Note +# that a note *can* allow more than one, e.g. 10.00 allows Area 10-19, Category +# 10, and ID 10.00 to exist. Note that you can use bound segments in this. +[[system.jdex.children.children.notes.ids]] +id = "B/=BB/" +entry = "B/=BB/ /=Branch/" + +[[system.jdex.children.children.notes]] +name = "JDex Cache Note" +format = "C/=BB/./##ID/ /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "C/=BB/./=ID/" +entry = "C/=BB/./=ID/ /=Name/" + +[[system.jdex.children.children.notes]] +name = "Nest To Cache Note" +format = "N/=BB/./####ID/~C/=BB/./##RelID/ /*Nest/.md" + +[[system.jdex.children.children.notes.ids]] +id = "N/=BB/./=ID/" +entry = "N/=BB/./=ID/~C/=BB/./=RelID/ /=Nest/" + +[[system.jdex.children.children.notes]] +name = "Nest To Nest Note" +format = "N/=BB/./####ID/~N/=BB/./####RelID/ /*Nest/.md" + +[[system.jdex.children.children.notes.ids]] +id = "N/=BB/./=ID/" +entry = "N/=BB/./=ID/~N/=BB/./=RelID/ /=Nest/" + +[[system.jdex.children.children.children]] +name = "Attachments Folder" +format = "Attachments" +allow_arbitrary_contents = true + +[[system.jdex.children.children]] +name = "JDex Cache Non-Index Folder" +format = "C/=BB/./##ID/ /*Cache/" +allow_arbitrary_contents = true + +[[system.jdex.children.children]] +name = "JDex Nest Non-Index Folder" +format = "N/=BB/./####ID/~/*Nest/" +allow_arbitrary_contents = true + +[[system.roots]] +name = "Knowledge" +path = "~/Knowledge" +ignore = [".git", ".gitignore", ".obsidian", ".trash"] + +[[system.roots.children]] +name = "Trunk" +format = "B/#T/0 /*Trunk/ ⬇️" +id = "B/=T/0" + +[[system.roots.children.children]] +name = "Trunk Index" +format = "C/=T/0.00 πŸ“‡ Index" +id = "C/=T/0.00" +allow_arbitrary_contents = true + +[[system.roots.children]] +name = "Branch" +format = "B/##BB/ /*Branch/" +id = "B/=BB/" + +[[system.roots.children.children]] +name = "Index" +format = "C/=BB/.00 πŸ“‡ Index" +id = "C/=BB/.00" +allow_arbitrary_contents = true + +[[system.roots.children.children]] +name = "Header" +format = "C/=BB/./#H/0 /*Header/ ⬇️" +id = "C/=BB/./=H/0" + +# Disallow headers that don't match this format +[[system.roots.children.children]] +name = "Invalid Header Or Index" +format = "C/=BB/./#H/0 /*Header/" +id = "C/=BB/./=H/0" +forbidden = true + +[[system.roots.children.children]] +name = "Inbox" +format = "C/=BB/.01 πŸ“₯️ Inbox" +id = "C/=BB/.01" + +# Disallow inboxes that don't match this format +[[system.roots.children.children]] +name = "Invalid Inbox" +format = "C/=BB/.01 /*Inbox/" +id = "C/=BB/.01" +forbidden = true + +[[system.roots.children.children]] +name = "Cache" +format = "C/=BB/./##ID/ /*Cache/" + +allow_arbitrary_contents = true +id = "C/=BB/./=ID/" + +[[system.roots.children.children]] +name = "Nest" +format = "N/=BB/./####ID/~/*Nest/" +id = "N/=BB/./=ID/" +allow_arbitrary_contents = true + +[[system.roots]] +name = "Caches" +path = "~/Caches" + +[[system.roots]] +name = "Knowledge" +path = "~/Knowledge" +ignore = [".obsidian", ".trash"] + +[[system.roots]] +name = "Nests" +path = "~/Nests" + +[[system.roots.children]] +name = "Nest" +format = "N/##BB/./####ID/~/*Nest/" +id = "N/=BB/./=ID/" +allow_arbitrary_contents = true + +[[system.default.children]] +name = "Trunk" +format = "B/#T/0 /*Trunk/ ⬇️" +id = "B/=T/0" + +[[system.default.children]] +name = "Branch" +format = "B/##BB/ /*Branch/" +id = "B/=BB/" + +## ############################################################################# +# Here, we're defining standard zeros so that they are all named consistently +## ############################################################################# +[[system.default.children.children]] +name = "Index" +format = "C/=BB/.00 πŸ“‡ Index" +id = "C/=BB/.00" +allow_arbitrary_contents = true + +[[system.default.children.children]] +name = "Invalid Index" +format = "C/=BB/.00/*Index/" +id = "C/=BB/.00" +forbidden = true + +[[system.default.children.children]] +name = "Inbox" +format = "C/=BB/.01 πŸ“₯️ Inbox" +id = "C/=BB/.01" + +[[system.default.children.children]] +name = "Invalid Inbox" +format = "C/=BB/.01/*Inbox/" +id = "C/=BB/.01" +forbidden = true + +[[system.default.children.children]] +name = "Control" +format = "C/=BB/.02 βœ… Control" +id = "C/=BB/.02" +allow_arbitrary_contents = true + +[[system.default.children.children]] +name = "Invalid Control" +format = "C/=BB/.02/*Control/" +id = "C/=BB/.02" +forbidden = true + +[[system.default.children.children]] +name = "Templates" +format = "C/=BB/.03 πŸ“‘ Templates & Standards" +id = "C/=BB/.03" +allow_arbitrary_contents = true + +[[system.default.children.children]] +name = "Invalid Templates" +format = "C/=BB/.03/*Templates/" +id = "C/=BB/.03" +forbidden = true + +[[system.default.children.children]] +name = "Links" +format = "C/=BB/.04 πŸ”— Sources, Resources, & Links" +id = "C/=BB/.04" +allow_arbitrary_contents = true + +[[system.default.children.children]] +name = "Invalid Links" +format = "C/=BB/.04/*Links/" +id = "C/=BB/.04" +forbidden = true + +[[system.default.children.children]] +name = "Ideas" +format = "C/=BB/.05 πŸ’­ Inspiration, Ideas, & Percolation" +id = "C/=BB/.05" +allow_arbitrary_contents = true + +[[system.default.children.children]] +name = "Invalid Ideas" +format = "C/=BB/.05/*Ideas/" +id = "C/=BB/.05" +forbidden = true + +[[system.default.children.children]] +name = "Tags" +format = "C/=BB/.06 🏷️ Topics & Tags" +id = "C/=BB/.06" +allow_arbitrary_contents = true + +[[system.default.children.children]] +name = "Invalid Tags" +format = "C/=BB/.06/*Tags/" +id = "C/=BB/.06" +forbidden = true + +[[system.default.children.children]] +name = "Unused .07" +format = "C/=BB/.07/*Name/" +id = "C/=BB/.07" +forbidden = true + +[[system.default.children.children]] +name = "Unused .08" +format = "C/=BB/.08/*Name/" +id = "C/=BB/.08" +forbidden = true + +[[system.default.children.children]] +name = "ADR" +format = "C/=BB/.09 βš–οΈ Decision Log" +id = "C/=BB/.09" +allow_arbitrary_contents = true + +[[system.default.children.children]] +name = "Invalid ADR" +format = "C/=BB/.09/*ADR/" +id = "C/=BB/.09" +forbidden = true + +## ############################################################################# +# Ensure headers are empty and properly named +## ############################################################################# +[[system.default.children.children]] +name = "Header" +format = "C/=BB/./#H/0 /*Header/ ⬇️" +id = "C/=BB/./=H/0" + +# Disallow headers that don't match this format +[[system.default.children.children]] +name = "Invalid Header Or Index" +format = "C/=BB/./#H/0 /*Header/" +id = "C/=BB/./=H/0" +forbidden = true + +## ############################################################################# +# Actual Content +## ############################################################################# +[[system.default.children.children]] +name = "Cache" +format = "C/=BB/./##ID/ /*Cache/" +allow_arbitrary_contents = true +id = "C/=BB/./=ID/" + +[[system.default.children.children]] +name = "Nest" +format = "N/=BB/./####ID/~/*Nest/" +id = "N/=BB/./=ID/" +allow_arbitrary_contents = true diff --git a/images/header_note.png b/images/header_note.png deleted file mode 100644 index a737e02..0000000 Binary files a/images/header_note.png and /dev/null differ diff --git a/jdlint.py b/jdlint.py index 18937a3..7609a1a 100755 --- a/jdlint.py +++ b/jdlint.py @@ -10,476 +10,934 @@ import os import re import sys +import textwrap +import typing from dataclasses import dataclass from pathlib import Path, PurePath -from typing import Any, Callable, Literal, TypeVar +from typing import TYPE_CHECKING, Literal, TypeVar +if TYPE_CHECKING: + from collections.abc import Callable +import tomllib -@dataclass(frozen=True) -class AreaDifferentFromJDex: - """An area with a differently-named JDex entry.""" +############################################################################### +# Exceptions +############################################################################### - area: str - jdex_name: str - type: Literal["AREA_DIFFERENT_FROM_JDEX"] = "AREA_DIFFERENT_FROM_JDEX" - def display(self, files: list[File]) -> str: - """Display this particular instance of an error.""" - return f"{_print_nest(files[0])} [JDex name: {self.jdex_name}]" +class ConfigError(Exception): + """An error in the jdlint config.""" - def explain(self) -> _Explanation: - """Explain what this error is.""" - return _Explanation( - explanation="An area was found, the name of which is different from its corresponding JDex entry.", - fix="Update the one that is incorrect.", - ) + def __init__(self, key: str, message: str) -> None: + """Create a config error, given the key it occurs at and a message.""" + super().__init__(f"Error in config at key: {key}. {message}") -@dataclass(frozen=True) -class AreaNotInJDex: - """An area without a corresponding JDex entry.""" +class ConfigMissingKeyError(ConfigError): + """A missing key in the jdlint config.""" - area: str - type: Literal["AREA_NOT_IN_JDEX"] = "AREA_NOT_IN_JDEX" + def __init__(self, key: str) -> None: + """Create a missing key error.""" + super().__init__( + key, + "Required key not found.", + ) - def display(self, files: list[File]) -> str: - """Display this particular instance of an error.""" - return f"{_print_nest(files[0])} [area: {_print_area(self.area)}]" - def explain(self) -> _Explanation: - """Explain what this error is.""" - return _Explanation( - explanation="An area was found in your files that is missing from your JDex.", - fix="Go add a corresponding entry to your JDex, or delete this if it's unused.", +class ConfigExtraKeyError(ConfigError): + """An unexpected key in the jdlint config.""" + + def __init__(self, key: str, valid: tuple[str, ...]) -> None: + """Create a key error, given the extra key and a list of valid keys.""" + super().__init__( + key, + f"Not an expected key. Valid keys are: [{', '.join(valid)}]", ) -@dataclass(frozen=True) -class CategoryDifferentFromJDex: - """A category with a differently-named JDex entry.""" +class ConfigTypeError(ConfigError): + """A value with the wrong type in the jdlint config.""" - category: str - jdex_name: str - type: Literal["CATEGORY_DIFFERENT_FROM_JDEX"] = "CATEGORY_DIFFERENT_FROM_JDEX" + def __init__(self, key: str, expected: str, got: str) -> None: + """Create a type error, given the key it occurs at, the expected type, and the actual type.""" + super().__init__(key, f"Wrong type. Expected: {expected} Got: {got}") - def display(self, files: list[File]) -> str: - """Display this particular instance of an error.""" - return f"{_print_nest(files[0])} [JDex name: {self.jdex_name}]" - def explain(self) -> _Explanation: - """Explain what this error is.""" - return _Explanation( - explanation="A category was found, the name of which is different from its corresponding JDex entry.", - fix="Update the one that is incorrect.", - ) +class ConfigValueError(ConfigError): + """A bad value in the jdlint config.""" + def __init__(self, key: str, issue: str, got: str) -> None: + """Create a value error, given the key it occurs at, the issue with the value, and the actual value.""" + super().__init__(key, f"Bad value. Got: {got} Issue: {issue}") -@dataclass(frozen=True) -class CategoryInWrongArea: - """A category that, by its number, has been put in the wrong area.""" - category_area: str - file_area: str - type: Literal["CATEGORY_IN_WRONG_AREA"] = "CATEGORY_IN_WRONG_AREA" +class ConfigConflictError(ConfigError): + """A conflict in the jdlint config.""" - def display(self, files: list[File]) -> str: - """Given the file's name, print the error message for it.""" - return f"{_print_nest(files[0])} [in {_print_area(self.file_area)} but should be in {_print_area(self.category_area)}]" + def __init__(self, key: str, issue: str) -> None: + """Create a conflict error, given the key it occurs at and the issue.""" + super().__init__(key, f"Conflict in config. Issue: {issue}") - def explain(self) -> _Explanation: - """Explain what this error is.""" - return _Explanation( - explanation="Some categories are in the wrong area.", - fix="Move them into the correct area folder.", + +############################################################################### +# Config +############################################################################### +def _report_extra_keys(at: str, from_file: dict, valid: tuple[str, ...]) -> None: + # Ensure no extra fields + for key in from_file: + err = ConfigExtraKeyError(f"{at}.{key}", valid) + raise err + + +def _pop_nonempty_str_attribute(at: str, attr: str, from_file: dict) -> str: + """Given a parent location, a mandatory attribute to get, and data, return it.""" + if attr not in from_file: + err = ConfigMissingKeyError(f"{at}.{attr}") + raise err + val = from_file.pop(attr) + if not isinstance(val, str): + err = ConfigTypeError( + f"{at}.{attr}", + "str", + type(val).__name__, + ) + raise err + if val == "": + err = ConfigValueError( + f"{at}.{attr}", + "Must not be empty.", + val, + ) + raise err + return val + + +def _pop_default_false_bool(at: str, attr: str, from_file: dict) -> bool: + """Get a boolean at the specified attribute, defaulting to false, or fail.""" + val = from_file.pop(attr, False) + if not isinstance(val, bool): + err = ConfigTypeError( + f"{at}.{attr}", + "bool", + type(val).__name__, + ) + raise err + return val + + +def _pop_default_empty_list(at: str, attr: str, from_file: dict) -> list: + """Get a list at the specified attribute, defaulting to [], or fail.""" + val = from_file.pop(attr, []) + if not isinstance(val, list): + err = ConfigTypeError( + f"{at}.{attr}", + "list", + type(val).__name__, ) + raise err + return val + + +def _pop_ignore_list(at: str, from_file: dict) -> list[str]: + """Get a list of strings at .ignore or fail, defaulting to [].""" + val = _pop_default_empty_list(at, "ignore", from_file) + for i, r in enumerate(val): + if not isinstance(r, str): + err = ConfigTypeError(f"{at}.ignore[{i}]", "str", type(r).__name__) + raise err + return val + + +class ConfigSystemRoot: + """A root of a JD system to check for correctness, e.g. ~/Documents.""" + + def __init__( + self, + at: str, + default_structure: list[ConfigSystemTier], + from_file: dict, + ) -> None: + """Create a valid configuration given a loaded section of a config file.""" + self.name = _pop_nonempty_str_attribute(at, "name", from_file) + self.path = Path( + _pop_nonempty_str_attribute(at, "path", from_file), + ).expanduser() + self.ignore = _pop_ignore_list(at, from_file) + + # Validate path is good + if not self.path.is_dir(): + err = ConfigValueError( + f"{at}.path", + "Root path isn't a folder that exists!", + str(self.path), + ) + raise err + + # Load specialized structure, if any + if "children" in from_file: + self.children = [ + ConfigSystemTier( + f"{at}.children[{i}]", + ConfigFormatAncestorInfo((), ()), + v, + ) + for i, v in enumerate( + _pop_default_empty_list(at, "children", from_file), + ) + ] + elif default_structure: + self.children = default_structure + else: + err = ConfigConflictError( + f"{at}", + "Either system.default.children must be specified or every root must specify its own children.", + ) + raise err + _report_extra_keys(at, from_file, tuple(self.__dict__.keys())) -@dataclass(frozen=True) -class CategoryNotInJDex: - """An category without a corresponding JDex entry.""" - category: str - type: Literal["CATEGORY_NOT_IN_JDEX"] = "CATEGORY_NOT_IN_JDEX" +class ConfigSystemJDex: + """Valid configuration for the JDex of a system.""" - def display(self, files: list[File]) -> str: - """Display this particular instance of an error.""" - return f"{_print_nest(files[0])} [category: {self.category}]" + def __init__(self, at: str, from_file: dict) -> None: + """Create a valid configuration given a loaded section of a config file.""" + # Acquire and set defaults + self.path = Path( + _pop_nonempty_str_attribute(at, "path", from_file), + ).expanduser() + self.ignore = _pop_ignore_list(at, from_file) - def explain(self) -> _Explanation: - """Explain what this error is.""" - return _Explanation( - explanation="A category was found in the files that is missing from the JDex.", - fix="Go add a corresponding entry to your JDex.", - ) + self.children = [ + ConfigJDexTier( + f"{at}.children[{i}]", + ConfigFormatAncestorInfo((), ()), + v, + ) + for i, v in enumerate(_pop_default_empty_list(at, "children", from_file)) + ] + self.notes = [ + ConfigJDexNotes( + f"{at}.notes[{i}]", + ConfigFormatAncestorInfo((), ()), + v, + ) + for i, v in enumerate(_pop_default_empty_list(at, "notes", from_file)) + ] + + # Validate path + if not self.path.is_dir(): + if not self.path.is_file(): + # Something's weird + err = ConfigValueError( + f"{at}.path", + "JDex path isn't a folder or file that exists!", + str(self.path), + ) + raise err + # We have a file-based JDex; that's fine + if self.children or self.notes or self.ignore: + err = ConfigConflictError( + at, + "Single file JDexes must not specify children or notes or ignore!", + ) + raise ConfigConflictError + # Load format + self.entry = ConfigStaticFormat( + f"{at}.entry", + # This is the default info made available to a file JDex + ConfigFormatAncestorInfo(("Single File JDex",), ("id", "title")), + _pop_nonempty_str_attribute(at, "entry", from_file), + ) + _report_extra_keys(at, from_file, tuple(self.__dict__.keys())) -@dataclass(frozen=True) -class DuplicateArea: - """An area that has been used multiple times.""" - area: str - type: Literal["DUPLICATE_AREA"] = "DUPLICATE_AREA" +class ConfigLinter: + """Valid configuration for the linter.""" - def display(self, files: list[File]) -> str: - """Display this particular instance of an error.""" - return f"Area {_print_area(self.area)}:\n " + "\n ".join( - [_print_nest(f) for f in files], + def __init__(self, from_file: dict) -> None: + """Create a valid configuration given a loaded linter section of a config file.""" + # Acquire and set defaults + self.disable_rules = _pop_default_empty_list( + "linter", + "disable_rules", + from_file, ) + self.json_output = _pop_default_false_bool("linter", "json_output", from_file) + self.ignore = _pop_ignore_list("linter", from_file) - def explain(self) -> _Explanation: - """Explain what this error is.""" - return _Explanation( - explanation="Duplicate areas were used.", - fix="Assign a new area to one of them.", - ) + # Validate + for r in self.disable_rules: + if r in [e.type for e in typing.get_args(AnyIssueType)]: + continue + err = ConfigValueError("linter.disable_rules", "not a valid rule name", r) + raise err + + if not isinstance(self.json_output, bool): + err = ConfigTypeError( + "linter.json_output", + "bool", + type(self.json_output).__name__, + ) + raise err + _report_extra_keys("linter", from_file, tuple(self.__dict__.keys())) -@dataclass(frozen=True) -class DuplicateCategory: - """A category that has been used multiple times.""" - category: str - type: Literal["DUPLICATE_CATEGORY"] = "DUPLICATE_CATEGORY" +class ConfigSystem: + """Valid configuration for the JD system.""" - def display(self, files: list[File]) -> str: - """Display this particular instance of an error.""" - return f"Category {self.category}:\n " + "\n ".join( - [_print_nest(f) for f in files], + def __init__(self, from_file: dict) -> None: + """Create a valid configuration given a loaded system section of a config file.""" + default_structure = [ + ConfigSystemTier( + f"system.default.children[{i}]", + ConfigFormatAncestorInfo((), ()), + v, + ) + for i, v in enumerate( + _pop_default_empty_list( + "system.default", + "children", + from_file.pop("default", {}), + ), + ) + ] + + self.roots = [ + ConfigSystemRoot( + f"system.roots[{i}]", + default_structure, + v, + ) + for i, v in enumerate(_pop_default_empty_list("system", "roots", from_file)) + ] + + accum_names = {} + accum_paths = {} + for root in self.roots: + if root.name in accum_names: + err = ConfigConflictError( + "system.roots", + f"System root names must be unique. {root.name} occurs multiple times.", + ) + raise err + if root.path in accum_paths: + err = ConfigConflictError( + "system.roots", + f"System root paths must be unique. {root.path} occurs multiple times.", + ) + raise err + + if "jdex" in from_file: + self.jdex = ConfigSystemJDex("system.jdex", from_file.pop("jdex")) + else: + self.jdex = None + + _report_extra_keys("system", from_file, tuple(self.__dict__.keys())) + + +class ConfigStaticFormat: + """Configuration for how to assign a static ID or JDex note.""" + + # A valid variable segment of an ID format + variable_static_segment_re = re.compile(r"=([A-Za-z]+)") + + def __init__( + self, + at: str, + ancestors: ConfigFormatAncestorInfo, + from_file: str, + ) -> None: + """Create a valid format given a string from a config file.""" + # Validate + if from_file.count("/") % 2 != 0: + raise ConfigValueError( + at, + "Malformed format; there must be an even number of / characters. You have an extra/are missing one.", + from_file, + ) + + build = [] + + for i, v in enumerate(from_file.split("/")): + if i % 2 == 0: + # Literal segment + build.append(lambda _, v=v: v) + else: + # Variable segment + match = ConfigStaticFormat.variable_static_segment_re.fullmatch(v) + if not match: + raise ConfigValueError( + at, + "Malformed format; variable segment must consist of = followed by an alphabetic identifier.", + v, + ) + if match.group(1) in ancestors.segments: + p = match.group(1) + build.append(lambda d, p=p: d[p]) + + else: + raise ConfigValueError( + at, + "Malformed format; variable segment referenced an identifier never bound.", + v, + ) + + self.build = lambda d: "".join([f(d) for f in build]) + + +class ConfigJDexID: + """Configuration for how a JDex ID is related to a note.""" + + def __init__( + self, + at: str, + ancestors: ConfigFormatAncestorInfo, + from_file: dict, + ) -> None: + """Create a valid note format given a loaded section of a config file.""" + self.id = ConfigStaticFormat( + f"{at}.id", + ancestors, + _pop_nonempty_str_attribute(at, "id", from_file), + ) + self.entry = ConfigStaticFormat( + f"{at}.entry", + ancestors, + _pop_nonempty_str_attribute(at, "entry", from_file), ) - def explain(self) -> _Explanation: - """Explain what this error is.""" - return _Explanation( - explanation="Duplicate categories were used.", - fix="Assign a new category to one of them.", + _report_extra_keys(at, from_file, tuple(self.__dict__.keys())) + + +class ConfigJDexNotes: + """Configuration for how JDex notes are formatted.""" + + def __init__( + self, + at: str, + ancestors: ConfigFormatAncestorInfo, + from_file: dict, + ) -> None: + """Create a valid note format given a loaded section of a config file.""" + # Compile Format + if "format" not in from_file: + err = ConfigMissingKeyError(f"{at}.format") + raise err + self.format = ConfigFormat( + f"{at}", + ancestors, + from_file, + ) + if "ids" not in from_file and not self.format.forbidden: + err = ConfigMissingKeyError(f"{at}.ids") + raise err + self.ids = [ + ConfigJDexID( + f"{at}.ids[{i}]", + self.format, + v, + ) + for i, v in enumerate(_pop_default_empty_list(at, "ids", from_file)) + ] + if "jdex_entry" in from_file: + self.jdex_entry = ConfigStaticFormat( + f"{at}.jdex_entry", + self.format, + _pop_nonempty_str_attribute(at, "jdex_entry", from_file), + ) + else: + self.jdex_entry = None + + _report_extra_keys(at, from_file, tuple(self.__dict__.keys())) + + +class ConfigFolderTier: + """A tier of a JD system, e.g. a Category, whether in the JDex or the system itself.""" + + def __init__( + self, + child_class: Callable, + at: str, + ancestors: ConfigFormatAncestorInfo, + from_file: dict, + ) -> None: + """Create a valid tier given a loaded section of a config file.""" + # Acquire and set defaults + self.allow_arbitrary_contents = _pop_default_false_bool( + at, + "allow_arbitrary_contents", + from_file, ) + # Validate + if not isinstance(self.allow_arbitrary_contents, bool): + err = ConfigTypeError( + f"{at}.allow_arbitrary_contents", + "bool", + type(self.allow_arbitrary_contents).__name__, + ) + raise err -@dataclass(frozen=True) -class DuplicateId: - """An ID that has been used multiple times.""" + # Compile Format & Children + self.format = ConfigFormat( + at, + ancestors, + from_file, + ) + self.children = [ + child_class( + f"{at}.children[{i}]", + self.format, + v, + ) + for i, v in enumerate(_pop_default_empty_list(at, "children", from_file)) + ] + if self.children and self.allow_arbitrary_contents: + raise ConfigConflictError( + at, + "If children are specified, allow_arbitrary_contents must be false.", + ) + if self.format.forbidden and self.children: + raise ConfigConflictError( + at, + "If forbidden, children must not be specified.", + ) + if self.format.forbidden and self.allow_arbitrary_contents: + raise ConfigConflictError( + at, + "If forbidden, allow_arbitrary_contents must be false.", + ) - id: str - type: Literal["DUPLICATE_ID"] = "DUPLICATE_ID" - def display(self, files: list[File]) -> str: - """Display this particular instance of an error.""" - return f"ID {self.id}:\n " + "\n ".join([_print_nest(f) for f in files]) +class ConfigSystemTier(ConfigFolderTier): + """A tier of a JD system, e.g. a Category, in the system (not the JDex).""" - def explain(self) -> _Explanation: - """Explain what this error is.""" - return _Explanation( - explanation="Duplicate IDs were used.", - fix="Assign a new ID to one of them.", + def __init__( + self, + at: str, + ancestors: ConfigFormatAncestorInfo, + from_file: dict, + ) -> None: + """Create a valid tier given a loaded section of a config file.""" + # Acquire and set defaults + + self.can_be_file = _pop_default_false_bool(at, "can_be_file", from_file) + self.no_jdex_entry = _pop_default_false_bool(at, "no_jdex_entry", from_file) + + # Call the folder tier stuff + super().__init__(ConfigSystemTier, at, ancestors, from_file) + + if "jdex_entry" in from_file: + self.jdex_entry = ConfigStaticFormat( + f"{at}.jdex_entry", + self.format, + _pop_nonempty_str_attribute(at, "jdex_entry", from_file), + ) + else: + self.jdex_entry = None + + self.id = ConfigStaticFormat( + f"{at}.id", + self.format, + _pop_nonempty_str_attribute(at, "id", from_file), ) + if not isinstance(self.can_be_file, bool): + err = ConfigTypeError( + f"{at}.can_be_file", + "bool", + type(self.can_be_file).__name__, + ) + raise err + + if self.children and self.can_be_file: + err = ConfigConflictError( + at, + "If children are specified, can_be_file must be false.", + ) + raise err -@dataclass(frozen=True) -class FileOutsideId: - """A file was encountered not in a terminal ID folder.""" + if self.format.forbidden and self.can_be_file: + err = ConfigConflictError( + at, + "If forbidden, can_be_file must be false.", + ) + raise err + if self.no_jdex_entry and self.jdex_entry: + err = ConfigConflictError( + at, + "Only one of no_jdex_entry and jdex_entry may be set.", + ) + raise err - type: Literal["FILE_OUTSIDE_ID"] = "FILE_OUTSIDE_ID" + _report_extra_keys(at, from_file, tuple(self.__dict__.keys())) - def display(self, files: list[File]) -> str: - """Display this particular instance of an error.""" - return _print_nest(files[0]) - def explain(self) -> _Explanation: - """Explain what this error is.""" - return _Explanation( - explanation="Files were found outside of IDs.", - fix="Files should only be kept in IDs and not higher in the hierarchy.", - ) +class ConfigJDexTier(ConfigFolderTier): + """A tier (hierarchical level) of a JD system, e.g. a Category, in the JDex.""" + def __init__( + self, + at: str, + ancestors: ConfigFormatAncestorInfo, + from_file: dict, + ) -> None: + """Create a valid tier given a loaded section of a config file.""" + # Call the folder tier stuff + super().__init__(ConfigJDexTier, at, ancestors, from_file) -@dataclass(frozen=True) -class IdDifferentFromJDex: - """An ID with a differently-named JDex entry.""" + self.notes = [ + ConfigJDexNotes( + f"{at}.notes[{i}]", + self.format, + v, + ) + for i, v in enumerate(_pop_default_empty_list(at, "notes", from_file)) + ] - id: str - jdex_name: str - type: Literal["ID_DIFFERENT_FROM_JDEX"] = "ID_DIFFERENT_FROM_JDEX" + if self.notes and self.format.forbidden: + raise ConfigConflictError( + at, + "If forbidden, notes cannot be specified.", + ) - def display(self, files: list[File]) -> str: - """Display this particular instance of an error.""" - return f"{_print_nest(files[0])} [JDex name: {self.jdex_name}]" + _report_extra_keys(at, from_file, tuple(self.__dict__.keys())) - def explain(self) -> _Explanation: - """Explain what this error is.""" - return _Explanation( - explanation="An ID was found, the name of which is different from its corresponding JDex entry.", - fix="Update the one that is incorrect.", - ) +@dataclass +class ConfigFormatAncestorInfo: + """Information about the ancestors of a format.""" + + name: tuple[str, ...] + segments: tuple[str, ...] + + +class ConfigFormat(ConfigFormatAncestorInfo): + """A format for a file or folder.""" + + # A valid variable segment of a format + variable_segment_re = re.compile(r"(=|\*|[#]+)([A-Za-z]+)") + + def __init__( + self, + at: str, + ancestors: ConfigFormatAncestorInfo, + from_file: dict, + ) -> None: + """Create a valid format given a string from a config file.""" + name = _pop_nonempty_str_attribute(at, "name", from_file) + self.raw_format = _pop_nonempty_str_attribute(at, "format", from_file) + self.forbidden = _pop_default_false_bool(at, "forbidden", from_file) + + # Validate + if self.raw_format.count("/") % 2 != 0: + err = ConfigValueError( + f"{at}.format", + "Malformed format; there must be an even number of / characters. You have an extra one/are missing one.", + str(from_file), + ) + raise err + + regex = [] + new_segments = [] -@dataclass(frozen=True) -class IdInWrongCategory: - """An ID that, by its number, has been put in the wrong category.""" + for i, v in enumerate(self.raw_format.split("/")): + if i % 2 == 0: + # Literal segment + regex.append(lambda _, v=v: re.escape(v)) + continue + # Variable segment + match = ConfigFormat.variable_segment_re.fullmatch(v) + if not match: + err = ConfigValueError( + f"{at}.format", + "Malformed format; variable segment must consist of =, *, or one or more # followed by an alphabetic identifier.", + v, + ) + raise err + segment_type = match.group(1) + identifier = match.group(2) + if segment_type == "=": + if identifier in ancestors.segments: + p = identifier + regex.append(lambda d, p=p: re.escape(d[p])) + elif identifier in new_segments: + regex.append( + lambda _, identifier=identifier: f"(?P={identifier})", + ) - id_ac: str - file_ac: str - type: Literal["ID_IN_WRONG_CATEGORY"] = "ID_IN_WRONG_CATEGORY" + else: + err = ConfigValueError( + f"{at}.format", + f'Malformed format; variable segment referenced the identifier "{identifier}" which has not been bound.', + v, + ) + raise err + else: + if identifier in ancestors.segments: + err = ConfigValueError( + f"{at}.format", + f'Malformed format; variable segment tried to rebind the identifier "{identifier}", which was already bound in a parent.', + v, + ) + raise err + if identifier in new_segments: + err = ConfigValueError( + f"{at}.format", + f'Malformed format; variable segment tried to rebind the identifier "{identifier}", which was already bound in this format.', + v, + ) + raise err + new_segments.append(identifier) + if segment_type == "*": + regex.append( + lambda _, identifier=identifier: f"(?P<{identifier}>.+?)", + ) + else: + # Must be a ## type variable + match_len = len(segment_type) + regex.append( + lambda _, identifier=identifier, match_len=match_len: ( + f"(?P<{identifier}>[0-9]{{{match_len}}})" + ), + ) - def display(self, files: list[File]) -> str: - """Display this particular instance of an error.""" - return ( - f"{_print_nest(files[0])} [in {self.file_ac} but should be in {self.id_ac}]" - ) + self.name = (*ancestors.name, name) + self.segments = ancestors.segments + tuple(new_segments) + self.build_regex = lambda d: "".join([f(d) for f in regex]) - def explain(self) -> _Explanation: - """Explain what this error is.""" - return _Explanation( - explanation="Some IDs are in the wrong category.", - fix="Move them into the correct category folder.", - ) +class Config: + """Valid config for jdlint.""" -@dataclass(frozen=True) -class IdNotInJDex: - """An ID without a corresponding JDex entry.""" + def __init__(self, from_file: dict) -> None: + """Attempt to create a valid config from loaded TOML.""" + self.linter = ConfigLinter(from_file.get("linter", {})) - id: str - type: Literal["ID_NOT_IN_JDEX"] = "ID_NOT_IN_JDEX" + if "system" not in from_file: + err = ConfigMissingKeyError("system") + raise err + self.system = ConfigSystem(from_file["system"]) - def display(self, files: list[File]) -> str: - """Display this particular instance of an error.""" - return f"{_print_nest(files[0])} [ID: {self.id}]" - def explain(self) -> _Explanation: - """Explain what this error is.""" - return _Explanation( - explanation="An ID was found in the files that is missing from the JDex.", - fix="Go add a corresponding entry to your JDex.", - ) +############################################################################### +# Issues +############################################################################### @dataclass(frozen=True) -class InvalidAreaName: - """A folder at the area level that doesn't match the normal format.""" +class Issue: + """A single error detected in the system.""" - type: Literal["INVALID_AREA_NAME"] = "INVALID_AREA_NAME" + file: PurePath + type = "" - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return _print_nest(files[0]) + raise NotImplementedError def explain(self) -> _Explanation: """Explain what this error is.""" - return _Explanation( - explanation="Some areas have invalid names.", - fix='Valid area names look like "10-19 Life Admin", so edit the names to match that format.', - ) + raise NotImplementedError @dataclass(frozen=True) -class InvalidCategoryName: - """A folder at the category level that doesn't match the normal format.""" +class JDexIssue: + """A single error detected in the JDex.""" - type: Literal["INVALID_CATEGORY_NAME"] = "INVALID_CATEGORY_NAME" + file: PurePath | None + type = "" - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return _print_nest(files[0]) + raise NotImplementedError def explain(self) -> _Explanation: """Explain what this error is.""" - return _Explanation( - explanation="Some categories have invalid names.", - fix='Valid category names look like "11 Me, Myself, & I", so edit the names to match that format.', - ) + raise NotImplementedError @dataclass(frozen=True) -class InvalidIDName: - """A folder at the ID level that doesn't match the normal format.""" +class IssueEmptyFolder(Issue): + """A folder is completely empty (and is not arbitrary content).""" - type: Literal["INVALID_ID_NAME"] = "INVALID_ID_NAME" + type: Literal["EMPTY_FOLDER"] = "EMPTY_FOLDER" - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return _print_nest(files[0]) + return f"{self.file!s}" def explain(self) -> _Explanation: """Explain what this error is.""" return _Explanation( - explanation="Some IDs have invalid names.", - fix='Valid ID names look like "11.11 A Cool Project", so edit the names to match that format.', + explanation="A folder that matched a pattern in the system has no contents.", + fix="If this folder is unused, it shouldn't exist. Remove it or explicitly set it ignored if it must exist.", ) @dataclass(frozen=True) -class NonemptyInbox: - """An inbox (AC.01) that contains items.""" +class IssueFileWhereFolderExpected(Issue): + """A file that matched an expected folder was found.""" - num_items: int - type: Literal["NONEMPTY_INBOX"] = "NONEMPTY_INBOX" + matched_pattern: ContentPattern + type: Literal["FILE_WHERE_FOLDER_EXPECTED"] = "FILE_WHERE_FOLDER_EXPECTED" - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return f"{_print_nest(files[0])} [{self.num_items} items]" + return f"{self.file!s}\n matched: {_print_pattern(self.matched_pattern)})" def explain(self) -> _Explanation: """Explain what this error is.""" return _Explanation( - explanation="Files were found in an inbox.", - fix="Go sort them into the appropriate IDs.", + explanation="A file was found that matched the format of an expected child folder.", + fix="Your format should not mix folders and files that share a naming scheme.", ) -ErrorType = ( - AreaDifferentFromJDex - | AreaNotInJDex - | CategoryDifferentFromJDex - | CategoryInWrongArea - | CategoryNotInJDex - | DuplicateArea - | DuplicateCategory - | DuplicateId - | FileOutsideId - | IdDifferentFromJDex - | IdInWrongCategory - | IdNotInJDex - | InvalidAreaName - | InvalidCategoryName - | InvalidIDName - | NonemptyInbox -) - - @dataclass(frozen=True) -class JDexAreaHeaderDifferentFromArea: - """An area header with a different name than the correspnoding area.""" +class IssueArbitraryContentWhereNotAllowed(Issue): + """Content was found that didn't match any expected format.""" - area: str - jdex_name: str - type: Literal["JDEX_AREA_HEADER_DIFFERENT_FROM_AREA"] = ( - "JDEX_AREA_HEADER_DIFFERENT_FROM_AREA" + possible_formats: tuple[ContentPattern, ...] + type: Literal["ARBITRARY_CONTENT_WHERE_NOT_ALLOWED"] = ( + "ARBITRARY_CONTENT_WHERE_NOT_ALLOWED" ) - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return f"{_print_nest(files[0])} [JDex name: {self.jdex_name}]" + return f"{self.file!s}\n{textwrap.indent(_print_unmatched_patterns(self.possible_formats), ' ')}" def explain(self) -> _Explanation: """Explain what this error is.""" return _Explanation( - explanation="An area header was found, the name of which is different from its corresponding JDex entry.", - fix="Update the one that is incorrect.", + explanation="Files or folders were found that matched no expected format.", + fix="You should either make the content match or set allow_arbitrary_content to true if it is intended for random content to be mixed in.", ) @dataclass(frozen=True) -class JDexAreaHeaderWithoutArea: - """An area header with no corresponding area.""" +class IssueFolderShouldBeEmpty(Issue): + """Content was found in a folder that should be empty.""" - area: str - type: Literal["JDEX_AREA_HEADER_WITHOUT_AREA"] = "JDEX_AREA_HEADER_WITHOUT_AREA" + children: tuple[PurePath, ...] + type: Literal["FOLDER_SHOULD_BE_EMPTY"] = "FOLDER_SHOULD_BE_EMPTY" - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return f"{_print_nest(files[0])} [area: {_print_area(self.area)}]" + return f"{self.file!s}\n has {_pluralize(len(self.children), 'child', 'children')}" def explain(self) -> _Explanation: """Explain what this error is.""" return _Explanation( - explanation="An area header was found in the JDex with no corresponding area entry.", - fix="Go add a corresponding entry to your JDex, or delete this header if it is no longer needed.", + explanation="Files or folders were found in a folder that should be empty.", + fix="Either the folder in question should have allow_arbitrary_content set to true, or you should remove the content.", ) @dataclass(frozen=True) -class JDexCategoryInWrongArea: - """A JDex category that, by its number, has been put in the wrong area.""" +class IssueDuplicateID(Issue): + """An ID that has been used multiple times.""" - category_area: str - file_area: str - type: Literal["JDEX_CATEGORY_IN_WRONG_AREA"] = "JDEX_CATEGORY_IN_WRONG_AREA" + files: tuple[PurePath, ...] + id: str + type: Literal["DUPLICATE_ID"] = "DUPLICATE_ID" - def display(self, files: list[File]) -> str: - """Given the file's name, print the error message for it.""" - return f"{_print_nest(files[0])} [in {_print_area(self.file_area)} but should be in {_print_area(self.category_area)}]" + def display(self) -> str: + """Display this particular instance of an error.""" + return f"{self.id}:\n " + "\n ".join([str(f) for f in self.files]) def explain(self) -> _Explanation: """Explain what this error is.""" return _Explanation( - explanation="Some JDex categories are in the wrong area.", - fix="Move them into the correct area folder, or use a flat JDex structure.", + explanation="Duplicate IDs were used.", + fix="Assign a new ID to one of them.", ) @dataclass(frozen=True) -class JDexDuplicateArea: - """A JDex area that has been used multiple times.""" +class IssueIDNotInJDex(Issue): + """An ID without a corresponding JDex entry.""" - area: str - type: Literal["JDEX_DUPLICATE_AREA"] = "JDEX_DUPLICATE_AREA" + id: str + type: Literal["ID_NOT_IN_JDEX"] = "ID_NOT_IN_JDEX" - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return f"Area {_print_area(self.area)}:\n " + "\n ".join( - [_print_nest(f) for f in files], - ) + return f"{self.id}:\n {self.file!s}" def explain(self) -> _Explanation: """Explain what this error is.""" return _Explanation( - explanation="Duplicate areas were used in the JDex.", - fix="Assign a new area to one of them.", + explanation="An ID was found in files that is missing from the JDex.", + fix="Go add a corresponding entry to your JDex.", ) @dataclass(frozen=True) -class JDexDuplicateAreaHeader: - """Multiple headers for the same area.""" +class IssueIDDifferentFromJDex(Issue): + """An ID with a differently-named JDex entry.""" - area: str - type: Literal["JDEX_DUPLICATE_AREA_HEADER"] = "JDEX_DUPLICATE_AREA_HEADER" + id: str + expected_jdex_entry: str + known_jdex_entries: list[JDexEntry] + type: Literal["ID_DIFFERENT_FROM_JDEX"] = "ID_DIFFERENT_FROM_JDEX" - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return f"Area {_print_area(self.area)}:\n " + "\n ".join( - [_print_nest(f) for f in files], + known = "\n".join( + f"{n.entry} [from {n.path}]" for n in self.known_jdex_entries ) + return f"{self.id}:\n Folder: {self.file!s}\n Expected JDex: {self.expected_jdex_entry}\n Actual JDex:\n{textwrap.indent(known, ' ')}" def explain(self) -> _Explanation: """Explain what this error is.""" return _Explanation( - explanation="Duplicate headers were found for the same area in the JDex.", - fix="Delete the one that is incorrect or fix the area number.", + explanation="An ID was found, the name of which is different from its corresponding JDex entry.", + fix="Update the one that is incorrect.", ) @dataclass(frozen=True) -class JDexDuplicateCategory: - """A JDex category that has been used multiple times.""" +class IssueEncounteredForbiddenFolder(Issue): + """A file that matched a forbidden format was found.""" - category: str - type: Literal["JDEX_DUPLICATE_CATEGORY"] = "JDEX_DUPLICATE_CATEGORY" + matched_pattern: ContentPattern + type: Literal["ENCOUNTERED_FORBIDDEN_FOLDER"] = "ENCOUNTERED_FORBIDDEN_FOLDER" - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return ( - self.category + ":\n " + "\n ".join([_print_nest(f) for f in files]) - ) + return f"{self.file!s}\n matched: {_print_pattern(self.matched_pattern)})" def explain(self) -> _Explanation: """Explain what this error is.""" return _Explanation( - explanation="Duplicate categories were used in the JDex.", - fix="Assign a new category to one of them.", + explanation="A file was found that matched the format of a forbidden folder.", + fix="You should remove/rename the file in question.", ) @dataclass(frozen=True) -class JDexDuplicateId: +class File: + """A file or folder that has been detected by jdlint.""" + + name: Path + path: Path + + +@dataclass(frozen=True) +class JDexIssueDuplicateID(JDexIssue): """A JDex ID that has been used multiple times.""" + files: tuple[PurePath | None, ...] id: str type: Literal["JDEX_DUPLICATE_ID"] = "JDEX_DUPLICATE_ID" - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return self.id + ":\n " + "\n ".join([_print_nest(f) for f in files]) + return f"{self.id}:\n " + "\n ".join([str(f) for f in self.files]) def explain(self) -> _Explanation: """Explain what this error is.""" @@ -490,122 +948,151 @@ def explain(self) -> _Explanation: @dataclass(frozen=True) -class JDexFileOutsideCategory: - """A JDex file was encountered not in a terminal category folder.""" +class JDexIssueFileWhereFolderExpected(JDexIssue): + """A JDex file that matched an expected folder was found.""" - type: Literal["JDEX_FILE_OUTSIDE_CATEGORY"] = "JDEX_FILE_OUTSIDE_CATEGORY" + matched_pattern: ContentPattern + type: Literal["JDEX_FILE_WHERE_FOLDER_EXPECTED"] = "JDEX_FILE_WHERE_FOLDER_EXPECTED" - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return _print_nest(files[0]) + return f"{self.file!s}\n matched: {_print_pattern(self.matched_pattern)})" def explain(self) -> _Explanation: """Explain what this error is.""" return _Explanation( - explanation="JDex files were found outside of categories in a nested structure.", - fix="JDex files should be entirely flat, or nested under area then category.", + explanation="A JDex file was found that matched the format of an expected child folder.", + fix="Your JDex format should not mix folders and notes that share a naming scheme.", ) @dataclass(frozen=True) -class JDexIdInWrongCategory: - """A JDex ID that, by its number, has been put in the wrong category.""" +class JDexIssueFolderWhereNoteExpected(JDexIssue): + """A JDex folder that matched an expected note was found.""" - id_ac: str - file_ac: str - type: Literal["JDEX_ID_IN_WRONG_CATEGORY"] = "JDEX_ID_IN_WRONG_CATEGORY" + matched_pattern: ContentPattern + type: Literal["JDEX_FOLDER_WHERE_NOTE_EXPECTED"] = "JDEX_FOLDER_WHERE_NOTE_EXPECTED" - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return ( - f"{_print_nest(files[0])} [in {self.file_ac} but should be in {self.id_ac}]" - ) + return f"{self.file!s}\n matched: {_print_pattern(self.matched_pattern)})" def explain(self) -> _Explanation: """Explain what this error is.""" return _Explanation( - explanation="Some JDex IDs are in the wrong category.", - fix="Move them into the correct category folder, or use a flat JDex structure.", + explanation="A JDex folder was found that matched the format of an expected note.", + fix="Your JDex format should not mix folders and notes that share a naming scheme.", ) @dataclass(frozen=True) -class JDexInvalidAreaName: - """A folder at the JDex area level that doesn't match the normal format.""" +class ContentPattern: + """A possible pattern that could be matched.""" + + name: tuple[str, ...] + format: str - type: Literal["JDEX_INVALID_AREA_NAME"] = "JDEX_INVALID_AREA_NAME" - def display(self, files: list[File]) -> str: +@dataclass(frozen=True) +class JDexIssueArbitraryContentWhereNotAllowed(JDexIssue): + """Content was found in the JDex that didn't match any expected format.""" + + possible_formats: tuple[ContentPattern, ...] + type: Literal["JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED"] = ( + "JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED" + ) + + def display(self) -> str: """Display this particular instance of an error.""" - return _print_nest(files[0]) + return f"{self.file!s}\n{textwrap.indent(_print_unmatched_patterns(self.possible_formats), ' ')}" def explain(self) -> _Explanation: """Explain what this error is.""" return _Explanation( - explanation="Some JDex areas have invalid names.", - fix='Valid area names look like "10-19 Life Admin", so edit the names to match that format.', + explanation="Files or folders were found in the JDex that matched no expected format.", + fix="You should either make the content match or set allow_arbitrary_content to true if it is intended for random content to be mixed in.", ) @dataclass(frozen=True) -class JDexInvalidCategoryName: - """A folder at the JDex category level that doesn't match the normal format.""" +class JDexIssueEmptyFolder(JDexIssue): + """A folder in the JDex is completely empty (and is not arbitrary content).""" - type: Literal["JDEX_INVALID_CATEGORY_NAME"] = "JDEX_INVALID_CATEGORY_NAME" + type: Literal["JDEX_EMPTY_FOLDER"] = "JDEX_EMPTY_FOLDER" - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return _print_nest(files[0]) + return f"{self.file!s}" def explain(self) -> _Explanation: """Explain what this error is.""" return _Explanation( - explanation="Some JDex categories have invalid names.", - fix='Valid category names look like "11 Me, Myself, & I", so edit the names to match that format.', + explanation="A folder that matched a pattern in the JDex has no contents.", + fix="You should ensure that all JDex notes exist; if this folder truly contains no IDs, it shouldn't exist.", ) @dataclass(frozen=True) -class JDexInvalidIDName: - """A JDex note that doesn't match the normal format.""" +class JDexIssueEncounteredForbiddenFolder(JDexIssue): + """A JDex file that matched a forbidden format was found.""" - type: Literal["JDEX_INVALID_ID_NAME"] = "JDEX_INVALID_ID_NAME" + matched_pattern: ContentPattern + type: Literal["JDEX_ENCOUNTERED_FORBIDDEN_FOLDER"] = ( + "JDEX_ENCOUNTERED_FORBIDDEN_FOLDER" + ) - def display(self, files: list[File]) -> str: + def display(self) -> str: """Display this particular instance of an error.""" - return _print_nest(files[0]) + return f"{self.file!s}\n matched: {_print_pattern(self.matched_pattern)})" def explain(self) -> _Explanation: """Explain what this error is.""" return _Explanation( - explanation="Some JDex IDs have invalid names.", - fix='Valid ID names look like "11.11 A Cool Project", so edit the names to match that format.', + explanation="A JDex file was found that matched the format of a forbidden folder.", + fix="You should remove/rename the file in question.", ) -JDexErrorType = ( - JDexAreaHeaderDifferentFromArea - | JDexAreaHeaderWithoutArea - | JDexCategoryInWrongArea - | JDexDuplicateArea - | JDexDuplicateAreaHeader - | JDexDuplicateCategory - | JDexDuplicateId - | JDexFileOutsideCategory - | JDexIdInWrongCategory - | JDexInvalidAreaName - | JDexInvalidCategoryName - | JDexInvalidIDName -) +@dataclass(frozen=True) +class JDexIssueEncounteredForbiddenNote(JDexIssue): + """A JDex file that matched a forbidden format was found.""" + matched_pattern: ContentPattern + type: Literal["JDEX_ENCOUNTERED_FORBIDDEN_NOTE"] = "JDEX_ENCOUNTERED_FORBIDDEN_NOTE" -@dataclass(frozen=True) -class File: - """A file or folder that has been detected by jdlint.""" + def display(self) -> str: + """Display this particular instance of an error.""" + return f"{self.file!s}\n matched: {_print_pattern(self.matched_pattern)})" - name: str - full_path: str - nested_under: list[str] + def explain(self) -> _Explanation: + """Explain what this error is.""" + return _Explanation( + explanation="A JDex file was found that matched the format of a forbidden note.", + fix="You should remove/rename the file in question.", + ) + + +JDexIssueType = ( + JDexIssueArbitraryContentWhereNotAllowed + | JDexIssueDuplicateID + | JDexIssueEmptyFolder + | JDexIssueFileWhereFolderExpected + | JDexIssueFolderWhereNoteExpected + | JDexIssueEncounteredForbiddenFolder + | JDexIssueEncounteredForbiddenNote +) +IssueType = ( + IssueArbitraryContentWhereNotAllowed + | IssueDuplicateID + | IssueEmptyFolder + | IssueFileWhereFolderExpected + | IssueFolderShouldBeEmpty + | IssueIDDifferentFromJDex + | IssueIDNotInJDex + | IssueEncounteredForbiddenFolder +) + +AnyIssueType = JDexIssueType | IssueType @dataclass(frozen=True) @@ -615,707 +1102,604 @@ class _Explanation: @dataclass(frozen=True) -class Error: - """A single error detected.""" +class SystemFolder: + """A folder detected in a JD root, including its path and its children (by ID).""" - error: ErrorType - files: list[File] - - def type(self) -> str: - """Return the name (type) of the error.""" - return self.error.type - - def display(self) -> str: - """Display this particular instance of an error.""" - return self.error.display(self.files) - - def explain(self) -> _Explanation: - """Explain what this error is.""" - return self.error.explain() + path: PurePath + children: dict[str, list[SystemFolder | SystemFile]] @dataclass(frozen=True) -class JDexError: - """A single error detected in the JDex.""" +class SystemFile: + """A file detected in a JD root, consisting of its path.""" - error: JDexErrorType - files: list[File] + path: PurePath - def type(self) -> str: - """Return the name (type) of the error.""" - return self.error.type - def display(self) -> str: - """Display this particular instance of an error.""" - return self.error.display(self.files) +@dataclass(frozen=True) +class JDexEntry: + """An entry in a JDex, including the path to the note that defined it.""" - def explain(self) -> _Explanation: - """Explain what this error is.""" - return self.error.explain() + entry: str + path: PurePath | None @dataclass(frozen=True) -class LintResults: - """All errors returned from linting files, as well as dictionaries of all areas, categories, and IDs used (and their names).""" +class JDexLintResults: + """All errors returned from linting the JDex.""" - errors: list[Error] - used_areas: dict[str, list[tuple[str, File]]] - used_categories: dict[str, list[tuple[str, File]]] - used_ids: dict[str, list[tuple[str, File]]] + errors: list[JDexIssue] + path: PurePath + entries: dict[str, list[JDexEntry]] -@dataclass -class _JDexAccumulator: - """Accumulator used by _get_jdex_entries to gather information about the JDex.""" - - errors: list[JDexError] - areas: dict[str, list[tuple[str, File]]] - categories: dict[str, list[tuple[str, File]]] - ids: dict[str, list[tuple[str, File]]] - headers: dict[str, list[tuple[str, File]]] +@dataclass(frozen=True) +class RootLintResults: + """All errors returned from linting a system root.""" - def __init__(self) -> None: - self.errors = [] - self.areas = {} - self.categories = {} - self.ids = {} - self.headers = {} + errors: list[Issue] + path: PurePath + structure: dict[str, list[SystemFolder | SystemFile]] @dataclass(frozen=True) -class _JDexResults: - """Canonical results from the JDex, featuring the ID and name of each area/category/ID.""" +class LintResults: + """All errors returned from linting files, as well as the JDex and filesystems structures.""" - areas: dict[str, str] - categories: dict[str, str] - ids: dict[str, str] + jdex: None | JDexLintResults + roots: dict[str, RootLintResults] + ignored_errs: int class _EnhancedJSONEncoder(json.JSONEncoder): def default(self, o: object) -> object: # Add JSON encoding for dataclasses and paths if dataclasses.is_dataclass(o): - return dataclasses.asdict(o) # type: ignore[arg-type] + return dataclasses.asdict(o) # ty:ignore[invalid-argument-type] if isinstance(o, PurePath): return str(o) return super().default(o) -def _sort_error(e: Error | JDexError) -> tuple[str, list[tuple[list[str], str]]]: - # Sort errors alphabetically by type, then by file/s affected - return ( - e.error.type, - [_sort_file(f) for f in e.files], - ) - - -def _sort_file(f: File) -> tuple[list[str], str]: - # Sort files first by degree of nesting, then alphabetically - return (f.nested_under, f.name) - - -# Any valid area folder name -valid_area_re = re.compile("([0-9])0-(?:\\1)9 (.+)") -# Any valid category folder name -generic_category_re = re.compile("([0-9])[0-9] .+") -# Any valid ID folder name -generic_id_re = re.compile("([0-9][0-9])\\.([0-9][0-9]) (.+)") -# Matches only IDs that are inboxes -inbox_re = re.compile("[0-9][0-9]\\.01 .+") +def _print_pattern(p: ContentPattern) -> str: + return f"{'/'.join(p.name)}: {p.format}" -def _valid_category_re(a: str) -> re.Pattern: - """Match only valid categories for a given area.""" - return re.compile("(" + a + "[0-9]) (.+)") +def _print_unmatched_patterns(ps: tuple[ContentPattern, ...]) -> str: + formats = "\n".join(_print_pattern(p) for p in ps) + return f"matched none of:\n{textwrap.indent(formats, ' ')}" -def _valid_id_re(ac: str) -> re.Pattern: - """Match only valid IDs for a given area and category.""" - return re.compile("(" + ac + "\\.[0-9][0-9]) (.+)") +def _sort_jdex_error(e: JDexIssue) -> tuple[str, tuple[tuple[str, ...], str]]: + # Sort errors alphabetically by type, then by file affected + # This is split from _sort_error for type-checking nonsense + if e.type == "": + raise NotImplementedError + return ( + e.type, + (e.file.parent.parts, e.file.name) if e.file else ((), ""), + ) -# Match area header JDex notes -jdex_note_header_re = re.compile("([0-9])0\\. (.+?)(\\.md)?") -# Match any valid ID JDex note -jdex_note_generic_id_re = re.compile("([0-9][0-9])\\.([0-9][0-9]) (.+?)(\\.md)?") +def _sort_error(e: Issue) -> tuple[str, tuple[tuple[str, ...], str]]: + # Sort errors alphabetically by type, then by file affected + # This is split from _sort_jdex_error for type-checking nonsense + if e.type == "": + raise NotImplementedError + return ( + e.type, + (e.file.parent.parts, e.file.name), + ) -def _jdex_note_id_re(ac: str) -> re.Pattern: - """Match only valid JDex note IDs for a given area and category.""" - return re.compile("(" + ac + "\\.[0-9][0-9]) (.+?)(\\.md)?") +def _sort_jdex_entry(e: JDexEntry) -> tuple[str, PurePath]: + return (e.entry, e.path or PurePath()) def _entry_is_ignored( ignored: list[str] | None, - nested_under: list[str], f: os.DirEntry, ) -> bool: """Check if a given file/directory should be ignored.""" if not ignored: return False - p = PurePath(*nested_under, f.name) - return any(p.match(pattern) for pattern in ignored) + return any(PurePath(f).match(pattern) for pattern in ignored) E = TypeVar("E") -def _error_if_dups( # Python's types are horrid and it just is awful to try to type this better - make_error_type: Callable[[str], Any], - make_error: Callable[[Any, list[File]], E], - d: dict[str, list[tuple[Any, File]]], -) -> list[E]: - return [ - make_error( - make_error_type(k), - sorted([file for (_, file) in v], key=_sort_file), - ) - for k, v in d.items() - if len(v) > 1 - ] - - -def _insert_append(k, v, d) -> None: # noqa: ANN001 +def _insert_append_sorted(k, v, d, key=None) -> None: # noqa: ANN001 """Add value as a singleton if it's not already in the dict, else append it to the list.""" if k not in d: d.update({k: []}) d[k].append(v) + d[k].sort(key=key) -def _process_single_file_jdex(path: Path) -> _JDexResults: - """Process a JDex located in a single file.""" - # Matches JDex areas in a single-file format - jdex_line_area_re = re.compile("([0-9])0-(?:\\1)9 (.+?)\\s*(//.*)?") - # Matches JDex categories in a single-file format - jdex_line_category_re = re.compile("([0-9][0-9]) (.+?)\\s*(//.*)?") - # Matches JDex ids in a single-file format - jdex_line_id_re = re.compile("([0-9][0-9].[0-9][0-9]) (.+?)\\s*(//.*)?") - - file_areas = {} - file_categories = {} - file_ids = {} - - with path.open() as jdex_it: - for entry in jdex_it: - area_match = jdex_line_area_re.fullmatch(entry.strip()) - if area_match: - file_areas[area_match.group(1)] = ( - f"{area_match.group(1)}0-09 {area_match.group(2)}" - ) - continue - category_match = jdex_line_category_re.fullmatch(entry.strip()) - if category_match: - file_categories[category_match.group(1)] = ( - f"{category_match.group(1)} {category_match.group(2)}" - ) - continue - id_match = jdex_line_id_re.fullmatch(entry.strip()) - if id_match: - file_ids[id_match.group(1)] = f"{id_match.group(1)} {id_match.group(2)}" - continue - return _JDexResults( - areas=file_areas, - categories=file_categories, - ids=file_ids, - ) - - -def _process_flat_jdex_structure( - files: list[os.DirEntry], - jdex: _JDexAccumulator, - *, - ignored: list[str] | None, - alt_zeros: bool = False, -) -> None: - """Process a JDex that is a series of flat files.""" - area_re = re.compile( - "0([0-9])\\.00 (.+?)( area management)?( index)?(\\.md)?" - if alt_zeros - else "([0-9])0\\.00 (.+?)( area management)?( index)?(\\.md)?", - flags=re.IGNORECASE, - ) - category_re = re.compile( - # We need to tolerate the "area management" suffix for a category as well, to create categories from e.g. `01.00 Life Admin Area Management` - "([0-9][0-9])\\.00 (.+?)( (category|area) management)?( index)?(\\.md)?" - if alt_zeros - else "([0-9][1-9])\\.00 (.+?)( category management)?( index)?(\\.md)?", - flags=re.IGNORECASE, - ) - - for jid in files: - if _entry_is_ignored(ignored, [], jid): - continue - - file = File(name=jid.name, full_path=jid.path, nested_under=[]) - - # Check if the file matches an area - area_match = area_re.fullmatch(jid.name) - if area_match: - _insert_append( - area_match.group(1), - (area_match.group(2), file), - jdex.areas, - ) - - # Check if the file matches a category - cat_match = category_re.fullmatch(jid.name) - if cat_match: - _insert_append( - cat_match.group(1), - (cat_match.group(2), file), - jdex.categories, - ) - - # Check if it's a header match for alt zeros - header_match = jdex_note_header_re.fullmatch(jid.name) - if header_match: - _insert_append( - header_match.group(1), - (header_match.group(2), file), - jdex.headers, - ) - continue +def _insert_concat_sorted(k, vs: list, d, key=None) -> None: # noqa: ANN001 + """Add value as a singleton if it's not already in the dict, else append it to the list.""" + if k not in d: + d.update({k: []}) - # The file should also be a valid ID (or is bad) - id_match = jdex_note_generic_id_re.fullmatch(jid.name) - if id_match: - _insert_append( - f"{id_match.group(1)}.{id_match.group(2)}", - (id_match.group(3), file), - jdex.ids, - ) - else: - jdex.errors.append( - JDexError(error=JDexInvalidIDName(), files=[file]), + d[k].extend(vs) + d[k].sort(key=key) + + +def _get_jdex_entries_from_json( + jdex: ConfigSystemJDex, + json: dict, +) -> tuple[dict[str, list[JDexEntry]], list[JDexIssue]]: + accumulated_entries: dict[str, list[JDexEntry]] = {} + accumulated_errors: list[JDexIssue] = [] + for jid, v in json.items(): + _insert_append_sorted( + jid, + JDexEntry( + jdex.entry.build( + {"id": jid, "title": v["title"]}, + ), + None, + ), + accumulated_entries, + key=_sort_jdex_entry, + ) + return (accumulated_entries, accumulated_errors) + + +def _get_jdex_entries_from_text( + jdex: ConfigSystemJDex, + text: str, +) -> tuple[dict[str, list[JDexEntry]], list[JDexIssue]]: + accumulated_entries: dict[str, list[JDexEntry]] = {} + accumulated_errors: list[JDexIssue] = [] + id_regex = re.compile("^\\s*([0-9]{2}(?:[.-][0-9]{2})?) ([^/\\n]+?)\\s*(?:$|/.*)") + + for line in text.splitlines(): + match = id_regex.fullmatch(line) + if match: + _insert_append_sorted( + match.group(1), + JDexEntry( + jdex.entry.build( + {"id": match.group(1), "title": match.group(2)}, + ), + None, + ), + accumulated_entries, + key=_sort_jdex_entry, ) + return (accumulated_entries, accumulated_errors) -def _process_nested_jdex_structure( +def _get_jdex_entries_from_file( path: Path, - jdex: _JDexAccumulator, - root_level_files: list[os.DirEntry], - *, - ignored: list[str] | None, -) -> None: - for area in os.scandir(path): - if _entry_is_ignored(ignored, [], area): - continue - if area.is_file(): - # Maybe we have a flat structure - root_level_files.append(area) - continue + jdex: ConfigSystemJDex, +) -> tuple[dict[str, list[JDexEntry]], list[JDexIssue]]: + # Load file + as_text = Path.read_text(path) + try: + return _get_jdex_entries_from_json(jdex, json.loads(as_text)) + + except json.JSONDecodeError: + # This isn't valid JSON, so it must be plaintext + return _get_jdex_entries_from_text(jdex, as_text) + + +def _get_jdex_entries_here_or_children( + ignored: list[str], + root_path: PurePath, + bound_segments: dict[str, str], + path: os.PathLike, + tier: ConfigJDexTier | ConfigSystemJDex, +) -> tuple[dict[str, list[JDexEntry]], list[JDexIssue]]: + # Compile regexes for children + valid_children = [ + (re.compile(c.format.build_regex(bound_segments)), c) for c in tier.children + ] + valid_notes = [ + (re.compile(n.format.build_regex(bound_segments)), n) for n in tier.notes + ] - # Otherwise, a directory, so nested structure - area_file = File(name=area.name, full_path=area.path, nested_under=[]) - area_match = valid_area_re.fullmatch(area.name) - if not area_match: - jdex.errors.append( - JDexError(error=JDexInvalidAreaName(), files=[area_file]), - ) - continue - _insert_append( - area_match.group(1), - (area_match.group(2), area_file), - jdex.areas, - ) - cat_re = _valid_category_re(area_match.group(1)) - with os.scandir(area.path) as cats_it: - for cat in cats_it: - if _entry_is_ignored(ignored, [area.name], cat): - continue - cat_file = File( - name=cat.name, - full_path=cat.path, - nested_under=[area.name], - ) - if cat.is_file(): - jdex.errors.append( - JDexError( - error=JDexFileOutsideCategory(), - files=[cat_file], + accumulated_entries: dict[str, list[JDexEntry]] = {} + accumulated_errors: list[JDexIssue] = [] + + has_content = False + + def process_dir_entry(x: os.DirEntry) -> None: + for child_format, child in valid_children: + match = child_format.fullmatch(x.name) + if match: + if child.format.forbidden: + accumulated_errors.append( + JDexIssueEncounteredForbiddenFolder( + PurePath(x).relative_to(root_path), + ContentPattern( + child.format.name, + child.format.raw_format, + ), ), ) - continue - - if cat_match := cat_re.fullmatch(cat.name): - _insert_append( - cat_match.group(1), - (cat_match.group(2), cat_file), - jdex.categories, + break + # Is a valid child folder + if x.is_file(): + # This is an error + accumulated_errors.append( + JDexIssueFileWhereFolderExpected( + PurePath(x).relative_to(root_path), + ContentPattern( + child.format.name, + child.format.raw_format, + ), + ), ) - id_re = _jdex_note_id_re(cat_match.group(1)) - with os.scandir(cat.path) as ids_it: - nested_under = [area.name, cat.name] - for jid in ids_it: - if _entry_is_ignored(ignored, nested_under, jid): - continue - id_file = File( - name=jid.name, - full_path=jid.path, - nested_under=nested_under, + break + + # Walk child + (child_entries, child_errors) = _get_jdex_entries_here_or_children( + ignored, + root_path, + {**bound_segments, **match.groupdict()}, + PurePath(x), + child, + ) + for jid, entries in child_entries.items(): + _insert_concat_sorted( + jid, + entries, + accumulated_entries, + key=_sort_jdex_entry, + ) + accumulated_errors.extend(child_errors) + break + else: + for note_format, note in valid_notes: + match = note_format.fullmatch(x.name) + if match: + if note.format.forbidden: + accumulated_errors.append( + JDexIssueEncounteredForbiddenNote( + PurePath(x).relative_to(root_path), + ContentPattern( + note.format.name, + note.format.raw_format, + ), + ), + ) + break + # Is a valid JDex note + if x.is_dir(): + # This is an error + accumulated_errors.append( + JDexIssueFolderWhereNoteExpected( + PurePath(x).relative_to(root_path), + ContentPattern( + note.format.name, + note.format.raw_format, + ), + ), + ) + break + + # Create entry + for jid in note.ids: + _insert_append_sorted( + jid.id.build({**bound_segments, **match.groupdict()}), + JDexEntry( + jid.entry.build( + {**bound_segments, **match.groupdict()}, + ), + PurePath(x).relative_to(root_path), + ), + accumulated_entries, + key=_sort_jdex_entry, + ) + break + else: + # If we got here, it matched no known child/note + if not getattr(tier, "allow_arbitrary_contents", False): + # This is an error + accumulated_errors.append( + JDexIssueArbitraryContentWhereNotAllowed( + PurePath(x).relative_to(root_path), + tuple( + ContentPattern(c.format.name, c.format.raw_format) + for c in tier.children ) - if id_match := id_re.fullmatch(jid.name): - _insert_append( - id_match.group(1), - (id_match.group(2), id_file), - jdex.ids, - ) - elif gen_match := jdex_note_generic_id_re.fullmatch( - jid.name, - ): - jdex.errors.append( - JDexError( - error=JDexIdInWrongCategory( - id_ac=gen_match.group(1), - file_ac=cat_match.group(1), - ), - files=[id_file], - ), - ) - else: - jdex.errors.append( - JDexError( - error=JDexInvalidIDName(), - files=[id_file], - ), - ) - - elif gen_match := generic_category_re.fullmatch(cat.name): - jdex.errors.append( - JDexError( - error=JDexCategoryInWrongArea( - category_area=gen_match.group(1), - file_area=area_match.group(1), + + tuple( + ContentPattern(n.format.name, n.format.raw_format) + for n in tier.notes ), - files=[cat_file], ), ) - else: - jdex.errors.append( - JDexError(error=JDexInvalidCategoryName(), files=[cat_file]), - ) + with os.scandir(path) as contents: + for x in contents: + if _entry_is_ignored(ignored, x): + continue + has_content = True + process_dir_entry(x) -def _get_jdex_entries( - jdex_dir: Path, - *, - ignored: list[str] | None, - alt_zeros: bool = False, -) -> _JDexResults | list[JDexError]: - """Return canonical JDex information or a list of errors for it.""" - if jdex_dir.is_file(): - # Single file JDex - return _process_single_file_jdex(jdex_dir) - - jdex: _JDexAccumulator = _JDexAccumulator() - root_level_files: list[os.DirEntry] = [] - - _process_nested_jdex_structure(jdex_dir, jdex, root_level_files, ignored=ignored) - - if jdex.ids or jdex.errors: - # Not a flat structure, so we need to add all root level files as invalid - jdex.errors.extend( - [ - JDexError( - error=JDexFileOutsideCategory(), - files=[ - File( - name=f.name, - full_path=f.path, - nested_under=[], - ), - ], - ) - for f in root_level_files - ], + if not has_content: + # We have a fully empty JDex folder; it shouldn't exist if it's doing nothing. + accumulated_errors.append( + JDexIssueEmptyFolder(PurePath(path).relative_to(root_path)), + ) + return (accumulated_entries, accumulated_errors) + + +def _process_jdex( + ignored: list[str], + jdex: ConfigSystemJDex, +) -> tuple[dict[str, list[JDexEntry]], list[JDexIssue]]: + # We need to first see if we have a single file, or a folder + if not getattr(jdex, "entry", False): + # Normal note-based JDex + (jdex_entries_by_id, jdex_errors) = _get_jdex_entries_here_or_children( + ignored + jdex.ignore, + jdex.path, + {}, + jdex.path, + jdex, ) - else: - # Nothing nested, and not a file, so assume a flat structure - _process_flat_jdex_structure( - root_level_files, + # Single file JDex + (jdex_entries_by_id, jdex_errors) = _get_jdex_entries_from_file( + jdex.path, jdex, - ignored=ignored, - alt_zeros=alt_zeros, ) - # These duplicate errors apply regardless of JDex type - jdex.errors.extend(_error_if_dups(JDexDuplicateArea, JDexError, jdex.areas)) - jdex.errors.extend( - _error_if_dups(JDexDuplicateCategory, JDexError, jdex.categories), - ) - jdex.errors.extend(_error_if_dups(JDexDuplicateId, JDexError, jdex.ids)) - jdex.errors.extend(_error_if_dups(JDexDuplicateAreaHeader, JDexError, jdex.headers)) - - for header, files in jdex.headers.items(): - if header not in jdex.areas: - jdex.errors.append( - JDexError( - error=JDexAreaHeaderWithoutArea(area=header), - files=[f for (_, f) in files], - ), - ) - elif len(files) == 1 and files[0][0] != jdex.areas[header][0][0]: - jdex.errors.append( - JDexError( - error=JDexAreaHeaderDifferentFromArea( - area=header, - jdex_name=f"{_print_area(header)} {jdex.areas[header][0][0]}", - ), - files=[f for (_, f) in files], - ), - ) - - if jdex.errors: - return jdex.errors - return _JDexResults( - areas={k: f"{_print_area(k)} {v[0][0]}" for k, v in jdex.areas.items()}, - categories={k: f"{k} {v[0][0]}" for k, v in jdex.categories.items()}, - ids={k: f"{k} {v[0][0]}" for k, v in jdex.ids.items()}, + # Check for duplicate ids + duplicate_id_errors = [ + JDexIssueDuplicateID( + ns[0].path, + tuple(n.path for n in ns), + jid, + ) + for jid, ns in jdex_entries_by_id.items() + if len(ns) != 1 + ] + return ( + jdex_entries_by_id, + jdex_errors + duplicate_id_errors, ) -def lint_dir( - path: Path, - ignored: list[str] | None = None, -) -> LintResults: - """Check a root of a JD system for issues.""" - errors: list[Error] = [] - used_areas: dict[str, list[tuple[str, File]]] = {} - used_categories: dict[str, list[tuple[str, File]]] = {} - used_ids: dict[str, list[tuple[str, File]]] = {} - - def check_inbox(nested_under: list[str], f: os.DirEntry) -> None: - if inbox_re.fullmatch(f.name): - entries = len(os.listdir(f.path)) - if entries: - errors.append( - Error( - error=NonemptyInbox(num_items=entries), - files=[ - File( - name=f.name, - full_path=f.path, - nested_under=nested_under, +def _process_system_level_and_children( + by_id_dict: dict[str, list[tuple[str | None, PurePath]]], + ignored: list[str], + root_path: PurePath, + bound_segments: dict[str, str], + path: os.PathLike, + tier: ConfigSystemRoot | ConfigSystemTier, +) -> tuple[dict[str, list[SystemFolder | SystemFile]], list[Issue]]: + # Compile regexes for children + valid_children = [ + (re.compile(c.format.build_regex(bound_segments)), c) for c in tier.children + ] + accumulated_errors = [] + accumulated_structure = {} + has_content = False + content_in_should_be_empty = [] + + def process_dir_entry(x: os.DirEntry) -> None: + for child_format, child in valid_children: + match = child_format.fullmatch(x.name) + if match: + if child.format.forbidden: + accumulated_errors.append( + IssueEncounteredForbiddenFolder( + PurePath(x).relative_to(root_path), + ContentPattern( + child.format.name, + child.format.raw_format, ), - ], - ), - ) - - def check_if_out_of_id(file: os.DirEntry, nested_under: list[str]) -> bool: - if file.is_file(): - errors.append( - Error( - error=FileOutsideId(), - files=[ - File( - name=file.name, - full_path=file.path, - nested_under=nested_under, ), - ], - ), - ) - return True - return False - - with os.scandir(path) as areas_it: - for area in areas_it: - if _entry_is_ignored(ignored, [], area) or check_if_out_of_id(area, []): - continue - area_file = File( - name=area.name, - full_path=area.path, - nested_under=[], - ) - area_match = valid_area_re.fullmatch(area.name) - if not area_match: - errors.append( - Error( - error=InvalidAreaName(), - files=[area_file], - ), - ) - continue - # Valid area - _insert_append( - area_match.group(1), - (area_match.group(2), area_file), - used_areas, - ) - cat_re = _valid_category_re(area_match.group(1)) - with os.scandir(area.path) as cats_it: - for cat in cats_it: - if _entry_is_ignored( - ignored, - [area.name], - cat, - ) or check_if_out_of_id(cat, [area.name]): - continue - cat_file = File( - name=cat.name, - full_path=cat.path, - nested_under=[area.name], ) - if cat_match := cat_re.fullmatch(cat.name): - _insert_append( - cat_match.group(1), - (cat_match.group(2), cat_file), - used_categories, - ) - id_re = _valid_id_re(cat_match.group(1)) - with os.scandir(cat.path) as ids_it: - nested_under = [area.name, cat.name] - - for jid in ids_it: - if _entry_is_ignored( - ignored, - nested_under, - jid, - ) or check_if_out_of_id(jid, nested_under): - continue - id_file = File( - name=jid.name, - full_path=jid.path, - nested_under=nested_under, - ) - if id_match := id_re.fullmatch(jid.name): - _insert_append( - id_match.group(1), - (id_match.group(2), id_file), - used_ids, - ) - - check_inbox(nested_under, jid) - elif gen_match := generic_id_re.fullmatch(jid.name): - errors.append( - Error( - error=IdInWrongCategory( - id_ac=gen_match.group( - 1, - ), - file_ac=cat_match.group( - 1, - ), - ), - files=[id_file], - ), - ) - - else: - errors.append( - Error( - error=InvalidIDName(), - files=[id_file], - ), - ) - elif gen_match := generic_category_re.fullmatch(cat.name): - errors.append( - Error( - error=CategoryInWrongArea( - category_area=gen_match.group(1), - file_area=area_match.group(1), - ), - files=[cat_file], + break + # Is a valid child folder + child_id = child.id.build({**bound_segments, **match.groupdict()}) + if not child.no_jdex_entry: + _insert_append_sorted( + child_id, + ( + child.jdex_entry.build( + {**bound_segments, **match.groupdict()}, + ) + if child.jdex_entry + else x.name, + PurePath(x).relative_to(root_path), + ), + by_id_dict, + # Sort duplicates by their path, not their JDex entry + key=lambda e: e[1], + ) + if x.is_file(): + if child.can_be_file: + _insert_append_sorted( + child_id, + SystemFile( + PurePath(x).relative_to(root_path), ), + accumulated_structure, + key=lambda e: e.path, ) else: - errors.append( - Error( - error=InvalidCategoryName(), - files=[cat_file], + # This is an error + accumulated_errors.append( + IssueFileWhereFolderExpected( + PurePath(x).relative_to(root_path), + ContentPattern( + child.format.name, + child.format.raw_format, + ), ), ) + break + + # Walk child + (child_structure, child_errors) = _process_system_level_and_children( + by_id_dict, + ignored, + root_path, + {**bound_segments, **match.groupdict()}, + PurePath(x), + child, + ) + _insert_append_sorted( + child_id, + SystemFolder( + PurePath(x).relative_to(root_path), + child_structure, + ), + accumulated_structure, + key=lambda e: e.path, + ) + accumulated_errors.extend(child_errors) + break + else: + # If we got here, it matched no known child/note + if not getattr(tier, "allow_arbitrary_contents", False): + # If the tier has no children specified, it should be empty + if not tier.children: + content_in_should_be_empty.append( + PurePath(x).relative_to(root_path), + ) + else: + accumulated_errors.append( + IssueArbitraryContentWhereNotAllowed( + PurePath(x).relative_to(root_path), + tuple( + ContentPattern(c.format.name, c.format.raw_format) + for c in tier.children + ), + ), + ) - errors.extend(_error_if_dups(DuplicateArea, Error, used_areas)) - errors.extend(_error_if_dups(DuplicateCategory, Error, used_categories)) - errors.extend(_error_if_dups(DuplicateId, Error, used_ids)) - - return LintResults( - errors=sorted(errors, key=_sort_error), - used_areas=used_areas, - used_categories=used_categories, - used_ids=used_ids, + with os.scandir(path) as contents: + for x in contents: + if _entry_is_ignored(ignored, x): + continue + has_content = True + process_dir_entry(x) + + if content_in_should_be_empty: + accumulated_errors.append( + IssueFolderShouldBeEmpty( + PurePath(path).relative_to(root_path), + tuple(content_in_should_be_empty), + ), + ) + if not has_content and ( + tier.children or getattr(tier, "allow_arbitrary_contents", False) + ): + # We have a fully empty folder; it shouldn't exist if it's doing nothing (unless it should be empty). + accumulated_errors.append( + IssueEmptyFolder(PurePath(path).relative_to(root_path)), + ) + return (accumulated_structure, accumulated_errors) + + +def _process_system_root( + ignored: list[str], + root: ConfigSystemRoot, + jdex: None | dict[str, list[JDexEntry]], +) -> tuple[dict[str, list[SystemFolder | SystemFile]], list[Issue]]: + by_id: dict[str, list[tuple[str | None, PurePath]]] = {} + (root_structure, root_errors) = _process_system_level_and_children( + by_id, + ignored + root.ignore, + root.path, + {}, + root.path, + root, ) + # Check for duplicate IDs + duplicate_id_errors = [ + IssueDuplicateID(fs[0][1], tuple([f[1] for f in fs]), jid) + for jid, fs in by_id.items() + if len(fs) != 1 + ] -def lint_dir_and_jdex( - *, - path: Path, - jdex_path: Path, - ignored: list[str] | None = None, - alt_zeros: bool = False, -) -> tuple[list[Error], list[JDexError]]: - """Check a root of a JD system and its JDex for issues.""" - results = lint_dir(path, ignored) - jdex = _get_jdex_entries(jdex_path, ignored=ignored, alt_zeros=alt_zeros) - if isinstance(jdex, list): - return (results.errors, sorted(jdex, key=_sort_error)) - - errors = results.errors - - for area, files in results.used_areas.items(): - if area not in jdex.areas: - errors.append( - Error( - error=AreaNotInJDex(area=area), - files=[f for (_, f) in files], - ), - ) - elif len(files) == 1 and files[0][1].name != jdex.areas[area]: - errors.append( - Error( - error=AreaDifferentFromJDex( - area=area, - jdex_name=jdex.areas[area], - ), - files=[f for (_, f) in files], - ), - ) - for category, files in results.used_categories.items(): - if category not in jdex.categories: - errors.append( - Error( - error=CategoryNotInJDex(category=category), - files=[f for (_, f) in files], - ), - ) - elif len(files) == 1 and files[0][1].name != jdex.categories[category]: - errors.append( - Error( - error=CategoryDifferentFromJDex( - category=category, - jdex_name=jdex.categories[category], - ), - files=[f for (_, f) in files], - ), - ) - for jid, files in results.used_ids.items(): - if jid not in jdex.ids: - errors.append( - Error(error=IdNotInJDex(id=jid), files=[f for (_, f) in files]), - ) - elif len(files) == 1 and files[0][1].name != jdex.ids[jid]: - errors.append( - Error( - error=IdDifferentFromJDex(id=jid, jdex_name=jdex.ids[jid]), - files=[f for (_, f) in files], - ), - ) - return (sorted(errors, key=_sort_error), []) + # If we have a JDex, we can do some additional checks + id_errors = [] + if jdex is not None: + for jid, fs in by_id.items(): + if jid not in jdex: + id_errors.append(IssueIDNotInJDex(fs[0][1], jid)) + else: + jdex_entries = [n.entry for n in jdex[jid]] + for expected_jdex_entry, f in fs: + if expected_jdex_entry and expected_jdex_entry not in jdex_entries: + id_errors.append( + IssueIDDifferentFromJDex( + f, + jid, + expected_jdex_entry, + jdex[jid], + ), + ) + return (root_structure, root_errors + duplicate_id_errors + id_errors) -def _print_area(d: str) -> str: - """Given the number of an area, pretty-print it.""" - return f"{d}0-{d}9" +def lint_system(config: Config) -> LintResults: + """Given a valid jdlint config, lint the specified system and return results.""" + jdex_errors = [] + jdex_entries = {} + if config.system.jdex: + (jdex_entries, jdex_errors) = _process_jdex( + config.linter.ignore, + config.system.jdex, + ) + roots = {} + ignored_errors = 0 + for root in config.system.roots: + (root_structure, root_errors) = _process_system_root( + config.linter.ignore, + root, + jdex_entries if config.system.jdex else None, + ) + ignored_errors += sum( + 1 for e in root_errors if e.type in config.linter.disable_rules + ) + root_errors = [ + e for e in root_errors if e.type not in config.linter.disable_rules + ] + roots[root.name] = RootLintResults( + sorted(root_errors, key=_sort_error), + root.path, + root_structure, + ) -def _print_nest(f: File) -> str: - """Pretty-print a nested file.""" - if f.nested_under: - return str(PurePath(*f.nested_under, f.name)) - return f.name + ignored_jdex_errors = sum( + 1 for e in jdex_errors if e.type in config.linter.disable_rules + ) + + return LintResults( + JDexLintResults( + sorted( + [e for e in jdex_errors if e.type not in config.linter.disable_rules], + key=_sort_jdex_error, + ), + config.system.jdex.path, + jdex_entries, + ) + if config.system.jdex + else None, + roots, + ignored_errors + ignored_jdex_errors, + ) + + +def _pluralize(num: int, word: str, weird_plural: str | None = None) -> str: + if num == 1: + return f"{num!s} {word}" + if weird_plural is None: + return f"{num!s} {word}s" + return f"{num!s} {weird_plural}" if __name__ == "__main__": @@ -1324,15 +1708,11 @@ def _print_nest(f: File) -> str: description="Ensure that your Johnny Decimal system is neat and clean", ) parser.add_argument( - "path", - metavar="ROOT_PATH", - help='The root of a JD file structure; should contain folders called e.g. "10-19 Life Admin"', - ) - parser.add_argument( - "--jdex", - "--index", - metavar="JDEX_FILES", - help="Folder containing your JDex/index notes", + "-c", + "--config", + metavar="CONFIG_FILE_PATH", + default="./jdlint.toml", + help="Path to jdlint config file (default ./jdlint.toml)", ) parser.add_argument( "-i", @@ -1350,7 +1730,7 @@ def _print_nest(f: File) -> str: action="append", metavar="RULE_TO_DISABLE", default=[], - help="A rule to disable by name, e.g. NONEMPTY_INBOX", + help="A rule to disable by name, e.g. DUPLICATE_ID", ) parser.add_argument( "-j", @@ -1358,98 +1738,109 @@ def _print_nest(f: File) -> str: dest="json", action="store_const", const=True, - help="Output as machine-readable JSON", - ) - parser.add_argument( - "--altzeros", - dest="altzeros", - action="store_const", - const=True, - help="Specify use of the alternative standard zeros layout; see the README for more info", + help="Override config file to output machine-readable JSON", ) args = parser.parse_args() - # Get all errors - if args.jdex: - (errors, jdex_errors) = lint_dir_and_jdex( - path=Path(args.path), - jdex_path=Path(args.jdex), - ignored=args.ignored, - alt_zeros=args.altzeros, - ) - else: - errors = (lint_dir(args.path, args.ignored)).errors - jdex_errors = [] + with Path.open(args.config, "rb") as config_file: + config = Config(tomllib.load(config_file)) - # Filter disabled errors - errors = [e for e in errors if e.type() not in args.disable] - jdex_errors = [e for e in jdex_errors if e.type() not in args.disable] + if args.json: + config.linter.json_output = True + config.linter.ignore.extend(args.ignored) + for r in args.disable: + if r in [e.type for e in typing.get_args(AnyIssueType)]: + continue + err = ConfigValueError("--disable", "not a valid rule name", r) + raise err - # If there were issues - if errors or jdex_errors: - # Dump to JSON if asked - if args.json: - json.dump( - {"errors": errors, "jdex_errors": jdex_errors}, - sys.stdout, - cls=_EnhancedJSONEncoder, - ) + config.linter.disable_rules.extend(args.disable) - # Or print them out - else: - # Group errors by type and then by type details - # Since all explanations are identical, there's no reason to print them multiple times - jdex_errs_by_type: dict[str, dict[JDexErrorType, list[JDexError]]] = {} - for je in jdex_errors: - if je.error.type not in jdex_errs_by_type: - jdex_errs_by_type.update({je.error.type: {}}) - _insert_append(je.error, je, jdex_errs_by_type[je.error.type]) - - errs_by_type: dict[str, dict[ErrorType, list[Error]]] = {} - for e in errors: - if e.error.type not in errs_by_type: - errs_by_type.update({e.error.type: {}}) - _insert_append(e.error, e, errs_by_type[e.error.type]) + # We have a valid config; now run the linter + results = lint_system(config) + + # Dump to JSON if asked + if config.linter.json_output: + json.dump( + results, + sys.stdout, + cls=_EnhancedJSONEncoder, + ) + any_errors = False + + # If there were issues + if not config.linter.json_output: + if results.jdex: + jdex_errs_by_type: dict[JDexIssueType, list[JDexIssue]] = {} + for je in results.jdex.errors if results.jdex else []: + _insert_append_sorted( + je.type, + je, + jdex_errs_by_type, + key=_sort_jdex_error, + ) # Print JDex errors if any - if jdex_errors: - print("JDex errors found:") - for je_type in jdex_errs_by_type.values(): - first_j_err = next(iter(je_type.keys())) # Just get the first error + if jdex_errs_by_type: + any_errors = True + total_errs = sum(len(errs) for errs in jdex_errs_by_type.values()) + print( + f"{'':=^80}\n{'JDex Errors Found:':^80}\n{_pluralize(total_errs, 'instance') + '; ' + _pluralize(len(jdex_errs_by_type), 'kind'):^80}\n{'':=^80}\n", + ) + for errs in jdex_errs_by_type.values(): + first_j_err = next(iter(errs)) # Just get the first error explanation = first_j_err.explain() - print(f"\n{explanation.explanation} ({first_j_err.type})") - print( - "\n".join( - [ - " " + e.display() - for jes in je_type.values() - for e in jes - ], - ), + print( # noqa: T201 + f"{first_j_err.type + ' (' + str(len(errs)) + ')':^80}\n{explanation.explanation}\n---", ) - print(explanation.fix) - print("\n") - - # Print file errors if any - if errors: - print("Errors found:") - for e_type in errs_by_type.values(): - first_err = next(iter(e_type.keys())) # Just get the first error - explanation = first_err.explain() - print(f"\n{explanation.explanation} ({first_err.type})") - print( - "\n".join( - [" " + e.display() for es in e_type.values() for e in es], + print( # noqa: T201 + textwrap.indent( + "\n".join( + [e.display() for e in errs], + ), + " ", ), ) - print(explanation.fix) - print("\n") + print(f"---\n{explanation.fix}\n") # noqa: T201 + + # Print file errors if any + if any(r.errors for r in results.roots.values()): + any_errors = True + for location, root in results.roots.items(): + errs_by_type: dict[IssueType, list[Issue]] = {} + if root.errors: + errs_by_type = {} + for e in root.errors: + _insert_append_sorted(e.type, e, errs_by_type, key=_sort_error) + total_errs = sum(len(errs) for errs in errs_by_type.values()) + print( # noqa: T201 + f"{'':=^80}\n{location + ' Errors Found:':^80}\n{_pluralize(total_errs, 'instance') + '; ' + _pluralize(len(errs_by_type), 'kind'):^80}\n{'':=^80}\n", + ) + for errs in errs_by_type.values(): + first_err = next(iter(errs)) # Just get the first error + explanation = first_err.explain() + print( # noqa: T201 + f"{first_err.type + ' (' + str(len(errs)) + ')':^80}\n{explanation.explanation}\n---", + ) + print( # noqa: T201 + textwrap.indent( + "\n".join( + [e.display() for e in errs], + ), + " ", + ), + ) + print(f"---\n{explanation.fix}\n") # noqa: T201 + if results.ignored_errs: + print( # noqa: T201 + f"{'':=^80}\n{'Ignored Errors: ' + str(results.ignored_errs):^80}\n{'':=^80}", + ) + if any_errors: # Exit unhappily sys.exit(1) - # If we're here, there were no issues - print("Everything looks good!") - + if not config.linter.json_output: + print("Everything looks good!") # noqa: T201 sys.exit(0) diff --git a/run_tests.py b/run_tests.py index d3d88b4..ec1aae9 100755 --- a/run_tests.py +++ b/run_tests.py @@ -4,98 +4,51 @@ from __future__ import annotations -import dataclasses +import contextlib import json import os import unittest from pathlib import Path, PurePath -from typing import Any - -import jdlint +import tomllib -def _convert_err(e: jdlint.Error | jdlint.JDexError) -> dict[str, Any]: - return { - "error": dataclasses.asdict(e.error) # type: ignore[arg-type] - if dataclasses.is_dataclass(e.error) - else e.error, - "files": [ - # Strip full_path, since it's dependent on where we're running the test - {"name": f.name, "nested_under": f.nested_under} - for f in e.files - ], - } +import jdlint class AllTests(unittest.TestCase): """Locate and run all tests.""" - def tests_without_jdex(self) -> None: - """Locate and run tests that don't require the jdex.""" + def tests(self) -> None: + """Locate and run all tests.""" self.maxDiff = None # Show full diff # Find all tests - with os.scandir(PurePath("tests", "without_jdex")) as test_it: + with os.scandir(PurePath("tests")) as test_it: for f in test_it: - # Make a subtest and open result file - with self.subTest(msg=f.name, f=f), Path( - f, - "result.json", - ).open() as golden_file: - # Get ignore file if any - try: - ignore = Path(f, "ignore").read_text().splitlines() - except FileNotFoundError: - ignore = [] - - # Lint the test dir - results = jdlint.lint_dir( - Path(f, "files"), - ignored=ignore, - ) + # Make a sub-test and open result file + with ( + self.subTest(msg=f.name, f=f), + Path( + f, + "result.json", + ).open() as golden_file, + Path(f, "jdlint.toml").open("rb") as config_file, + contextlib.chdir(f), + ): + # Load config + config = jdlint.Config(tomllib.load(config_file)) + + # Lint the test directory + results = jdlint.lint_system(config) expected = json.load(golden_file) # Convert lint results into loaded format - actual = { - "errors": [_convert_err(e) for e in results.errors], - "jdex_errors": [], - } - - # Compare results - self.assertEqual(expected, actual) # noqa: PT009 - - def tests_with_jdex(self) -> None: - """Locate and run tests that have the JDex.""" - self.maxDiff = None # Show full diff - - # Find all tests - with os.scandir(PurePath("tests", "with_jdex")) as test_it: - for f in test_it: - # Make a subtest and open result file - with self.subTest(msg=f.name, f=f), Path( - f, - "result.json", - ).open() as golden_file: - # Get ignore file if any - try: - ignore = Path(f, "ignore").read_text().splitlines() - except FileNotFoundError: - ignore = [] - - # Lint the test dir and JDex - (errors, jdex_errors) = jdlint.lint_dir_and_jdex( - path=Path(f, "files"), - jdex_path=Path(f, "jdex"), - ignored=ignore, - alt_zeros=Path(f, "altzeros").exists(), + actual = json.loads( + json.dumps( + results, + cls=jdlint._EnhancedJSONEncoder, + ), ) - expected = json.load(golden_file) - - # Convert lint results into loaded format - actual = { - "errors": [_convert_err(e) for e in errors], - "jdex_errors": [_convert_err(e) for e in jdex_errors], - } # Compare results self.assertEqual(expected, actual) # noqa: PT009 diff --git a/tests/with_jdex/area_different_from_jdex_flat/files/00-09 Systme/01 System Stuff/01.02 A Name/.placeholder b/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/1A/.placeholder similarity index 100% rename from tests/with_jdex/area_different_from_jdex_flat/files/00-09 Systme/01 System Stuff/01.02 A Name/.placeholder rename to tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/1A/.placeholder diff --git a/tests/with_jdex/area_different_from_jdex_flat/files/00-09 Systme/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/File similarity index 100% rename from tests/with_jdex/area_different_from_jdex_flat/files/00-09 Systme/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder rename to tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/File diff --git a/tests/with_jdex/area_different_from_jdex_nested/files/00-09 Systme/01 System Stuff/01.02 A Name/.placeholder b/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/Folder/.placeholder similarity index 100% rename from tests/with_jdex/area_different_from_jdex_nested/files/00-09 Systme/01 System Stuff/01.02 A Name/.placeholder rename to tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/Folder/.placeholder diff --git a/tests/with_jdex/area_different_from_jdex_flat/files/00-09 Systme/01 System Stuff/01.03 Another ID/File Inside ID b/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/B1/File similarity index 100% rename from tests/with_jdex/area_different_from_jdex_flat/files/00-09 Systme/01 System Stuff/01.03 Another ID/File Inside ID rename to tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/B1/File diff --git a/tests/with_jdex/area_different_from_jdex_nested/files/00-09 Systme/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/B1/Folder/.placeholder similarity index 100% rename from tests/with_jdex/area_different_from_jdex_nested/files/00-09 Systme/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder rename to tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/B1/Folder/.placeholder diff --git a/tests/with_jdex/area_different_from_jdex_flat/jdex/00.00 System.md b/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/B1/X.md similarity index 100% rename from tests/with_jdex/area_different_from_jdex_flat/jdex/00.00 System.md rename to tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/B1/X.md diff --git a/tests/with_jdex/area_different_from_jdex_flat/jdex/01.00 System Stuff.md b/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/File similarity index 100% rename from tests/with_jdex/area_different_from_jdex_flat/jdex/01.00 System Stuff.md rename to tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/File diff --git a/tests/with_jdex/area_not_in_jdex/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder b/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/Folder/.placeholder similarity index 100% rename from tests/with_jdex/area_not_in_jdex/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder rename to tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/Folder/.placeholder diff --git a/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/jdlint.toml b/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/jdlint.toml new file mode 100644 index 0000000..4186f81 --- /dev/null +++ b/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/jdlint.toml @@ -0,0 +1,28 @@ +[linter] +json_output = true + +[[system.roots]] +name = "Files" +path = "files" + +[[system.default.children]] +name = "A" +format = "/#A/" +id = "/=A/" + +[[system.default.children.children]] +name = "B1" +format = "/*Name//=A/" +id = "/=A/./=Name/" +allow_arbitrary_contents = true + +[[system.default.children.children]] +name = "B2" +id = "/=A/./=Name/" +format = "/=A//*Name/" + +[[system.default.children.children.children]] +name = "C2" +format = "/=A//=Name/" +id = "/=A/./=Name/ Child" +allow_arbitrary_contents = true diff --git a/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/result.json b/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/result.json new file mode 100644 index 0000000..1a7f10e --- /dev/null +++ b/tests/ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/result.json @@ -0,0 +1,107 @@ +{ + "roots": { + "Files": { + "errors": [ + { + "type": "ARBITRARY_CONTENT_WHERE_NOT_ALLOWED", + "file": "1/File", + "possible_formats": [ + { + "name": [ + "A", + "B1" + ], + "format": "/*Name//=A/" + }, + { + "name": [ + "A", + "B2" + ], + "format": "/=A//*Name/" + } + ] + }, + { + "type": "ARBITRARY_CONTENT_WHERE_NOT_ALLOWED", + "file": "1/Folder", + "possible_formats": [ + { + "name": [ + "A", + "B1" + ], + "format": "/*Name//=A/" + }, + { + "name": [ + "A", + "B2" + ], + "format": "/=A//*Name/" + } + ] + }, + { + "type": "ARBITRARY_CONTENT_WHERE_NOT_ALLOWED", + "file": "1/1A/File", + "possible_formats": [ + { + "name": [ + "A", + "B2", + "C2" + ], + "format": "/=A//=Name/" + } + ] + }, + { + "type": "ARBITRARY_CONTENT_WHERE_NOT_ALLOWED", + "file": "1/1A/Folder", + "possible_formats": [ + { + "name": [ + "A", + "B2", + "C2" + ], + "format": "/=A//=Name/" + } + ] + } + ], + "path": "files", + "structure": { + "1": [ + { + "path": "1", + "children": { + "1.A": [ + { + "path": "1/1A", + "children": { + "1.A Child": [ + { + "path": "1/1A/1A", + "children": {} + } + ] + } + } + ], + "1.B": [ + { + "path": "1/B1", + "children": {} + } + ] + } + } + ] + } + } + }, + "jdex": null, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/area_not_in_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/DUPLICATE_ID/files/1/11 A/.placeholder similarity index 100% rename from tests/with_jdex/area_not_in_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder rename to tests/DUPLICATE_ID/files/1/11 A/.placeholder diff --git a/tests/with_jdex/area_not_in_jdex/files/10-19 Oops/11 Cat/11.12 ID/.placeholder b/tests/DUPLICATE_ID/files/1/11 B/.placeholder similarity index 100% rename from tests/with_jdex/area_not_in_jdex/files/10-19 Oops/11 Cat/11.12 ID/.placeholder rename to tests/DUPLICATE_ID/files/1/11 B/.placeholder diff --git a/tests/with_jdex/category_different_from_jdex_flat/files/00-09 System/01 System Stuf/01.02 A Name/.placeholder b/tests/DUPLICATE_ID/files/B1/11 A/.placeholder similarity index 100% rename from tests/with_jdex/category_different_from_jdex_flat/files/00-09 System/01 System Stuf/01.02 A Name/.placeholder rename to tests/DUPLICATE_ID/files/B1/11 A/.placeholder diff --git a/tests/with_jdex/category_different_from_jdex_flat/files/00-09 System/01 System Stuf/01.03 Another ID/Directory Inside Id/.placeholder b/tests/DUPLICATE_ID/files/B1/11 B/.placeholder similarity index 100% rename from tests/with_jdex/category_different_from_jdex_flat/files/00-09 System/01 System Stuf/01.03 Another ID/Directory Inside Id/.placeholder rename to tests/DUPLICATE_ID/files/B1/11 B/.placeholder diff --git a/tests/DUPLICATE_ID/jdlint.toml b/tests/DUPLICATE_ID/jdlint.toml new file mode 100644 index 0000000..6755dd2 --- /dev/null +++ b/tests/DUPLICATE_ID/jdlint.toml @@ -0,0 +1,28 @@ +[linter] +json_output = true + +[[system.roots]] +name = "Files" +path = "files" + +[[system.default.children]] +name = "A" +format = "/#A/" +id = "/=A/" + +[[system.default.children.children]] +name = "B" +format = "/=A//#ID//*Name/" +id = "/=A/./=ID/" +allow_arbitrary_contents = true + +[[system.default.children]] +name = "C" +format = "B/#B/" +id = "/=B/" + +[[system.default.children.children]] +name = "D" +format = "/=B//#ID//*Name/" +id = "/=B/./=ID/" +allow_arbitrary_contents = true diff --git a/tests/DUPLICATE_ID/result.json b/tests/DUPLICATE_ID/result.json new file mode 100644 index 0000000..d7340ac --- /dev/null +++ b/tests/DUPLICATE_ID/result.json @@ -0,0 +1,65 @@ +{ + "roots": { + "Files": { + "errors": [ + { + "type": "DUPLICATE_ID", + "file": "1", + "files": [ + "1", + "B1" + ], + "id": "1" + }, + { + "type": "DUPLICATE_ID", + "file": "1/11 A", + "files": [ + "1/11 A", + "1/11 B", + "B1/11 A", + "B1/11 B" + ], + "id": "1.1" + } + ], + "path": "files", + "structure": { + "1": [ + { + "path": "1", + "children": { + "1.1": [ + { + "path": "1/11 A", + "children": {} + }, + { + "path": "1/11 B", + "children": {} + } + ] + } + }, + { + "path": "B1", + "children": { + "1.1": [ + { + "path": "B1/11 A", + "children": {} + }, + { + "path": "B1/11 B", + "children": {} + } + ] + } + } + ] + } + } + }, + "jdex": null, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/category_different_from_jdex_nested/files/00-09 System/01 System Stuf/01.02 A Name/.placeholder b/tests/EMPTY_FOLDER/files/1/1A/.placeholder similarity index 100% rename from tests/with_jdex/category_different_from_jdex_nested/files/00-09 System/01 System Stuf/01.02 A Name/.placeholder rename to tests/EMPTY_FOLDER/files/1/1A/.placeholder diff --git a/tests/EMPTY_FOLDER/jdlint.toml b/tests/EMPTY_FOLDER/jdlint.toml new file mode 100644 index 0000000..1cf11a9 --- /dev/null +++ b/tests/EMPTY_FOLDER/jdlint.toml @@ -0,0 +1,18 @@ +[linter] +json_output = true +ignore = [".placeholder"] + +[[system.roots]] +name = "Files" +path = "files" + +[[system.default.children]] +name = "A" +format = "/#A/" +id = "/=A/" + +[[system.default.children.children]] +name = "B" +format = "/=A//*Name/" +id = "/=A/./=Name/" +allow_arbitrary_contents = true diff --git a/tests/EMPTY_FOLDER/result.json b/tests/EMPTY_FOLDER/result.json new file mode 100644 index 0000000..c0d3f88 --- /dev/null +++ b/tests/EMPTY_FOLDER/result.json @@ -0,0 +1,30 @@ +{ + "roots": { + "Files": { + "errors": [ + { + "type": "EMPTY_FOLDER", + "file": "1/1A" + } + ], + "path": "files", + "structure": { + "1": [ + { + "path": "1", + "children": { + "1.A": [ + { + "path": "1/1A", + "children": {} + } + ] + } + } + ] + } + } + }, + "jdex": null, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/category_different_from_jdex_nested/files/00-09 System/01 System Stuf/01.03 Another ID/Directory Inside Id/.placeholder b/tests/ENCOUNTERED_FORBIDDEN_FOLDER/files/10-19 Life Admin/11 Me, Myself, & I/11.01 Inbxo/.placeholder similarity index 100% rename from tests/with_jdex/category_different_from_jdex_nested/files/00-09 System/01 System Stuf/01.03 Another ID/Directory Inside Id/.placeholder rename to tests/ENCOUNTERED_FORBIDDEN_FOLDER/files/10-19 Life Admin/11 Me, Myself, & I/11.01 Inbxo/.placeholder diff --git a/tests/with_jdex/area_different_from_jdex_flat/jdex/01.02 A Name.md "b/tests/ENCOUNTERED_FORBIDDEN_FOLDER/files/10-19 Life Admin/11 Me, Myself, & I/11.10 \342\226\240Selves.md" similarity index 100% rename from tests/with_jdex/area_different_from_jdex_flat/jdex/01.02 A Name.md rename to "tests/ENCOUNTERED_FORBIDDEN_FOLDER/files/10-19 Life Admin/11 Me, Myself, & I/11.10 \342\226\240Selves.md" diff --git a/tests/with_jdex/area_different_from_jdex_flat/jdex/01.03 Another ID.md b/tests/ENCOUNTERED_FORBIDDEN_FOLDER/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md similarity index 100% rename from tests/with_jdex/area_different_from_jdex_flat/jdex/01.03 Another ID.md rename to tests/ENCOUNTERED_FORBIDDEN_FOLDER/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md diff --git a/tests/with_jdex/area_different_from_jdex_nested/files/00-09 Systme/01 System Stuff/01.00 An ID/Other File b/tests/ENCOUNTERED_FORBIDDEN_FOLDER/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md similarity index 100% rename from tests/with_jdex/area_different_from_jdex_nested/files/00-09 Systme/01 System Stuff/01.00 An ID/Other File rename to tests/ENCOUNTERED_FORBIDDEN_FOLDER/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md diff --git a/tests/ENCOUNTERED_FORBIDDEN_FOLDER/jdlint.toml b/tests/ENCOUNTERED_FORBIDDEN_FOLDER/jdlint.toml new file mode 100644 index 0000000..13e98cd --- /dev/null +++ b/tests/ENCOUNTERED_FORBIDDEN_FOLDER/jdlint.toml @@ -0,0 +1,46 @@ +[linter] +json_output = true +ignore = [".placeholder"] + +[[system.roots]] +name = "Files" +path = "files" + +[[system.default.children]] +name = "Area" +format = "/#A/0-/=A/9 /*Area/" +id = "/=A/0-/=A/9" + +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" +id = "/=A//=C/" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A//=C/.01 Inbox" +id = "/=A//=C/.01" + +[[system.default.children.children.children]] +name = "Bad Inbox" +format = "/=A//=C/.01 /*Inbox/" +id = "/=A//=C/.01" +forbidden = true + +[[system.default.children.children.children]] +name = "Header" +format = "/=A//=C/./#I/0 β–  /*Header/" +id = "/=A//=C/./=I/0" + +[[system.default.children.children.children]] +name = "Bad Header" +format = "/=A//=C/./#I/0 /*Header/" +id = "/=A//=C/./=I/0" +forbidden = true + +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true +allow_arbitrary_contents = true diff --git a/tests/ENCOUNTERED_FORBIDDEN_FOLDER/result.json b/tests/ENCOUNTERED_FORBIDDEN_FOLDER/result.json new file mode 100644 index 0000000..7987d4c --- /dev/null +++ b/tests/ENCOUNTERED_FORBIDDEN_FOLDER/result.json @@ -0,0 +1,61 @@ +{ + "roots": { + "Files": { + "errors": [ + { + "type": "ENCOUNTERED_FORBIDDEN_FOLDER", + "matched_pattern": { + "name": [ + "Area", + "Category", + "Bad Inbox" + ], + "format": "/=A//=C/.01 /*Inbox/" + }, + "file": "10-19 Life Admin/11 Me, Myself, & I/11.01 Inbxo" + }, + { + "type": "ENCOUNTERED_FORBIDDEN_FOLDER", + "matched_pattern": { + "name": [ + "Area", + "Category", + "Bad Header" + ], + "format": "/=A//=C/./#I/0 /*Header/" + }, + "file": "10-19 Life Admin/11 Me, Myself, & I/11.10 β– Selves.md" + } + ], + "path": "files", + "structure": { + "10-19": [ + { + "path": "10-19 Life Admin", + "children": { + "11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I", + "children": { + "11.11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md" + } + ], + "11.12": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md" + } + ] + } + } + ] + } + } + ] + } + } + }, + "jdex": null, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/area_different_from_jdex_nested/files/00-09 Systme/01 System Stuff/01.03 Another ID/File Inside ID b/tests/FILE_WHERE_FOLDER_EXPECTED/files/1/1A/1A similarity index 100% rename from tests/with_jdex/area_different_from_jdex_nested/files/00-09 Systme/01 System Stuff/01.03 Another ID/File Inside ID rename to tests/FILE_WHERE_FOLDER_EXPECTED/files/1/1A/1A diff --git a/tests/with_jdex/area_different_from_jdex_nested/jdex/00-09 System/01 System Stuff/01.00 An ID.md b/tests/FILE_WHERE_FOLDER_EXPECTED/files/1/1B similarity index 100% rename from tests/with_jdex/area_different_from_jdex_nested/jdex/00-09 System/01 System Stuff/01.00 An ID.md rename to tests/FILE_WHERE_FOLDER_EXPECTED/files/1/1B diff --git a/tests/FILE_WHERE_FOLDER_EXPECTED/jdlint.toml b/tests/FILE_WHERE_FOLDER_EXPECTED/jdlint.toml new file mode 100644 index 0000000..7a09ead --- /dev/null +++ b/tests/FILE_WHERE_FOLDER_EXPECTED/jdlint.toml @@ -0,0 +1,21 @@ +[linter] +json_output = true + +[[system.roots]] +name = "Files" +path = "files" + +[[system.default.children]] +name = "A" +format = "/#A/" +id = "/=A/" + +[[system.default.children.children]] +name = "B" +format = "/=A//*Name/" +id = "/=A/./=Name/" + +[[system.default.children.children.children]] +name = "C" +format = "/=A//=Name/" +id = "/=A/./=Name/F" diff --git a/tests/FILE_WHERE_FOLDER_EXPECTED/result.json b/tests/FILE_WHERE_FOLDER_EXPECTED/result.json new file mode 100644 index 0000000..b28cd64 --- /dev/null +++ b/tests/FILE_WHERE_FOLDER_EXPECTED/result.json @@ -0,0 +1,49 @@ +{ + "roots": { + "Files": { + "errors": [ + { + "type": "FILE_WHERE_FOLDER_EXPECTED", + "file": "1/1B", + "matched_pattern": { + "name": [ + "A", + "B" + ], + "format": "/=A//*Name/" + } + }, + { + "type": "FILE_WHERE_FOLDER_EXPECTED", + "file": "1/1A/1A", + "matched_pattern": { + "name": [ + "A", + "B", + "C" + ], + "format": "/=A//=Name/" + } + } + ], + "path": "files", + "structure": { + "1": [ + { + "path": "1", + "children": { + "1.A": [ + { + "path": "1/1A", + "children": {} + } + ] + } + } + ] + } + } + }, + "jdex": null, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/area_different_from_jdex_nested/jdex/00-09 System/01 System Stuff/01.02 A Name.md b/tests/FOLDER_SHOULD_BE_EMPTY/files/10-19 Life Admin/11 Me, Myself, & I/11.01 Inbox/Content similarity index 100% rename from tests/with_jdex/area_different_from_jdex_nested/jdex/00-09 System/01 System Stuff/01.02 A Name.md rename to tests/FOLDER_SHOULD_BE_EMPTY/files/10-19 Life Admin/11 Me, Myself, & I/11.01 Inbox/Content diff --git a/tests/with_jdex/area_different_from_jdex_nested/jdex/00-09 System/01 System Stuff/01.03 Another ID.md "b/tests/FOLDER_SHOULD_BE_EMPTY/files/10-19 Life Admin/11 Me, Myself, & I/11.10 \342\226\240 Selves/Content" similarity index 100% rename from tests/with_jdex/area_different_from_jdex_nested/jdex/00-09 System/01 System Stuff/01.03 Another ID.md rename to "tests/FOLDER_SHOULD_BE_EMPTY/files/10-19 Life Admin/11 Me, Myself, & I/11.10 \342\226\240 Selves/Content" diff --git a/tests/with_jdex/area_not_in_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID b/tests/FOLDER_SHOULD_BE_EMPTY/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me/Content similarity index 100% rename from tests/with_jdex/area_not_in_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID rename to tests/FOLDER_SHOULD_BE_EMPTY/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me/Content diff --git a/tests/with_jdex/area_not_in_jdex/jdex/00.00 System.md b/tests/FOLDER_SHOULD_BE_EMPTY/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself/Content similarity index 100% rename from tests/with_jdex/area_not_in_jdex/jdex/00.00 System.md rename to tests/FOLDER_SHOULD_BE_EMPTY/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself/Content diff --git a/tests/FOLDER_SHOULD_BE_EMPTY/jdlint.toml b/tests/FOLDER_SHOULD_BE_EMPTY/jdlint.toml new file mode 100644 index 0000000..10b8c43 --- /dev/null +++ b/tests/FOLDER_SHOULD_BE_EMPTY/jdlint.toml @@ -0,0 +1,34 @@ +[linter] +json_output = true +ignore = [".placeholder"] + +[[system.roots]] +name = "Files" +path = "files" + +[[system.default.children]] +name = "Area" +format = "/#A/0-/=A/9 /*Area/" +id = "/=A/0-/=A/9" + +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" +id = "/=A//=C/" + +[[system.default.children.children.children]] +name = "Header" +format = "/=A//=C/./#I/0 β–  /*Header/" +id = "/=A//=C/./=I/0" + +[[system.default.children.children.children]] +name = "Inbox" +format = "/=A//=C/.01 /*Inbox/" +id = "/=A//=C/.01" + +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true +allow_arbitrary_contents = true diff --git a/tests/FOLDER_SHOULD_BE_EMPTY/result.json b/tests/FOLDER_SHOULD_BE_EMPTY/result.json new file mode 100644 index 0000000..41411d2 --- /dev/null +++ b/tests/FOLDER_SHOULD_BE_EMPTY/result.json @@ -0,0 +1,65 @@ +{ + "roots": { + "Files": { + "errors": [ + { + "type": "FOLDER_SHOULD_BE_EMPTY", + "file": "10-19 Life Admin/11 Me, Myself, & I/11.01 Inbox", + "children": [ + "10-19 Life Admin/11 Me, Myself, & I/11.01 Inbox/Content" + ] + }, + { + "type": "FOLDER_SHOULD_BE_EMPTY", + "file": "10-19 Life Admin/11 Me, Myself, & I/11.10 β–  Selves", + "children": [ + "10-19 Life Admin/11 Me, Myself, & I/11.10 β–  Selves/Content" + ] + } + ], + "path": "files", + "structure": { + "10-19": [ + { + "path": "10-19 Life Admin", + "children": { + "11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I", + "children": { + "11.01": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.01 Inbox", + "children": {} + } + ], + "11.10": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.10 β–  Selves", + "children": {} + } + ], + "11.11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.11 Me", + "children": {} + } + ], + "11.12": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myself", + "children": {} + } + ] + } + } + ] + } + } + ] + } + } + }, + "jdex": null, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/area_not_in_jdex/jdex/01.00 System Stuff.md b/tests/ID_DIFFERENT_FROM_JDEX/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me/Content similarity index 100% rename from tests/with_jdex/area_not_in_jdex/jdex/01.00 System Stuff.md rename to tests/ID_DIFFERENT_FROM_JDEX/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me/Content diff --git a/tests/with_jdex/area_not_in_jdex/jdex/01.02 A Name.md b/tests/ID_DIFFERENT_FROM_JDEX/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myslef/Content similarity index 100% rename from tests/with_jdex/area_not_in_jdex/jdex/01.02 A Name.md rename to tests/ID_DIFFERENT_FROM_JDEX/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myslef/Content diff --git a/tests/with_jdex/area_not_in_jdex/jdex/01.03 Another ID.md b/tests/ID_DIFFERENT_FROM_JDEX/jdex/10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md similarity index 100% rename from tests/with_jdex/area_not_in_jdex/jdex/01.03 Another ID.md rename to tests/ID_DIFFERENT_FROM_JDEX/jdex/10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md diff --git a/tests/with_jdex/area_not_in_jdex/jdex/11.00 Cat.md b/tests/ID_DIFFERENT_FROM_JDEX/jdex/10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md similarity index 100% rename from tests/with_jdex/area_not_in_jdex/jdex/11.00 Cat.md rename to tests/ID_DIFFERENT_FROM_JDEX/jdex/10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md diff --git a/tests/with_jdex/area_not_in_jdex/jdex/11.12 ID.md b/tests/ID_DIFFERENT_FROM_JDEX/jdex/10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md similarity index 100% rename from tests/with_jdex/area_not_in_jdex/jdex/11.12 ID.md rename to tests/ID_DIFFERENT_FROM_JDEX/jdex/10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md diff --git a/tests/with_jdex/category_different_from_jdex_flat/files/00-09 System/01 System Stuf/01.03 Another ID/File Inside ID b/tests/ID_DIFFERENT_FROM_JDEX/jdex/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md similarity index 100% rename from tests/with_jdex/category_different_from_jdex_flat/files/00-09 System/01 System Stuf/01.03 Another ID/File Inside ID rename to tests/ID_DIFFERENT_FROM_JDEX/jdex/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md diff --git a/tests/ID_DIFFERENT_FROM_JDEX/jdlint.toml b/tests/ID_DIFFERENT_FROM_JDEX/jdlint.toml new file mode 100644 index 0000000..77dc76e --- /dev/null +++ b/tests/ID_DIFFERENT_FROM_JDEX/jdlint.toml @@ -0,0 +1,67 @@ +[linter] +json_output = true +ignore = [".placeholder"] + +[[system.roots]] +name = "Files" +path = "files" + +[system.jdex] +path = "jdex" + +[[system.jdex.children]] +name = "JDex Area Folder" +format = "/#A/0-/=A/9 /*Area/" + +[[system.jdex.children.children]] +name = "JDex Category Folder" +format = "/=A//#C/ /*Category/" + +[[system.jdex.children.children.notes]] +name = "JDex Area Note" +format = "/=A/0.00 /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/0-/=A/9" +entry = "/=A/0-/=A/9 /=Name/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/0.00" +entry = "/=A/0.00 /=Name/" + +[[system.jdex.children.children.notes]] +name = "JDex Category Note" +format = "/=A//=C/.00 /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/" +entry = "/=A//=C/ /=Name/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/.00" +entry = "/=A//=C/.00 /=Name/" + +[[system.jdex.children.children.notes]] +name = "JDex Id Note" +format = "/=A//=C/./##ID/ /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/./=ID/" +entry = "/=A//=C/./=ID/ /=Name/" + +[[system.default.children]] +name = "Area" +format = "/#A/0-/=A/9 /*Area/" +id = "/=A/0-/=A/9" + +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" +id = "/=A//=C/" + +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true +allow_arbitrary_contents = true diff --git a/tests/ID_DIFFERENT_FROM_JDEX/result.json b/tests/ID_DIFFERENT_FROM_JDEX/result.json new file mode 100644 index 0000000..e28bf46 --- /dev/null +++ b/tests/ID_DIFFERENT_FROM_JDEX/result.json @@ -0,0 +1,92 @@ +{ + "roots": { + "Files": { + "errors": [ + { + "type": "ID_DIFFERENT_FROM_JDEX", + "id": "11.12", + "file": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myslef", + "expected_jdex_entry": "11.12 Myslef", + "known_jdex_entries": [ + { + "entry": "11.12 Myself", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md" + } + ] + } + ], + "path": "files", + "structure": { + "10-19": [ + { + "path": "10-19 Life Admin", + "children": { + "11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I", + "children": { + "11.11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.11 Me", + "children": {} + } + ], + "11.12": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myslef", + "children": {} + } + ] + } + } + ] + } + } + ] + } + } + }, + "ignored_errs": 0, + "jdex": { + "errors": [], + "path": "jdex", + "entries": { + "10-19": [ + { + "entry": "10-19 Life Admin", + "path": "10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md" + } + ], + "10.00": [ + { + "entry": "10.00 Life Admin", + "path": "10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md" + } + ], + "11": [ + { + "entry": "11 Me, Myself, & I", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md" + } + ], + "11.00": [ + { + "entry": "11.00 Me, Myself, & I", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md" + } + ], + "11.11": [ + { + "entry": "11.11 Me", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md" + } + ], + "11.12": [ + { + "entry": "11.12 Myself", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md" + } + ] + } + } +} \ No newline at end of file diff --git a/tests/with_jdex/category_different_from_jdex_flat/jdex/00.00 System.md b/tests/ID_NOT_IN_JDEX/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me/Content similarity index 100% rename from tests/with_jdex/category_different_from_jdex_flat/jdex/00.00 System.md rename to tests/ID_NOT_IN_JDEX/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me/Content diff --git a/tests/with_jdex/category_different_from_jdex_flat/jdex/01.00 System Stuff.md b/tests/ID_NOT_IN_JDEX/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself/Content similarity index 100% rename from tests/with_jdex/category_different_from_jdex_flat/jdex/01.00 System Stuff.md rename to tests/ID_NOT_IN_JDEX/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself/Content diff --git a/tests/with_jdex/category_different_from_jdex_flat/jdex/01.02 A Name.md b/tests/ID_NOT_IN_JDEX/files/10-19 Life Admin/11 Me, Myself, & I/11.13 I/Content similarity index 100% rename from tests/with_jdex/category_different_from_jdex_flat/jdex/01.02 A Name.md rename to tests/ID_NOT_IN_JDEX/files/10-19 Life Admin/11 Me, Myself, & I/11.13 I/Content diff --git a/tests/with_jdex/category_different_from_jdex_flat/jdex/01.03 Another ID.md b/tests/ID_NOT_IN_JDEX/jdex/10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md similarity index 100% rename from tests/with_jdex/category_different_from_jdex_flat/jdex/01.03 Another ID.md rename to tests/ID_NOT_IN_JDEX/jdex/10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md diff --git a/tests/with_jdex/category_different_from_jdex_nested/files/00-09 System/01 System Stuf/01.00 An ID/Other File b/tests/ID_NOT_IN_JDEX/jdex/10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md similarity index 100% rename from tests/with_jdex/category_different_from_jdex_nested/files/00-09 System/01 System Stuf/01.00 An ID/Other File rename to tests/ID_NOT_IN_JDEX/jdex/10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md diff --git a/tests/with_jdex/category_different_from_jdex_nested/files/00-09 System/01 System Stuf/01.03 Another ID/File Inside ID b/tests/ID_NOT_IN_JDEX/jdex/10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md similarity index 100% rename from tests/with_jdex/category_different_from_jdex_nested/files/00-09 System/01 System Stuf/01.03 Another ID/File Inside ID rename to tests/ID_NOT_IN_JDEX/jdex/10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md diff --git a/tests/with_jdex/category_different_from_jdex_nested/jdex/00-09 System/01 System Stuff/01.00 An ID.md b/tests/ID_NOT_IN_JDEX/jdex/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md similarity index 100% rename from tests/with_jdex/category_different_from_jdex_nested/jdex/00-09 System/01 System Stuff/01.00 An ID.md rename to tests/ID_NOT_IN_JDEX/jdex/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md diff --git a/tests/ID_NOT_IN_JDEX/jdlint.toml b/tests/ID_NOT_IN_JDEX/jdlint.toml new file mode 100644 index 0000000..77dc76e --- /dev/null +++ b/tests/ID_NOT_IN_JDEX/jdlint.toml @@ -0,0 +1,67 @@ +[linter] +json_output = true +ignore = [".placeholder"] + +[[system.roots]] +name = "Files" +path = "files" + +[system.jdex] +path = "jdex" + +[[system.jdex.children]] +name = "JDex Area Folder" +format = "/#A/0-/=A/9 /*Area/" + +[[system.jdex.children.children]] +name = "JDex Category Folder" +format = "/=A//#C/ /*Category/" + +[[system.jdex.children.children.notes]] +name = "JDex Area Note" +format = "/=A/0.00 /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/0-/=A/9" +entry = "/=A/0-/=A/9 /=Name/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/0.00" +entry = "/=A/0.00 /=Name/" + +[[system.jdex.children.children.notes]] +name = "JDex Category Note" +format = "/=A//=C/.00 /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/" +entry = "/=A//=C/ /=Name/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/.00" +entry = "/=A//=C/.00 /=Name/" + +[[system.jdex.children.children.notes]] +name = "JDex Id Note" +format = "/=A//=C/./##ID/ /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/./=ID/" +entry = "/=A//=C/./=ID/ /=Name/" + +[[system.default.children]] +name = "Area" +format = "/#A/0-/=A/9 /*Area/" +id = "/=A/0-/=A/9" + +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" +id = "/=A//=C/" + +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true +allow_arbitrary_contents = true diff --git a/tests/ID_NOT_IN_JDEX/result.json b/tests/ID_NOT_IN_JDEX/result.json new file mode 100644 index 0000000..9250445 --- /dev/null +++ b/tests/ID_NOT_IN_JDEX/result.json @@ -0,0 +1,91 @@ +{ + "roots": { + "Files": { + "errors": [ + { + "type": "ID_NOT_IN_JDEX", + "id": "11.13", + "file": "10-19 Life Admin/11 Me, Myself, & I/11.13 I" + } + ], + "path": "files", + "structure": { + "10-19": [ + { + "path": "10-19 Life Admin", + "children": { + "11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I", + "children": { + "11.11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.11 Me", + "children": {} + } + ], + "11.12": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myself", + "children": {} + } + ], + "11.13": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.13 I", + "children": {} + } + ] + } + } + ] + } + } + ] + } + } + }, + "ignored_errs": 0, + "jdex": { + "errors": [], + "path": "jdex", + "entries": { + "10-19": [ + { + "entry": "10-19 Life Admin", + "path": "10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md" + } + ], + "10.00": [ + { + "entry": "10.00 Life Admin", + "path": "10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md" + } + ], + "11": [ + { + "entry": "11 Me, Myself, & I", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md" + } + ], + "11.00": [ + { + "entry": "11.00 Me, Myself, & I", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md" + } + ], + "11.11": [ + { + "entry": "11.11 Me", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md" + } + ], + "11.12": [ + { + "entry": "11.12 Myself", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md" + } + ] + } + } +} \ No newline at end of file diff --git a/tests/with_jdex/category_different_from_jdex_nested/jdex/00-09 System/01 System Stuff/01.02 A Name.md b/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/1.md similarity index 100% rename from tests/with_jdex/category_different_from_jdex_nested/jdex/00-09 System/01 System Stuff/01.02 A Name.md rename to tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/1.md diff --git a/tests/with_jdex/category_different_from_jdex_nested/jdex/00-09 System/01 System Stuff/01.03 Another ID.md b/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/1A.md similarity index 100% rename from tests/with_jdex/category_different_from_jdex_nested/jdex/00-09 System/01 System Stuff/01.03 Another ID.md rename to tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/1A.md diff --git a/tests/with_jdex/category_not_in_jdex/files/00-09 System/01 System Stuff/01.02 An ID/.placeholder b/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/File similarity index 100% rename from tests/with_jdex/category_not_in_jdex/files/00-09 System/01 System Stuff/01.02 An ID/.placeholder rename to tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/File diff --git a/tests/with_jdex/category_not_in_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/Folder/.placeholder similarity index 100% rename from tests/with_jdex/category_not_in_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder rename to tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/1A/Folder/.placeholder diff --git a/tests/with_jdex/category_not_in_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID b/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/B1/File similarity index 100% rename from tests/with_jdex/category_not_in_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID rename to tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/B1/File diff --git a/tests/with_jdex/flat_alt_zeros/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/Directory Inside Id/.placeholder b/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/B1/Folder/.placeholder similarity index 100% rename from tests/with_jdex/flat_alt_zeros/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/Directory Inside Id/.placeholder rename to tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/B1/Folder/.placeholder diff --git a/tests/with_jdex/category_not_in_jdex/jdex/00.00 System.md b/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/B1/X.md similarity index 100% rename from tests/with_jdex/category_not_in_jdex/jdex/00.00 System.md rename to tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/B1/X.md diff --git a/tests/with_jdex/category_not_in_jdex/jdex/01.02 An ID.md b/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/File similarity index 100% rename from tests/with_jdex/category_not_in_jdex/jdex/01.02 An ID.md rename to tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/File diff --git a/tests/with_jdex/flat_alt_zeros/files/10-19 Life Admin/10 Me, Myself, and I/10.02 An ID/.placeholder b/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/Folder/.placeholder similarity index 100% rename from tests/with_jdex/flat_alt_zeros/files/10-19 Life Admin/10 Me, Myself, and I/10.02 An ID/.placeholder rename to tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/files/1/Folder/.placeholder diff --git a/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/jdlint.toml b/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/jdlint.toml new file mode 100644 index 0000000..4b85e08 --- /dev/null +++ b/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/jdlint.toml @@ -0,0 +1,52 @@ +[linter] +json_output = true + +[[system.roots]] +name = "Files" +path = "files" + +[system.jdex] +path = "files" + +[[system.jdex.children]] +name = "A" +format = "/#A/" + +[[system.jdex.children.children]] +name = "B1" +format = "/*Name//=A/" +allow_arbitrary_contents = true + +[[system.jdex.children.children.notes]] +name = "C1" +format = "X.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/./=Name/" +entry = "/=A/./=Name/" + +[[system.jdex.children.children]] +name = "B2" +format = "/=A//*Name/" + +[[system.jdex.children.children.notes]] +name = "C3" +format = "/=A/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/" +entry = "/=A/" + +[[system.jdex.children.children.notes]] +name = "C2" +format = "/=A//=Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/./=Name/" +entry = "/=A/./=Name/" + +[[system.default.children]] +name = "Area" +format = "/#A/" +id = "/=A/" +allow_arbitrary_contents = true diff --git a/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/result.json b/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/result.json new file mode 100644 index 0000000..6b59bd0 --- /dev/null +++ b/tests/JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED/result.json @@ -0,0 +1,126 @@ +{ + "roots": { + "Files": { + "errors": [], + "path": "files", + "structure": { + "1": [ + { + "path": "1", + "children": {} + } + ] + } + } + }, + "jdex": { + "errors": [ + { + "type": "JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED", + "file": "1/File", + "possible_formats": [ + { + "name": [ + "A", + "B1" + ], + "format": "/*Name//=A/" + }, + { + "name": [ + "A", + "B2" + ], + "format": "/=A//*Name/" + } + ] + }, + { + "type": "JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED", + "file": "1/Folder", + "possible_formats": [ + { + "name": [ + "A", + "B1" + ], + "format": "/*Name//=A/" + }, + { + "name": [ + "A", + "B2" + ], + "format": "/=A//*Name/" + } + ] + }, + { + "type": "JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED", + "file": "1/1A/File", + "possible_formats": [ + { + "name": [ + "A", + "B2", + "C3" + ], + "format": "/=A/.md" + }, + { + "name": [ + "A", + "B2", + "C2" + ], + "format": "/=A//=Name/.md" + } + ] + }, + { + "type": "JDEX_ARBITRARY_CONTENT_WHERE_NOT_ALLOWED", + "file": "1/1A/Folder", + "possible_formats": [ + { + "name": [ + "A", + "B2", + "C3" + ], + "format": "/=A/.md" + }, + { + "name": [ + "A", + "B2", + "C2" + ], + "format": "/=A//=Name/.md" + } + ] + } + ], + "path": "files", + "entries": { + "1": [ + { + "entry": "1", + "path": "1/1A/1.md" + } + ], + "1.A": [ + { + "entry": "1.A", + "path": "1/1A/1A.md" + } + ], + "1.B": [ + { + "entry": "1.B", + "path": "1/B1/X.md" + } + ] + } + }, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/category_not_in_jdex/jdex/01.03 Another ID.md b/tests/JDEX_DUPLICATE_ID/files/1/1.md similarity index 100% rename from tests/with_jdex/category_not_in_jdex/jdex/01.03 Another ID.md rename to tests/JDEX_DUPLICATE_ID/files/1/1.md diff --git a/tests/with_jdex/flat_alt_zeros/altzeros b/tests/JDEX_DUPLICATE_ID/files/1/11 A.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros/altzeros rename to tests/JDEX_DUPLICATE_ID/files/1/11 A.md diff --git a/tests/with_jdex/flat_alt_zeros/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/File Inside ID b/tests/JDEX_DUPLICATE_ID/files/1/11 B.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/File Inside ID rename to tests/JDEX_DUPLICATE_ID/files/1/11 B.md diff --git a/tests/JDEX_DUPLICATE_ID/jdlint.toml b/tests/JDEX_DUPLICATE_ID/jdlint.toml new file mode 100644 index 0000000..777d85a --- /dev/null +++ b/tests/JDEX_DUPLICATE_ID/jdlint.toml @@ -0,0 +1,35 @@ +[linter] +json_output = true + +[[system.roots]] +name = "Files" +path = "files" + +[system.jdex] +path = "files" + +[[system.jdex.children]] +name = "A" +format = "/#A/" + +[[system.jdex.children.notes]] +name = "C" +format = "/=A/.md" + +[[system.jdex.children.notes.ids]] +id = "/=A/" +entry = "/=A/" + +[[system.jdex.children.notes]] +name = "B" +format = "/=A//#ID/ /*Name/.md" + +[[system.jdex.children.notes.ids]] +id = "/=A/./=ID/" +entry = "/=A/./=ID/ /=Name/" + +[[system.default.children]] +name = "Area" +format = "/#A/" +id = "/=A/" +allow_arbitrary_contents = true diff --git a/tests/JDEX_DUPLICATE_ID/result.json b/tests/JDEX_DUPLICATE_ID/result.json new file mode 100644 index 0000000..6c8d5da --- /dev/null +++ b/tests/JDEX_DUPLICATE_ID/result.json @@ -0,0 +1,49 @@ +{ + "roots": { + "Files": { + "errors": [], + "path": "files", + "structure": { + "1": [ + { + "path": "1", + "children": {} + } + ] + } + } + }, + "jdex": { + "errors": [ + { + "type": "JDEX_DUPLICATE_ID", + "file": "1/11 A.md", + "files": [ + "1/11 A.md", + "1/11 B.md" + ], + "id": "1.1" + } + ], + "path": "files", + "entries": { + "1": [ + { + "entry": "1", + "path": "1/1.md" + } + ], + "1.1": [ + { + "entry": "1.1 A", + "path": "1/11 A.md" + }, + { + "entry": "1.1 B", + "path": "1/11 B.md" + } + ] + } + }, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/flat_alt_zeros_duplicate_header/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/Directory Inside Id/.placeholder b/tests/JDEX_EMPTY_FOLDER/files/1/1A/.placeholder similarity index 100% rename from tests/with_jdex/flat_alt_zeros_duplicate_header/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/Directory Inside Id/.placeholder rename to tests/JDEX_EMPTY_FOLDER/files/1/1A/.placeholder diff --git a/tests/with_jdex/flat_alt_zeros/jdex/00.00 System Area Management.md b/tests/JDEX_EMPTY_FOLDER/files/1/1B/X.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros/jdex/00.00 System Area Management.md rename to tests/JDEX_EMPTY_FOLDER/files/1/1B/X.md diff --git a/tests/JDEX_EMPTY_FOLDER/jdlint.toml b/tests/JDEX_EMPTY_FOLDER/jdlint.toml new file mode 100644 index 0000000..1787edd --- /dev/null +++ b/tests/JDEX_EMPTY_FOLDER/jdlint.toml @@ -0,0 +1,33 @@ +[linter] +json_output = true +ignore = [".placeholder"] + +[[system.roots]] +name = "Files" +path = "files" + +[system.jdex] +path = "files" + +[[system.jdex.children]] +name = "A" +format = "/#A/" + +[[system.jdex.children.children]] +name = "B" +format = "/=A//*Name/" +allow_arbitrary_contents = true + +[[system.jdex.children.children.notes]] +name = "C1" +format = "X.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/" +entry = "/=A/" + +[[system.default.children]] +name = "Area" +format = "/#A/" +id = "/=A/" +allow_arbitrary_contents = true diff --git a/tests/JDEX_EMPTY_FOLDER/result.json b/tests/JDEX_EMPTY_FOLDER/result.json new file mode 100644 index 0000000..15055ad --- /dev/null +++ b/tests/JDEX_EMPTY_FOLDER/result.json @@ -0,0 +1,34 @@ +{ + "roots": { + "Files": { + "errors": [], + "path": "files", + "structure": { + "1": [ + { + "path": "1", + "children": {} + } + ] + } + } + }, + "jdex": { + "errors": [ + { + "type": "JDEX_EMPTY_FOLDER", + "file": "1/1A" + } + ], + "path": "files", + "entries": { + "1": [ + { + "entry": "1", + "path": "1/1B/X.md" + } + ] + } + }, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/flat_alt_zeros/jdex/01.00 Life Admin Area Management.md b/tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me/Content similarity index 100% rename from tests/with_jdex/flat_alt_zeros/jdex/01.00 Life Admin Area Management.md rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me/Content diff --git a/tests/with_jdex/flat_alt_zeros/jdex/01.03 Area Standard Zero.md b/tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself/Content similarity index 100% rename from tests/with_jdex/flat_alt_zeros/jdex/01.03 Area Standard Zero.md rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself/Content diff --git a/tests/with_jdex/flat_alt_zeros/jdex/10.00 Me, Myself, and I.md b/tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/jdex/10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros/jdex/10.00 Me, Myself, and I.md rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/jdex/10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md diff --git a/tests/with_jdex/flat_alt_zeros/jdex/10.02 An ID.md b/tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/jdex/10-19 Life Admin/10 Managemnt of area 10-19/10.00 Life Admin.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros/jdex/10.02 An ID.md rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/jdex/10-19 Life Admin/10 Managemnt of area 10-19/10.00 Life Admin.md diff --git a/tests/with_jdex/flat_alt_zeros_duplicate_header/altzeros b/tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/jdex/10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_duplicate_header/altzeros rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/jdex/10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md diff --git a/tests/with_jdex/flat_alt_zeros_duplicate_header/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/File Inside ID b/tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/jdex/10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_duplicate_header/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/File Inside ID rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/jdex/10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md diff --git a/tests/with_jdex/flat_alt_zeros_duplicate_header/files/10-19 Life Admin/10 Me, Myself, and I/10.02 An ID/.placeholder b/tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/jdex/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_duplicate_header/files/10-19 Life Admin/10 Me, Myself, and I/10.02 An ID/.placeholder rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/jdex/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md diff --git a/tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/jdlint.toml b/tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/jdlint.toml new file mode 100644 index 0000000..50d3a0e --- /dev/null +++ b/tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/jdlint.toml @@ -0,0 +1,78 @@ +[linter] +json_output = true +ignore = [".placeholder"] + +[[system.roots]] +name = "Files" +path = "files" + +[system.jdex] +path = "jdex" + +[[system.jdex.children]] +name = "JDex Area Folder" +format = "/#A/0-/=A/9 /*Area/" + +[[system.jdex.children.children]] +name = "JDex Area Management Folder" +format = "/=A/0 Management of area /=A/0-/=A/9" + +[[system.jdex.children.children.notes]] +name = "JDex Area Note" +format = "/=A/0.00 /*Name/.md" +jdex_entry = "/=A/0.00 /=Name/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/0-/=A/9" +entry = "/=A/0-/=A/9 /=Name/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/0.00" +entry = "/=A/0.00 /=Name/" + +[[system.jdex.children.children]] +name = "JDex Bad Area Management Folder" +format = "/=A/0 /*AreaManagement/" +forbidden = true + +[[system.jdex.children.children]] +name = "JDex Category Folder" +format = "/=A//#C/ /*Category/" + +[[system.jdex.children.children.notes]] +name = "JDex Category Note" +format = "/=A//=C/.00 /*Name/.md" +jdex_entry = "/=A//=C/.00 /=Name/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/" +entry = "/=A//=C/ /=Name/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/.00" +entry = "/=A//=C/.00 /=Name/" + +[[system.jdex.children.children.notes]] +name = "JDex Id Note" +format = "/=A//=C/./##ID/ /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/./=ID/" +entry = "/=A//=C/./=ID/ /=Name/" + +[[system.default.children]] +name = "Area" +format = "/#A/0-/=A/9 /*Area/" +id = "/=A/0-/=A/9" + +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" +id = "/=A//=C/" + +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true +allow_arbitrary_contents = true diff --git a/tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/result.json b/tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/result.json new file mode 100644 index 0000000..a6d3f24 --- /dev/null +++ b/tests/JDEX_ENCOUNTERED_FORBIDDEN_FOLDER/result.json @@ -0,0 +1,91 @@ +{ + "roots": { + "Files": { + "errors": [], + "path": "files", + "structure": { + "10-19": [ + { + "path": "10-19 Life Admin", + "children": { + "11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I", + "children": { + "11.11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.11 Me", + "children": {} + } + ], + "11.12": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myself", + "children": {} + } + ] + } + } + ] + } + } + ] + } + } + }, + "ignored_errs": 0, + "jdex": { + "errors": [ + { + "type": "JDEX_ENCOUNTERED_FORBIDDEN_FOLDER", + "matched_pattern": { + "name": [ + "JDex Area Folder", + "JDex Bad Area Management Folder" + ], + "format": "/=A/0 /*AreaManagement/" + }, + "file": "10-19 Life Admin/10 Managemnt of area 10-19" + } + ], + "path": "jdex", + "entries": { + "10-19": [ + { + "entry": "10-19 Life Admin", + "path": "10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md" + } + ], + "10.00": [ + { + "entry": "10.00 Life Admin", + "path": "10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md" + } + ], + "11": [ + { + "entry": "11 Me, Myself, & I", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md" + } + ], + "11.00": [ + { + "entry": "11.00 Me, Myself, & I", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md" + } + ], + "11.11": [ + { + "entry": "11.11 Me", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md" + } + ], + "11.12": [ + { + "entry": "11.12 Myself", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md" + } + ] + } + } +} \ No newline at end of file diff --git a/tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/00.00 System Area Management.md b/tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me/Content similarity index 100% rename from tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/00.00 System Area Management.md rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me/Content diff --git a/tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/01.00 Life Admin Area Management.md b/tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself/Content similarity index 100% rename from tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/01.00 Life Admin Area Management.md rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself/Content diff --git a/tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/01.03 Area Standard Zero.md b/tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/jdex/10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/01.03 Area Standard Zero.md rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/jdex/10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md diff --git a/tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/10. Life Admin.md b/tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/jdex/10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/10. Life Admin.md rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/jdex/10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md diff --git a/tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/10. Life Adminn.md b/tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/jdex/10-19 Life Admin/11 Me, Myself, & I/11.01 Inbxo.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/10. Life Adminn.md rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/jdex/10-19 Life Admin/11 Me, Myself, & I/11.01 Inbxo.md diff --git a/tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/10.00 Me, Myself, and I.md b/tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/jdex/10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/10.00 Me, Myself, and I.md rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/jdex/10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md diff --git a/tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/10.02 An ID.md b/tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/jdex/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_duplicate_header/jdex/10.02 An ID.md rename to tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/jdex/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md diff --git a/tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/jdlint.toml b/tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/jdlint.toml new file mode 100644 index 0000000..3e2fe13 --- /dev/null +++ b/tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/jdlint.toml @@ -0,0 +1,80 @@ +[linter] +json_output = true +ignore = [".placeholder"] + +[[system.roots]] +name = "Files" +path = "files" + +[system.jdex] +path = "jdex" + +[[system.jdex.children]] +name = "JDex Area Folder" +format = "/#A/0-/=A/9 /*Area/" + +[[system.jdex.children.children]] +name = "JDex Category Folder" +format = "/=A//#C/ /*Category/" + +[[system.jdex.children.children.notes]] +name = "JDex Area Note" +format = "/=A/0.00 /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/0-/=A/9" +entry = "/=A/0-/=A/9 /=Name/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/0.00" +entry = "/=A/0.00 /=Name/" + +[[system.jdex.children.children.notes]] +name = "JDex Category Note" +format = "/=A//=C/.00 /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/" +entry = "/=A//=C/ /=Name/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/.00" +entry = "/=A//=C/.00 /=Name/" + +[[system.jdex.children.children.notes]] +name = "JDex Inbox" +format = "/=A//=C/.01 Inbox.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/.01" +entry = "/=A//=C/.01 Inbox" + +[[system.jdex.children.children.notes]] +name = "JDex Bad Inbox" +format = "/=A//=C/.01 /*Name/" +forbidden = true + +[[system.jdex.children.children.notes]] +name = "JDex Id Note" +format = "/=A//=C/./##ID/ /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/./=ID/" +entry = "/=A//=C/./=ID/ /=Name/" + +[[system.default.children]] +name = "Area" +format = "/#A/0-/=A/9 /*Area/" +id = "/=A/0-/=A/9" + +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" +id = "/=A//=C/" + +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true +allow_arbitrary_contents = true diff --git a/tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/result.json b/tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/result.json new file mode 100644 index 0000000..6de6d00 --- /dev/null +++ b/tests/JDEX_ENCOUNTERED_FORBIDDEN_NOTE/result.json @@ -0,0 +1,92 @@ +{ + "roots": { + "Files": { + "errors": [], + "path": "files", + "structure": { + "10-19": [ + { + "path": "10-19 Life Admin", + "children": { + "11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I", + "children": { + "11.11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.11 Me", + "children": {} + } + ], + "11.12": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myself", + "children": {} + } + ] + } + } + ] + } + } + ] + } + } + }, + "ignored_errs": 0, + "jdex": { + "errors": [ + { + "type": "JDEX_ENCOUNTERED_FORBIDDEN_NOTE", + "matched_pattern": { + "name": [ + "JDex Area Folder", + "JDex Category Folder", + "JDex Bad Inbox" + ], + "format": "/=A//=C/.01 /*Name/" + }, + "file": "10-19 Life Admin/11 Me, Myself, & I/11.01 Inbxo.md" + } + ], + "path": "jdex", + "entries": { + "10-19": [ + { + "entry": "10-19 Life Admin", + "path": "10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md" + } + ], + "10.00": [ + { + "entry": "10.00 Life Admin", + "path": "10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md" + } + ], + "11": [ + { + "entry": "11 Me, Myself, & I", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md" + } + ], + "11.00": [ + { + "entry": "11.00 Me, Myself, & I", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md" + } + ], + "11.11": [ + { + "entry": "11.11 Me", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md" + } + ], + "11.12": [ + { + "entry": "11.12 Myself", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md" + } + ] + } + } +} \ No newline at end of file diff --git a/tests/with_jdex/flat_alt_zeros_with_headers/altzeros b/tests/JDEX_FILE_WHERE_FOLDER_EXPECTED/files/1/1A/1.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_with_headers/altzeros rename to tests/JDEX_FILE_WHERE_FOLDER_EXPECTED/files/1/1A/1.md diff --git a/tests/with_jdex/flat_alt_zeros_with_headers/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/Directory Inside Id/.placeholder b/tests/JDEX_FILE_WHERE_FOLDER_EXPECTED/files/1/1A/1A.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_with_headers/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/Directory Inside Id/.placeholder rename to tests/JDEX_FILE_WHERE_FOLDER_EXPECTED/files/1/1A/1A.md diff --git a/tests/with_jdex/flat_alt_zeros_with_headers/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/File Inside ID b/tests/JDEX_FILE_WHERE_FOLDER_EXPECTED/files/1/1B similarity index 100% rename from tests/with_jdex/flat_alt_zeros_with_headers/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/File Inside ID rename to tests/JDEX_FILE_WHERE_FOLDER_EXPECTED/files/1/1B diff --git a/tests/JDEX_FILE_WHERE_FOLDER_EXPECTED/jdlint.toml b/tests/JDEX_FILE_WHERE_FOLDER_EXPECTED/jdlint.toml new file mode 100644 index 0000000..e0f6317 --- /dev/null +++ b/tests/JDEX_FILE_WHERE_FOLDER_EXPECTED/jdlint.toml @@ -0,0 +1,39 @@ +[linter] +json_output = true + +[[system.roots]] +name = "Files" +path = "files" + +[system.jdex] +path = "files" + +[[system.jdex.children]] +name = "A" +format = "/#A/" + +[[system.jdex.children.children]] +name = "B" +format = "/=A//*Name/" + +[[system.jdex.children.children.notes]] +name = "C" +format = "/=A/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/" +entry = "/=A/" + +[[system.jdex.children.children.notes]] +name = "C" +format = "/=A//=Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/./=Name/" +entry = "/=A/./=Name/" + +[[system.default.children]] +name = "Area" +format = "/#A/" +id = "/=A/" +allow_arbitrary_contents = true diff --git a/tests/JDEX_FILE_WHERE_FOLDER_EXPECTED/result.json b/tests/JDEX_FILE_WHERE_FOLDER_EXPECTED/result.json new file mode 100644 index 0000000..533e012 --- /dev/null +++ b/tests/JDEX_FILE_WHERE_FOLDER_EXPECTED/result.json @@ -0,0 +1,47 @@ +{ + "roots": { + "Files": { + "errors": [], + "path": "files", + "structure": { + "1": [ + { + "path": "1", + "children": {} + } + ] + } + } + }, + "jdex": { + "errors": [ + { + "type": "JDEX_FILE_WHERE_FOLDER_EXPECTED", + "file": "1/1B", + "matched_pattern": { + "name": [ + "A", + "B" + ], + "format": "/=A//*Name/" + } + } + ], + "path": "files", + "entries": { + "1": [ + { + "entry": "1", + "path": "1/1A/1.md" + } + ], + "1.A": [ + { + "entry": "1.A", + "path": "1/1A/1A.md" + } + ] + } + }, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/flat_alt_zeros_with_headers/files/10-19 Life Admin/10 Me, Myself, and I/10.02 An ID/.placeholder b/tests/JDEX_FOLDER_WHERE_NOTE_EXPECTED/files/1/1A/1.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_with_headers/files/10-19 Life Admin/10 Me, Myself, and I/10.02 An ID/.placeholder rename to tests/JDEX_FOLDER_WHERE_NOTE_EXPECTED/files/1/1A/1.md diff --git a/tests/with_jdex/flat_alt_zeros_with_headers/jdex/00.00 System Area Management.md b/tests/JDEX_FOLDER_WHERE_NOTE_EXPECTED/files/1/1A/1A.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_with_headers/jdex/00.00 System Area Management.md rename to tests/JDEX_FOLDER_WHERE_NOTE_EXPECTED/files/1/1A/1A.md diff --git a/tests/with_jdex/flat_with_index_suffix/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder b/tests/JDEX_FOLDER_WHERE_NOTE_EXPECTED/files/1/1B/1B.md/.placeholder similarity index 100% rename from tests/with_jdex/flat_with_index_suffix/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder rename to tests/JDEX_FOLDER_WHERE_NOTE_EXPECTED/files/1/1B/1B.md/.placeholder diff --git a/tests/JDEX_FOLDER_WHERE_NOTE_EXPECTED/jdlint.toml b/tests/JDEX_FOLDER_WHERE_NOTE_EXPECTED/jdlint.toml new file mode 100644 index 0000000..07f2843 --- /dev/null +++ b/tests/JDEX_FOLDER_WHERE_NOTE_EXPECTED/jdlint.toml @@ -0,0 +1,39 @@ +[linter] +json_output = true + +[[system.roots]] +name = "Files" +path = "files" + +[system.jdex] +path = "files" + +[[system.jdex.children]] +name = "A" +format = "/#A/" + +[[system.jdex.children.children]] +name = "B" +format = "/=A//*Name/" + +[[system.jdex.children.children.notes]] +name = "JDex Note" +format = "/=A/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/" +entry = "/=A/" + +[[system.jdex.children.children.notes]] +name = "JDex Note" +format = "/=A//=Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/./=Name/" +entry = "/=A/./=Name/" + +[[system.default.children]] +name = "Area" +format = "/#A/" +id = "/=A/" +allow_arbitrary_contents = true diff --git a/tests/JDEX_FOLDER_WHERE_NOTE_EXPECTED/result.json b/tests/JDEX_FOLDER_WHERE_NOTE_EXPECTED/result.json new file mode 100644 index 0000000..db8e832 --- /dev/null +++ b/tests/JDEX_FOLDER_WHERE_NOTE_EXPECTED/result.json @@ -0,0 +1,48 @@ +{ + "roots": { + "Files": { + "errors": [], + "path": "files", + "structure": { + "1": [ + { + "path": "1", + "children": {} + } + ] + } + } + }, + "jdex": { + "errors": [ + { + "type": "JDEX_FOLDER_WHERE_NOTE_EXPECTED", + "file": "1/1B/1B.md", + "matched_pattern": { + "name": [ + "A", + "B", + "JDex Note" + ], + "format": "/=A//=Name/.md" + } + } + ], + "path": "files", + "entries": { + "1": [ + { + "entry": "1", + "path": "1/1A/1.md" + } + ], + "1.A": [ + { + "entry": "1.A", + "path": "1/1A/1A.md" + } + ] + } + }, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/flat_alt_zeros_with_headers/jdex/01.00 Life Admin Area Management.md b/tests/can_be_file/files/1/1A/1A similarity index 100% rename from tests/with_jdex/flat_alt_zeros_with_headers/jdex/01.00 Life Admin Area Management.md rename to tests/can_be_file/files/1/1A/1A diff --git a/tests/can_be_file/jdlint.toml b/tests/can_be_file/jdlint.toml new file mode 100644 index 0000000..fc9c740 --- /dev/null +++ b/tests/can_be_file/jdlint.toml @@ -0,0 +1,22 @@ +[linter] +json_output = true + +[[system.roots]] +name = "Files" +path = "files" + +[[system.default.children]] +name = "A" +format = "/#A/" +id = "/=A/" + +[[system.default.children.children]] +name = "B" +format = "/=A//*Name/" +id = "/=A/./=Name/" + +[[system.default.children.children.children]] +name = "C" +format = "/=A//=Name/" +id = "/=A/./=Name/" +can_be_file = true diff --git a/tests/can_be_file/result.json b/tests/can_be_file/result.json new file mode 100644 index 0000000..8677165 --- /dev/null +++ b/tests/can_be_file/result.json @@ -0,0 +1,41 @@ +{ + "roots": { + "Files": { + "errors": [ + { + "type": "DUPLICATE_ID", + "file": "1/1A", + "files": [ + "1/1A", + "1/1A/1A" + ], + "id": "1.A" + } + ], + "path": "files", + "structure": { + "1": [ + { + "path": "1", + "children": { + "1.A": [ + { + "path": "1/1A", + "children": { + "1.A": [ + { + "path": "1/1A/1A" + } + ] + } + } + ] + } + } + ] + } + } + }, + "jdex": null, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/flat_with_index_suffix/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/jdex_entry/files/10-19 Life Admin/10 No JDex/.placeholder similarity index 100% rename from tests/with_jdex/flat_with_index_suffix/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder rename to tests/jdex_entry/files/10-19 Life Admin/10 No JDex/.placeholder diff --git a/tests/with_jdex/flat_alt_zeros_with_headers/jdex/01.03 Area Standard Zero.md b/tests/jdex_entry/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me/Content similarity index 100% rename from tests/with_jdex/flat_alt_zeros_with_headers/jdex/01.03 Area Standard Zero.md rename to tests/jdex_entry/files/10-19 Life Admin/11 Me, Myself, & I/11.11 Me/Content diff --git a/tests/with_jdex/flat_alt_zeros_with_headers/jdex/10. Life Admin.md b/tests/jdex_entry/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myslef/Content similarity index 100% rename from tests/with_jdex/flat_alt_zeros_with_headers/jdex/10. Life Admin.md rename to tests/jdex_entry/files/10-19 Life Admin/11 Me, Myself, & I/11.12 Myslef/Content diff --git a/tests/with_jdex/flat_alt_zeros_with_headers/jdex/10.00 Me, Myself, and I.md b/tests/jdex_entry/jdex/10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_with_headers/jdex/10.00 Me, Myself, and I.md rename to tests/jdex_entry/jdex/10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md diff --git a/tests/with_jdex/flat_alt_zeros_with_headers/jdex/10.02 An ID.md b/tests/jdex_entry/jdex/10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md similarity index 100% rename from tests/with_jdex/flat_alt_zeros_with_headers/jdex/10.02 An ID.md rename to tests/jdex_entry/jdex/10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md diff --git a/tests/with_jdex/flat_with_index_suffix/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID b/tests/jdex_entry/jdex/10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md similarity index 100% rename from tests/with_jdex/flat_with_index_suffix/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID rename to tests/jdex_entry/jdex/10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md diff --git a/tests/with_jdex/flat_with_index_suffix/jdex/00.00 System Index.md b/tests/jdex_entry/jdex/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md similarity index 100% rename from tests/with_jdex/flat_with_index_suffix/jdex/00.00 System Index.md rename to tests/jdex_entry/jdex/10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md diff --git a/tests/jdex_entry/jdlint.toml b/tests/jdex_entry/jdlint.toml new file mode 100644 index 0000000..af1e671 --- /dev/null +++ b/tests/jdex_entry/jdlint.toml @@ -0,0 +1,81 @@ +[linter] +json_output = true +ignore = [".placeholder"] + +[[system.roots]] +name = "Files" +path = "files" + +[system.jdex] +path = "jdex" + +[[system.jdex.children]] +name = "JDex Area Folder" +format = "/#A/0-/=A/9 /*Area/" + +[[system.jdex.children.children]] +name = "JDex Category Folder" +format = "/=A//#C/ /*Category/" + +[[system.jdex.children.children.notes]] +name = "JDex Area Note" +format = "/=A/0.00 /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/0-/=A/9" +entry = "/=A/0-/=A/9 /=Name/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A/0.00" +entry = "/=A/0.00 /=Name/" + +[[system.jdex.children.children.notes]] +name = "JDex Category Note" +format = "/=A//=C/.00 /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/" +entry = "/=A//=C/ /=Name/" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/.00" +entry = "/=A//=C/.00 /=Name/" + +[[system.jdex.children.children.notes]] +name = "JDex Id Note" +format = "/=A//=C/./##ID/ /*Name/.md" + +[[system.jdex.children.children.notes.ids]] +id = "/=A//=C/./=ID/" +entry = "/=A//=C/./=ID/ /=Name/" + +[[system.default.children]] +name = "Area" +format = "/#A/0-/=A/9 /*Area/" +id = "/=A/0-/=A/9" + +[[system.default.children.children]] +name = "10 Category" +format = "10 /*Category/" +id = "10" +no_jdex_entry = true + +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" +id = "/=A//=C/" + +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/.12 Myslef" +id = "/=A//=C/.12" +jdex_entry = "/=A//=C/.12 Myself" +can_be_file = true +allow_arbitrary_contents = true + +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true +allow_arbitrary_contents = true diff --git a/tests/jdex_entry/result.json b/tests/jdex_entry/result.json new file mode 100644 index 0000000..7e7f126 --- /dev/null +++ b/tests/jdex_entry/result.json @@ -0,0 +1,85 @@ +{ + "jdex": { + "errors": [], + "path": "jdex", + "entries": { + "10-19": [ + { + "entry": "10-19 Life Admin", + "path": "10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md" + } + ], + "10.00": [ + { + "entry": "10.00 Life Admin", + "path": "10-19 Life Admin/10 Management of area 10-19/10.00 Life Admin.md" + } + ], + "11": [ + { + "entry": "11 Me, Myself, & I", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md" + } + ], + "11.00": [ + { + "entry": "11.00 Me, Myself, & I", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.00 Me, Myself, & I.md" + } + ], + "11.11": [ + { + "entry": "11.11 Me", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.11 Me.md" + } + ], + "11.12": [ + { + "entry": "11.12 Myself", + "path": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myself.md" + } + ] + } + }, + "roots": { + "Files": { + "errors": [], + "path": "files", + "structure": { + "10-19": [ + { + "path": "10-19 Life Admin", + "children": { + "10": [ + { + "path": "10-19 Life Admin/10 No JDex", + "children": {} + } + ], + "11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I", + "children": { + "11.11": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.11 Me", + "children": {} + } + ], + "11.12": [ + { + "path": "10-19 Life Admin/11 Me, Myself, & I/11.12 Myslef", + "children": {} + } + ] + } + } + ] + } + } + ] + } + } + }, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/flat_with_index_suffix/jdex/01.00 System Stuff Index.md b/tests/json_jdex/files/A01 My life/10-19 Life admin/11 Me/11.01 Birth certificate/Content similarity index 100% rename from tests/with_jdex/flat_with_index_suffix/jdex/01.00 System Stuff Index.md rename to tests/json_jdex/files/A01 My life/10-19 Life admin/11 Me/11.01 Birth certificate/Content diff --git a/tests/with_jdex/flat_with_index_suffix/jdex/01.02 A Name.md b/tests/json_jdex/files/A01 My life/10-19 Life admin/11 Me/11.02 Passpor/Content similarity index 100% rename from tests/with_jdex/flat_with_index_suffix/jdex/01.02 A Name.md rename to tests/json_jdex/files/A01 My life/10-19 Life admin/11 Me/11.02 Passpor/Content diff --git a/tests/with_jdex/flat_with_index_suffix/jdex/01.03 Another ID.md b/tests/json_jdex/files/A01 My life/10-19 Life admin/12 Household/12.01 Insurance policies/Content similarity index 100% rename from tests/with_jdex/flat_with_index_suffix/jdex/01.03 Another ID.md rename to tests/json_jdex/files/A01 My life/10-19 Life admin/12 Household/12.01 Insurance policies/Content diff --git a/tests/with_jdex/flat_with_management_suffixes/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder b/tests/json_jdex/files/A01 My life/10-19 Life admin/12 Household/12.02 Missing/Content similarity index 100% rename from tests/with_jdex/flat_with_management_suffixes/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder rename to tests/json_jdex/files/A01 My life/10-19 Life admin/12 Household/12.02 Missing/Content diff --git a/tests/json_jdex/jdex.jd.json b/tests/json_jdex/jdex.jd.json new file mode 100644 index 0000000..800f10a --- /dev/null +++ b/tests/json_jdex/jdex.jd.json @@ -0,0 +1,41 @@ +{ + "A01": { + "type": "system", + "title": "My life" + }, + "10-19": { + "type": "area", + "title": "Life admin" + }, + "11": { + "type": "category", + "title": "Me" + }, + "11.01": { + "type": "id", + "title": "Birth certificate" + }, + "11.02": { + "type": "id", + "title": "Passport", + "metadata": { + "relatesTo": [ + "11.01" + ], + "expiryDate": "2028-04-15" + } + }, + "12": { + "type": "category", + "title": "Household" + }, + "12.01": { + "type": "id", + "title": "Insurance policies", + "metadata": { + "url": [ + "https://example.com/policy" + ] + } + } +} \ No newline at end of file diff --git a/tests/json_jdex/jdlint.toml b/tests/json_jdex/jdlint.toml new file mode 100644 index 0000000..2d73c5d --- /dev/null +++ b/tests/json_jdex/jdlint.toml @@ -0,0 +1,47 @@ +[linter] +json_output = true +ignore = [".placeholder"] + +[[system.roots]] +name = "Files" +path = "files" + +[system.jdex] +path = "jdex.jd.json" +entry = "/=id/ /=title/" + +[[system.default.children]] +name = "System" +format = "/*SYS/ /*System/" +id = "/=SYS/" + +[[system.default.children.children]] +name = "Area" +format = "/#A/0-/=A/9 /*Area/" +id = "/=A/0-/=A/9" + +[[system.default.children.children.children]] +name = "10 Category" +format = "10 /*Category/" +id = "10" +no_jdex_entry = true + +[[system.default.children.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" +id = "/=A//=C/" + +[[system.default.children.children.children.children]] +name = "ID" +format = "/=A//=C/.12 Myslef" +id = "/=A//=C/.12" +jdex_entry = "/=A//=C/.12 Myself" +can_be_file = true +allow_arbitrary_contents = true + +[[system.default.children.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true +allow_arbitrary_contents = true diff --git a/tests/json_jdex/result.json b/tests/json_jdex/result.json new file mode 100644 index 0000000..41894ec --- /dev/null +++ b/tests/json_jdex/result.json @@ -0,0 +1,129 @@ +{ + "jdex": { + "errors": [], + "path": "jdex.jd.json", + "entries": { + "A01": [ + { + "entry": "A01 My life", + "path": null + } + ], + "10-19": [ + { + "entry": "10-19 Life admin", + "path": null + } + ], + "11": [ + { + "entry": "11 Me", + "path": null + } + ], + "11.01": [ + { + "entry": "11.01 Birth certificate", + "path": null + } + ], + "11.02": [ + { + "entry": "11.02 Passport", + "path": null + } + ], + "12": [ + { + "entry": "12 Household", + "path": null + } + ], + "12.01": [ + { + "entry": "12.01 Insurance policies", + "path": null + } + ] + } + }, + "roots": { + "Files": { + "errors": [ + { + "type": "ID_DIFFERENT_FROM_JDEX", + "id": "11.02", + "file": "A01 My life/10-19 Life admin/11 Me/11.02 Passpor", + "expected_jdex_entry": "11.02 Passpor", + "known_jdex_entries": [ + { + "entry": "11.02 Passport", + "path": null + } + ] + }, + { + "type": "ID_NOT_IN_JDEX", + "id": "12.02", + "file": "A01 My life/10-19 Life admin/12 Household/12.02 Missing" + } + ], + "path": "files", + "structure": { + "A01": [ + { + "path": "A01 My life", + "children": { + "10-19": [ + { + "path": "A01 My life/10-19 Life admin", + "children": { + "11": [ + { + "path": "A01 My life/10-19 Life admin/11 Me", + "children": { + "11.01": [ + { + "path": "A01 My life/10-19 Life admin/11 Me/11.01 Birth certificate", + "children": {} + } + ], + "11.02": [ + { + "path": "A01 My life/10-19 Life admin/11 Me/11.02 Passpor", + "children": {} + } + ] + } + } + ], + "12": [ + { + "path": "A01 My life/10-19 Life admin/12 Household", + "children": { + "12.01": [ + { + "path": "A01 My life/10-19 Life admin/12 Household/12.01 Insurance policies", + "children": {} + } + ], + "12.02": [ + { + "path": "A01 My life/10-19 Life admin/12 Household/12.02 Missing", + "children": {} + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + }, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/flat_with_management_suffixes/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/plaintext_jdex/files/10-19 Life admin/11 Me/11.01 Birth certificate/Content similarity index 100% rename from tests/with_jdex/flat_with_management_suffixes/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder rename to tests/plaintext_jdex/files/10-19 Life admin/11 Me/11.01 Birth certificate/Content diff --git a/tests/with_jdex/flat_with_management_suffixes/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID b/tests/plaintext_jdex/files/10-19 Life admin/11 Me/11.02 Passpor/Content similarity index 100% rename from tests/with_jdex/flat_with_management_suffixes/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID rename to tests/plaintext_jdex/files/10-19 Life admin/11 Me/11.02 Passpor/Content diff --git a/tests/with_jdex/flat_with_management_suffixes/jdex/00.00 System Area Management.md b/tests/plaintext_jdex/files/10-19 Life admin/12 Household/12.01 Insurance policies/Content similarity index 100% rename from tests/with_jdex/flat_with_management_suffixes/jdex/00.00 System Area Management.md rename to tests/plaintext_jdex/files/10-19 Life admin/12 Household/12.01 Insurance policies/Content diff --git a/tests/with_jdex/flat_with_management_suffixes/jdex/01.00 System Stuff Category Management.md b/tests/plaintext_jdex/files/10-19 Life admin/12 Household/12.02 Missing/Content similarity index 100% rename from tests/with_jdex/flat_with_management_suffixes/jdex/01.00 System Stuff Category Management.md rename to tests/plaintext_jdex/files/10-19 Life admin/12 Household/12.02 Missing/Content diff --git a/tests/plaintext_jdex/jdex.txt b/tests/plaintext_jdex/jdex.txt new file mode 100644 index 0000000..0d6d034 --- /dev/null +++ b/tests/plaintext_jdex/jdex.txt @@ -0,0 +1,13 @@ +10-19 Life admin // which I can comment like this + + 11 Me /* or like this */ + /* multiline comments + are allowed on their own lines + */ + 11.01 Birth certificate + - expiryDate: 2028-04-15 + 11.02 Passport + + 12 Household + 12.01 Insurance policies + - url: https://example.com/policy diff --git a/tests/plaintext_jdex/jdlint.toml b/tests/plaintext_jdex/jdlint.toml new file mode 100644 index 0000000..d1d0b34 --- /dev/null +++ b/tests/plaintext_jdex/jdlint.toml @@ -0,0 +1,42 @@ +[linter] +json_output = true +ignore = [".placeholder"] + +[[system.roots]] +name = "Files" +path = "files" + +[system.jdex] +path = "jdex.txt" +entry = "/=id/ /=title/" + +[[system.default.children]] +name = "Area" +format = "/#A/0-/=A/9 /*Area/" +id = "/=A/0-/=A/9" + +[[system.default.children.children]] +name = "10 Category" +format = "10 /*Category/" +id = "10" +no_jdex_entry = true + +[[system.default.children.children]] +name = "Category" +format = "/=A//#C/ /*Category/" +id = "/=A//=C/" + +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/.12 Myslef" +id = "/=A//=C/.12" +jdex_entry = "/=A//=C/.12 Myself" +can_be_file = true +allow_arbitrary_contents = true + +[[system.default.children.children.children]] +name = "ID" +format = "/=A//=C/./##ID/ /*IDName/" +id = "/=A//=C/./=ID/" +can_be_file = true +allow_arbitrary_contents = true diff --git a/tests/plaintext_jdex/result.json b/tests/plaintext_jdex/result.json new file mode 100644 index 0000000..2bd23f0 --- /dev/null +++ b/tests/plaintext_jdex/result.json @@ -0,0 +1,116 @@ +{ + "jdex": { + "errors": [], + "path": "jdex.txt", + "entries": { + "10-19": [ + { + "entry": "10-19 Life admin", + "path": null + } + ], + "11": [ + { + "entry": "11 Me", + "path": null + } + ], + "11.01": [ + { + "entry": "11.01 Birth certificate", + "path": null + } + ], + "11.02": [ + { + "entry": "11.02 Passport", + "path": null + } + ], + "12": [ + { + "entry": "12 Household", + "path": null + } + ], + "12.01": [ + { + "entry": "12.01 Insurance policies", + "path": null + } + ] + } + }, + "roots": { + "Files": { + "errors": [ + { + "type": "ID_DIFFERENT_FROM_JDEX", + "id": "11.02", + "file": "10-19 Life admin/11 Me/11.02 Passpor", + "expected_jdex_entry": "11.02 Passpor", + "known_jdex_entries": [ + { + "entry": "11.02 Passport", + "path": null + } + ] + }, + { + "type": "ID_NOT_IN_JDEX", + "id": "12.02", + "file": "10-19 Life admin/12 Household/12.02 Missing" + } + ], + "path": "files", + "structure": { + "10-19": [ + { + "path": "10-19 Life admin", + "children": { + "11": [ + { + "path": "10-19 Life admin/11 Me", + "children": { + "11.01": [ + { + "path": "10-19 Life admin/11 Me/11.01 Birth certificate", + "children": {} + } + ], + "11.02": [ + { + "path": "10-19 Life admin/11 Me/11.02 Passpor", + "children": {} + } + ] + } + } + ], + "12": [ + { + "path": "10-19 Life admin/12 Household", + "children": { + "12.01": [ + { + "path": "10-19 Life admin/12 Household/12.01 Insurance policies", + "children": {} + } + ], + "12.02": [ + { + "path": "10-19 Life admin/12 Household/12.02 Missing", + "children": {} + } + ] + } + } + ] + } + } + ] + } + } + }, + "ignored_errs": 0 +} \ No newline at end of file diff --git a/tests/with_jdex/area_different_from_jdex_flat/result.json b/tests/with_jdex/area_different_from_jdex_flat/result.json deleted file mode 100644 index b00c81d..0000000 --- a/tests/with_jdex/area_different_from_jdex_flat/result.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "AREA_DIFFERENT_FROM_JDEX", - "area": "0", - "jdex_name": "00-09 System" - }, - "files": [ - { - "name": "00-09 Systme", - "nested_under": [] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/with_jdex/area_different_from_jdex_nested/result.json b/tests/with_jdex/area_different_from_jdex_nested/result.json deleted file mode 100644 index b00c81d..0000000 --- a/tests/with_jdex/area_different_from_jdex_nested/result.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "AREA_DIFFERENT_FROM_JDEX", - "area": "0", - "jdex_name": "00-09 System" - }, - "files": [ - { - "name": "00-09 Systme", - "nested_under": [] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/with_jdex/area_not_in_jdex/result.json b/tests/with_jdex/area_not_in_jdex/result.json deleted file mode 100644 index 8638b38..0000000 --- a/tests/with_jdex/area_not_in_jdex/result.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "AREA_NOT_IN_JDEX", - "area": "1" - }, - "files": [ - { - "name": "10-19 Oops", - "nested_under": [] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/with_jdex/category_different_from_jdex_flat/result.json b/tests/with_jdex/category_different_from_jdex_flat/result.json deleted file mode 100644 index 5411e6e..0000000 --- a/tests/with_jdex/category_different_from_jdex_flat/result.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "CATEGORY_DIFFERENT_FROM_JDEX", - "category": "01", - "jdex_name": "01 System Stuff" - }, - "files": [ - { - "name": "01 System Stuf", - "nested_under": [ - "00-09 System" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/with_jdex/category_different_from_jdex_nested/result.json b/tests/with_jdex/category_different_from_jdex_nested/result.json deleted file mode 100644 index 5411e6e..0000000 --- a/tests/with_jdex/category_different_from_jdex_nested/result.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "CATEGORY_DIFFERENT_FROM_JDEX", - "category": "01", - "jdex_name": "01 System Stuff" - }, - "files": [ - { - "name": "01 System Stuf", - "nested_under": [ - "00-09 System" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/with_jdex/category_not_in_jdex/result.json b/tests/with_jdex/category_not_in_jdex/result.json deleted file mode 100644 index 700977b..0000000 --- a/tests/with_jdex/category_not_in_jdex/result.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "CATEGORY_NOT_IN_JDEX", - "category": "01" - }, - "files": [ - { - "name": "01 System Stuff", - "nested_under": [ - "00-09 System" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/with_jdex/flat_alt_zeros/result.json b/tests/with_jdex/flat_alt_zeros/result.json deleted file mode 100644 index b784b4e..0000000 --- a/tests/with_jdex/flat_alt_zeros/result.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "errors": [], - "jdex_errors": [] -} diff --git a/tests/with_jdex/flat_alt_zeros_duplicate_header/result.json b/tests/with_jdex/flat_alt_zeros_duplicate_header/result.json deleted file mode 100644 index 2ccc67b..0000000 --- a/tests/with_jdex/flat_alt_zeros_duplicate_header/result.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "type": "JDEX_DUPLICATE_AREA_HEADER", - "area": "1" - }, - "files": [ - { - "name": "10. Life Admin.md", - "nested_under": [] - }, - { - "name": "10. Life Adminn.md", - "nested_under": [] - } - ] - } - ] -} diff --git a/tests/with_jdex/flat_alt_zeros_with_headers/result.json b/tests/with_jdex/flat_alt_zeros_with_headers/result.json deleted file mode 100644 index b784b4e..0000000 --- a/tests/with_jdex/flat_alt_zeros_with_headers/result.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "errors": [], - "jdex_errors": [] -} diff --git a/tests/with_jdex/flat_with_index_suffix/result.json b/tests/with_jdex/flat_with_index_suffix/result.json deleted file mode 100644 index b784b4e..0000000 --- a/tests/with_jdex/flat_with_index_suffix/result.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "errors": [], - "jdex_errors": [] -} diff --git a/tests/with_jdex/flat_with_management_suffixes/jdex/01.02 A Name.md b/tests/with_jdex/flat_with_management_suffixes/jdex/01.02 A Name.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/flat_with_management_suffixes/jdex/01.03 Another ID.md b/tests/with_jdex/flat_with_management_suffixes/jdex/01.03 Another ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/flat_with_management_suffixes/result.json b/tests/with_jdex/flat_with_management_suffixes/result.json deleted file mode 100644 index b784b4e..0000000 --- a/tests/with_jdex/flat_with_management_suffixes/result.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "errors": [], - "jdex_errors": [] -} diff --git a/tests/with_jdex/id_different_from_jdex/files/00-09 System/01 System Stuff/01.02 A Naem/.placeholder b/tests/with_jdex/id_different_from_jdex/files/00-09 System/01 System Stuff/01.02 A Naem/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_different_from_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/with_jdex/id_different_from_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_different_from_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID b/tests/with_jdex/id_different_from_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_different_from_jdex/files/00-09 System/01 System Stuff/01.04 An ID/Other File b/tests/with_jdex/id_different_from_jdex/files/00-09 System/01 System Stuff/01.04 An ID/Other File deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_different_from_jdex/jdex/00.00 System.md b/tests/with_jdex/id_different_from_jdex/jdex/00.00 System.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_different_from_jdex/jdex/01.00 System Stuff.md b/tests/with_jdex/id_different_from_jdex/jdex/01.00 System Stuff.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_different_from_jdex/jdex/01.02 A Name.md b/tests/with_jdex/id_different_from_jdex/jdex/01.02 A Name.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_different_from_jdex/jdex/01.03 Another ID.md b/tests/with_jdex/id_different_from_jdex/jdex/01.03 Another ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_different_from_jdex/jdex/01.04 An ID.md b/tests/with_jdex/id_different_from_jdex/jdex/01.04 An ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_different_from_jdex/result.json b/tests/with_jdex/id_different_from_jdex/result.json deleted file mode 100644 index 76f3864..0000000 --- a/tests/with_jdex/id_different_from_jdex/result.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "ID_DIFFERENT_FROM_JDEX", - "id": "01.02", - "jdex_name": "01.02 A Name" - }, - "files": [ - { - "name": "01.02 A Naem", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/with_jdex/id_not_in_jdex/files/00-09 System/01 System Stuff/01.02 Missing ID/.placeholder b/tests/with_jdex/id_not_in_jdex/files/00-09 System/01 System Stuff/01.02 Missing ID/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_not_in_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/with_jdex/id_not_in_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_not_in_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID b/tests/with_jdex/id_not_in_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_not_in_jdex/jdex/00.00 System.md b/tests/with_jdex/id_not_in_jdex/jdex/00.00 System.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_not_in_jdex/jdex/01.00 System Stuff.md b/tests/with_jdex/id_not_in_jdex/jdex/01.00 System Stuff.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_not_in_jdex/jdex/01.03 Another ID.md b/tests/with_jdex/id_not_in_jdex/jdex/01.03 Another ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/id_not_in_jdex/result.json b/tests/with_jdex/id_not_in_jdex/result.json deleted file mode 100644 index 03f764c..0000000 --- a/tests/with_jdex/id_not_in_jdex/result.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "ID_NOT_IN_JDEX", - "id": "01.02" - }, - "files": [ - { - "name": "01.02 Missing ID", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/with_jdex/jdex_area_header_different_from_area/altzeros b/tests/with_jdex/jdex_area_header_different_from_area/altzeros deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_different_from_area/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_area_header_different_from_area/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_different_from_area/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/File Inside ID b/tests/with_jdex/jdex_area_header_different_from_area/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_different_from_area/files/10-19 Life Admin/10 Me, Myself, and I/10.02 An ID/.placeholder b/tests/with_jdex/jdex_area_header_different_from_area/files/10-19 Life Admin/10 Me, Myself, and I/10.02 An ID/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_different_from_area/jdex/00.00 System Area Management.md b/tests/with_jdex/jdex_area_header_different_from_area/jdex/00.00 System Area Management.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_different_from_area/jdex/01.00 Life Admin Area Management.md b/tests/with_jdex/jdex_area_header_different_from_area/jdex/01.00 Life Admin Area Management.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_different_from_area/jdex/01.03 Area Standard Zero.md b/tests/with_jdex/jdex_area_header_different_from_area/jdex/01.03 Area Standard Zero.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_different_from_area/jdex/10. Life Adminn.md b/tests/with_jdex/jdex_area_header_different_from_area/jdex/10. Life Adminn.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_different_from_area/jdex/10.00 Me, Myself, and I.md b/tests/with_jdex/jdex_area_header_different_from_area/jdex/10.00 Me, Myself, and I.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_different_from_area/jdex/10.02 An ID.md b/tests/with_jdex/jdex_area_header_different_from_area/jdex/10.02 An ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_different_from_area/result.json b/tests/with_jdex/jdex_area_header_different_from_area/result.json deleted file mode 100644 index 19e527a..0000000 --- a/tests/with_jdex/jdex_area_header_different_from_area/result.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "type": "JDEX_AREA_HEADER_DIFFERENT_FROM_AREA", - "area": "1", - "jdex_name": "10-19 Life Admin" - }, - "files": [ - { - "name": "10. Life Adminn.md", - "nested_under": [] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_area_header_without_area/altzeros b/tests/with_jdex/jdex_area_header_without_area/altzeros deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_without_area/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_area_header_without_area/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_without_area/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/File Inside ID b/tests/with_jdex/jdex_area_header_without_area/files/00-09 System/01 Life Admin/01.03 Area Standard Zero/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_without_area/files/10-19 Life Admin/10 Me, Myself, and I/10.02 An ID/.placeholder b/tests/with_jdex/jdex_area_header_without_area/files/10-19 Life Admin/10 Me, Myself, and I/10.02 An ID/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_without_area/jdex/00.00 System Area Management.md b/tests/with_jdex/jdex_area_header_without_area/jdex/00.00 System Area Management.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_without_area/jdex/01.00 Life Admin Area Management.md b/tests/with_jdex/jdex_area_header_without_area/jdex/01.00 Life Admin Area Management.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_without_area/jdex/01.03 Area Standard Zero.md b/tests/with_jdex/jdex_area_header_without_area/jdex/01.03 Area Standard Zero.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_without_area/jdex/10. Life Admin.md b/tests/with_jdex/jdex_area_header_without_area/jdex/10. Life Admin.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_without_area/jdex/10.00 Me, Myself, and I.md b/tests/with_jdex/jdex_area_header_without_area/jdex/10.00 Me, Myself, and I.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_without_area/jdex/10.02 An ID.md b/tests/with_jdex/jdex_area_header_without_area/jdex/10.02 An ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_without_area/jdex/20. Digital Stuff.md b/tests/with_jdex/jdex_area_header_without_area/jdex/20. Digital Stuff.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_area_header_without_area/result.json b/tests/with_jdex/jdex_area_header_without_area/result.json deleted file mode 100644 index 20c86c9..0000000 --- a/tests/with_jdex/jdex_area_header_without_area/result.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "type": "JDEX_AREA_HEADER_WITHOUT_AREA", - "area": "2" - }, - "files": [ - { - "name": "20. Digital Stuff.md", - "nested_under": [] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_category_in_wrong_area/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_category_in_wrong_area/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_category_in_wrong_area/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID b/tests/with_jdex/jdex_category_in_wrong_area/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_category_in_wrong_area/jdex/00-09 System/01 System Stuff/01.00 An ID.md b/tests/with_jdex/jdex_category_in_wrong_area/jdex/00-09 System/01 System Stuff/01.00 An ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_category_in_wrong_area/jdex/00-09 System/11 Whoops/11.01 Inbox.md b/tests/with_jdex/jdex_category_in_wrong_area/jdex/00-09 System/11 Whoops/11.01 Inbox.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_category_in_wrong_area/result.json b/tests/with_jdex/jdex_category_in_wrong_area/result.json deleted file mode 100644 index c7a3ed2..0000000 --- a/tests/with_jdex/jdex_category_in_wrong_area/result.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "type": "JDEX_CATEGORY_IN_WRONG_AREA", - "category_area": "1", - "file_area": "0" - }, - "files": [ - { - "name": "11 Whoops", - "nested_under": [ - "00-09 System" - ] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_duplicate_area_flat/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_duplicate_area_flat/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_flat/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID b/tests/with_jdex/jdex_duplicate_area_flat/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_flat/jdex/00.00 A Reuse.md b/tests/with_jdex/jdex_duplicate_area_flat/jdex/00.00 A Reuse.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_flat/jdex/00.00 An Area.md b/tests/with_jdex/jdex_duplicate_area_flat/jdex/00.00 An Area.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_flat/jdex/01.00 A Category.md b/tests/with_jdex/jdex_duplicate_area_flat/jdex/01.00 A Category.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_flat/jdex/01.01 An ID.md b/tests/with_jdex/jdex_duplicate_area_flat/jdex/01.01 An ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_flat/jdex/02.00 An Id.md b/tests/with_jdex/jdex_duplicate_area_flat/jdex/02.00 An Id.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_flat/result.json b/tests/with_jdex/jdex_duplicate_area_flat/result.json deleted file mode 100644 index 367406f..0000000 --- a/tests/with_jdex/jdex_duplicate_area_flat/result.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "area": "0", - "type": "JDEX_DUPLICATE_AREA" - }, - "files": [ - { - "name": "00.00 A Reuse.md", - "nested_under": [] - }, - { - "name": "00.00 An Area.md", - "nested_under": [] - } - ] - }, - { - "error": { - "id": "00.00", - "type": "JDEX_DUPLICATE_ID" - }, - "files": [ - { - "name": "00.00 A Reuse.md", - "nested_under": [] - }, - { - "name": "00.00 An Area.md", - "nested_under": [] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_duplicate_area_header/altzeros b/tests/with_jdex/jdex_duplicate_area_header/altzeros deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_header/files/10-19 An Area/10 A Category/10.02 An Id/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_duplicate_area_header/files/10-19 An Area/10 A Category/10.02 An Id/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_header/files/10-19 An Area/10 A Category/10.02 An Id/File Inside ID b/tests/with_jdex/jdex_duplicate_area_header/files/10-19 An Area/10 A Category/10.02 An Id/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_header/jdex/01.00 An Area.md b/tests/with_jdex/jdex_duplicate_area_header/jdex/01.00 An Area.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_header/jdex/10. A Reuse.md b/tests/with_jdex/jdex_duplicate_area_header/jdex/10. A Reuse.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_header/jdex/10. An Area.md b/tests/with_jdex/jdex_duplicate_area_header/jdex/10. An Area.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_header/jdex/10.00 A Category.md b/tests/with_jdex/jdex_duplicate_area_header/jdex/10.00 A Category.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_header/jdex/10.02 An Id.md b/tests/with_jdex/jdex_duplicate_area_header/jdex/10.02 An Id.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_header/result.json b/tests/with_jdex/jdex_duplicate_area_header/result.json deleted file mode 100644 index c38030c..0000000 --- a/tests/with_jdex/jdex_duplicate_area_header/result.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "area": "1", - "type": "JDEX_DUPLICATE_AREA_HEADER" - }, - "files": [ - { - "name": "10. A Reuse.md", - "nested_under": [] - }, - { - "name": "10. An Area.md", - "nested_under": [] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_duplicate_area_nested/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_duplicate_area_nested/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_nested/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID b/tests/with_jdex/jdex_duplicate_area_nested/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_nested/jdex/00-09 A Reuse/02 Another Category/02.00 An Id b/tests/with_jdex/jdex_duplicate_area_nested/jdex/00-09 A Reuse/02 Another Category/02.00 An Id deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_nested/jdex/00-09 An Area/01 A Category/01.00 An ID b/tests/with_jdex/jdex_duplicate_area_nested/jdex/00-09 An Area/01 A Category/01.00 An ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_area_nested/result.json b/tests/with_jdex/jdex_duplicate_area_nested/result.json deleted file mode 100644 index 1552368..0000000 --- a/tests/with_jdex/jdex_duplicate_area_nested/result.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "area": "0", - "type": "JDEX_DUPLICATE_AREA" - }, - "files": [ - { - "name": "00-09 A Reuse", - "nested_under": [] - }, - { - "name": "00-09 An Area", - "nested_under": [] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_duplicate_category_flat/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_duplicate_category_flat/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_category_flat/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID b/tests/with_jdex/jdex_duplicate_category_flat/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_category_flat/jdex/00.00 An Area.md b/tests/with_jdex/jdex_duplicate_category_flat/jdex/00.00 An Area.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_category_flat/jdex/01.00 A Category.md b/tests/with_jdex/jdex_duplicate_category_flat/jdex/01.00 A Category.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_category_flat/jdex/01.00 A Reuse.md b/tests/with_jdex/jdex_duplicate_category_flat/jdex/01.00 A Reuse.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_category_flat/jdex/01.01 An ID.md b/tests/with_jdex/jdex_duplicate_category_flat/jdex/01.01 An ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_category_flat/jdex/02.00 An Id.md b/tests/with_jdex/jdex_duplicate_category_flat/jdex/02.00 An Id.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_category_flat/result.json b/tests/with_jdex/jdex_duplicate_category_flat/result.json deleted file mode 100644 index 97e94ef..0000000 --- a/tests/with_jdex/jdex_duplicate_category_flat/result.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "category": "01", - "type": "JDEX_DUPLICATE_CATEGORY" - }, - "files": [ - { - "name": "01.00 A Category.md", - "nested_under": [] - }, - { - "name": "01.00 A Reuse.md", - "nested_under": [] - } - ] - }, - { - "error": { - "id": "01.00", - "type": "JDEX_DUPLICATE_ID" - }, - "files": [ - { - "name": "01.00 A Category.md", - "nested_under": [] - }, - { - "name": "01.00 A Reuse.md", - "nested_under": [] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_duplicate_category_nested/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_duplicate_category_nested/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_category_nested/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID b/tests/with_jdex/jdex_duplicate_category_nested/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_category_nested/jdex/00-09 An Area/01 A Category/01.00 An ID b/tests/with_jdex/jdex_duplicate_category_nested/jdex/00-09 An Area/01 A Category/01.00 An ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_category_nested/jdex/00-09 An Area/01 A Reuse/01.02 Another ID b/tests/with_jdex/jdex_duplicate_category_nested/jdex/00-09 An Area/01 A Reuse/01.02 Another ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_category_nested/result.json b/tests/with_jdex/jdex_duplicate_category_nested/result.json deleted file mode 100644 index d349568..0000000 --- a/tests/with_jdex/jdex_duplicate_category_nested/result.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "category": "01", - "type": "JDEX_DUPLICATE_CATEGORY" - }, - "files": [ - { - "name": "01 A Category", - "nested_under": [ - "00-09 An Area" - ] - }, - { - "name": "01 A Reuse", - "nested_under": [ - "00-09 An Area" - ] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_duplicate_id_flat/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_duplicate_id_flat/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_id_flat/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID b/tests/with_jdex/jdex_duplicate_id_flat/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_id_flat/jdex/00.00 An Area.md b/tests/with_jdex/jdex_duplicate_id_flat/jdex/00.00 An Area.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_id_flat/jdex/01.00 A Category.md b/tests/with_jdex/jdex_duplicate_id_flat/jdex/01.00 A Category.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_id_flat/jdex/01.01 A Reuse.md b/tests/with_jdex/jdex_duplicate_id_flat/jdex/01.01 A Reuse.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_id_flat/jdex/01.01 An ID.md b/tests/with_jdex/jdex_duplicate_id_flat/jdex/01.01 An ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_id_flat/result.json b/tests/with_jdex/jdex_duplicate_id_flat/result.json deleted file mode 100644 index e9965a3..0000000 --- a/tests/with_jdex/jdex_duplicate_id_flat/result.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "id": "01.01", - "type": "JDEX_DUPLICATE_ID" - }, - "files": [ - { - "name": "01.01 A Reuse.md", - "nested_under": [] - }, - { - "name": "01.01 An ID.md", - "nested_under": [] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_duplicate_id_nested/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_duplicate_id_nested/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_id_nested/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID b/tests/with_jdex/jdex_duplicate_id_nested/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_id_nested/jdex/00-09 An Area/01 A Category/01.01 A Reuse.md b/tests/with_jdex/jdex_duplicate_id_nested/jdex/00-09 An Area/01 A Category/01.01 A Reuse.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_id_nested/jdex/00-09 An Area/01 A Category/01.01 An ID.md b/tests/with_jdex/jdex_duplicate_id_nested/jdex/00-09 An Area/01 A Category/01.01 An ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_duplicate_id_nested/result.json b/tests/with_jdex/jdex_duplicate_id_nested/result.json deleted file mode 100644 index 52722ac..0000000 --- a/tests/with_jdex/jdex_duplicate_id_nested/result.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "id": "01.01", - "type": "JDEX_DUPLICATE_ID" - }, - "files": [ - { - "name": "01.01 A Reuse.md", - "nested_under": [ - "00-09 An Area", - "01 A Category" - ] - }, - { - "name": "01.01 An ID.md", - "nested_under": [ - "00-09 An Area", - "01 A Category" - ] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_file_outside_category/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder b/tests/with_jdex/jdex_file_outside_category/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_file_outside_category/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_file_outside_category/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_file_outside_category/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID b/tests/with_jdex/jdex_file_outside_category/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_file_outside_category/jdex/00-09 System/01 System Stuff/01.02 A Name.md b/tests/with_jdex/jdex_file_outside_category/jdex/00-09 System/01 System Stuff/01.02 A Name.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_file_outside_category/jdex/00-09 System/01 System Stuff/01.03 Another ID.md b/tests/with_jdex/jdex_file_outside_category/jdex/00-09 System/01 System Stuff/01.03 Another ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_file_outside_category/jdex/00-09 System/Nor here b/tests/with_jdex/jdex_file_outside_category/jdex/00-09 System/Nor here deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_file_outside_category/jdex/Not here b/tests/with_jdex/jdex_file_outside_category/jdex/Not here deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_file_outside_category/result.json b/tests/with_jdex/jdex_file_outside_category/result.json deleted file mode 100644 index 0246b5a..0000000 --- a/tests/with_jdex/jdex_file_outside_category/result.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "type": "JDEX_FILE_OUTSIDE_CATEGORY" - }, - "files": [ - { - "name": "Not here", - "nested_under": [] - } - ] - }, - { - "error": { - "type": "JDEX_FILE_OUTSIDE_CATEGORY" - }, - "files": [ - { - "name": "Nor here", - "nested_under": [ - "00-09 System" - ] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_id_in_wrong_category/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_id_in_wrong_category/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_id_in_wrong_category/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID b/tests/with_jdex/jdex_id_in_wrong_category/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_id_in_wrong_category/jdex/00-09 System/01 System Stuff/01.00 An ID.md b/tests/with_jdex/jdex_id_in_wrong_category/jdex/00-09 System/01 System Stuff/01.00 An ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_id_in_wrong_category/jdex/00-09 System/01 System Stuff/02.00 Whoops.md b/tests/with_jdex/jdex_id_in_wrong_category/jdex/00-09 System/01 System Stuff/02.00 Whoops.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_id_in_wrong_category/result.json b/tests/with_jdex/jdex_id_in_wrong_category/result.json deleted file mode 100644 index edda4f2..0000000 --- a/tests/with_jdex/jdex_id_in_wrong_category/result.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "type": "JDEX_ID_IN_WRONG_CATEGORY", - "id_ac": "02", - "file_ac": "01" - }, - "files": [ - { - "name": "02.00 Whoops.md", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_in_folders/files/00-09 System/01 System Stuff/01.02 A Naem/.placeholder b/tests/with_jdex/jdex_in_folders/files/00-09 System/01 System Stuff/01.02 A Naem/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_in_folders/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_in_folders/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_in_folders/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID b/tests/with_jdex/jdex_in_folders/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_in_folders/jdex/00-09 System/01 System Stuff/01.02 A Name.md b/tests/with_jdex/jdex_in_folders/jdex/00-09 System/01 System Stuff/01.02 A Name.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_in_folders/jdex/00-09 System/01 System Stuff/01.03 Another ID.md b/tests/with_jdex/jdex_in_folders/jdex/00-09 System/01 System Stuff/01.03 Another ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_in_folders/result.json b/tests/with_jdex/jdex_in_folders/result.json deleted file mode 100644 index 76f3864..0000000 --- a/tests/with_jdex/jdex_in_folders/result.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "ID_DIFFERENT_FROM_JDEX", - "id": "01.02", - "jdex_name": "01.02 A Name" - }, - "files": [ - { - "name": "01.02 A Naem", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/with_jdex/jdex_invalid_area_name/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder b/tests/with_jdex/jdex_invalid_area_name/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_area_name/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_invalid_area_name/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_area_name/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID b/tests/with_jdex/jdex_invalid_area_name/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_area_name/jdex/00-09 System/01 System Stuff/01.02 A Name.md b/tests/with_jdex/jdex_invalid_area_name/jdex/00-09 System/01 System Stuff/01.02 A Name.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_area_name/jdex/00-09 System/01 System Stuff/01.03 Another ID.md b/tests/with_jdex/jdex_invalid_area_name/jdex/00-09 System/01 System Stuff/01.03 Another ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_area_name/jdex/10-18 Malformed Numbers/.placeholder b/tests/with_jdex/jdex_invalid_area_name/jdex/10-18 Malformed Numbers/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_area_name/jdex/No Numbers/.placeholder b/tests/with_jdex/jdex_invalid_area_name/jdex/No Numbers/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_area_name/result.json b/tests/with_jdex/jdex_invalid_area_name/result.json deleted file mode 100644 index fc648ac..0000000 --- a/tests/with_jdex/jdex_invalid_area_name/result.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "type": "JDEX_INVALID_AREA_NAME" - }, - "files": [ - { - "name": "10-18 Malformed Numbers", - "nested_under": [] - } - ] - }, - { - "error": { - "type": "JDEX_INVALID_AREA_NAME" - }, - "files": [ - { - "name": "No Numbers", - "nested_under": [] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_invalid_category_name/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder b/tests/with_jdex/jdex_invalid_category_name/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_category_name/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_invalid_category_name/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_category_name/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID b/tests/with_jdex/jdex_invalid_category_name/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_category_name/jdex/00-09 System/01 System Stuff/01.02 A Name.md b/tests/with_jdex/jdex_invalid_category_name/jdex/00-09 System/01 System Stuff/01.02 A Name.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_category_name/jdex/00-09 System/01 System Stuff/01.03 Another ID.md b/tests/with_jdex/jdex_invalid_category_name/jdex/00-09 System/01 System Stuff/01.03 Another ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_category_name/jdex/00-09 System/2 Malformed Numbers/.placeholder b/tests/with_jdex/jdex_invalid_category_name/jdex/00-09 System/2 Malformed Numbers/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_category_name/jdex/00-09 System/No Numbers/.placeholder b/tests/with_jdex/jdex_invalid_category_name/jdex/00-09 System/No Numbers/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_category_name/result.json b/tests/with_jdex/jdex_invalid_category_name/result.json deleted file mode 100644 index 9ff4ed6..0000000 --- a/tests/with_jdex/jdex_invalid_category_name/result.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "type": "JDEX_INVALID_CATEGORY_NAME" - }, - "files": [ - { - "name": "2 Malformed Numbers", - "nested_under": [ - "00-09 System" - ] - } - ] - }, - { - "error": { - "type": "JDEX_INVALID_CATEGORY_NAME" - }, - "files": [ - { - "name": "No Numbers", - "nested_under": [ - "00-09 System" - ] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_invalid_id_name_flat/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder b/tests/with_jdex/jdex_invalid_id_name_flat/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_flat/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_invalid_id_name_flat/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_flat/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID b/tests/with_jdex/jdex_invalid_id_name_flat/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_flat/files/00-09 System/01 System Stuff/01.04 An ID/Other File b/tests/with_jdex/jdex_invalid_id_name_flat/files/00-09 System/01 System Stuff/01.04 An ID/Other File deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_flat/jdex/00.00 System.md b/tests/with_jdex/jdex_invalid_id_name_flat/jdex/00.00 System.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_flat/jdex/01.00 System Stuff.md b/tests/with_jdex/jdex_invalid_id_name_flat/jdex/01.00 System Stuff.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_flat/jdex/01.02 A Name.md b/tests/with_jdex/jdex_invalid_id_name_flat/jdex/01.02 A Name.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_flat/jdex/01.03 Another ID.md b/tests/with_jdex/jdex_invalid_id_name_flat/jdex/01.03 Another ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_flat/jdex/01.04 An ID.md b/tests/with_jdex/jdex_invalid_id_name_flat/jdex/01.04 An ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_flat/jdex/01.5 Malformed Numbers.md b/tests/with_jdex/jdex_invalid_id_name_flat/jdex/01.5 Malformed Numbers.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_flat/jdex/No Numbers.md b/tests/with_jdex/jdex_invalid_id_name_flat/jdex/No Numbers.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_flat/result.json b/tests/with_jdex/jdex_invalid_id_name_flat/result.json deleted file mode 100644 index 00230e1..0000000 --- a/tests/with_jdex/jdex_invalid_id_name_flat/result.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "type": "JDEX_INVALID_ID_NAME" - }, - "files": [ - { - "name": "01.5 Malformed Numbers.md", - "nested_under": [] - } - ] - }, - { - "error": { - "type": "JDEX_INVALID_ID_NAME" - }, - "files": [ - { - "name": "No Numbers.md", - "nested_under": [] - } - ] - } - ] -} diff --git a/tests/with_jdex/jdex_invalid_id_name_nested/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder b/tests/with_jdex/jdex_invalid_id_name_nested/files/00-09 System/01 System Stuff/01.02 A Name/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_nested/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/with_jdex/jdex_invalid_id_name_nested/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_nested/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID b/tests/with_jdex/jdex_invalid_id_name_nested/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_nested/jdex/00-09 System/01 System Stuff/01.02 A Name.md b/tests/with_jdex/jdex_invalid_id_name_nested/jdex/00-09 System/01 System Stuff/01.02 A Name.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_nested/jdex/00-09 System/01 System Stuff/01.03 Another ID.md b/tests/with_jdex/jdex_invalid_id_name_nested/jdex/00-09 System/01 System Stuff/01.03 Another ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_nested/jdex/00-09 System/01 System Stuff/01.4 Malformed Numbers.md b/tests/with_jdex/jdex_invalid_id_name_nested/jdex/00-09 System/01 System Stuff/01.4 Malformed Numbers.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_nested/jdex/00-09 System/01 System Stuff/No ID.md b/tests/with_jdex/jdex_invalid_id_name_nested/jdex/00-09 System/01 System Stuff/No ID.md deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/jdex_invalid_id_name_nested/result.json b/tests/with_jdex/jdex_invalid_id_name_nested/result.json deleted file mode 100644 index f1cb4c1..0000000 --- a/tests/with_jdex/jdex_invalid_id_name_nested/result.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "errors": [], - "jdex_errors": [ - { - "error": { - "type": "JDEX_INVALID_ID_NAME" - }, - "files": [ - { - "name": "01.4 Malformed Numbers.md", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - } - ] - }, - { - "error": { - "type": "JDEX_INVALID_ID_NAME" - }, - "files": [ - { - "name": "No ID.md", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - } - ] - } - ] -} diff --git a/tests/with_jdex/single_file_jdex/files/00-09 System/01 System Stuff/01.02 A Naem/.placeholder b/tests/with_jdex/single_file_jdex/files/00-09 System/01 System Stuff/01.02 A Naem/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/single_file_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder b/tests/with_jdex/single_file_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/single_file_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID b/tests/with_jdex/single_file_jdex/files/00-09 System/01 System Stuff/01.03 Another ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/with_jdex/single_file_jdex/jdex b/tests/with_jdex/single_file_jdex/jdex deleted file mode 100644 index ca83f0e..0000000 --- a/tests/with_jdex/single_file_jdex/jdex +++ /dev/null @@ -1,12 +0,0 @@ -00-09 System // which I can comment like this // and a nested one - 01 System Stuff//Comments? - // More comments - 01.02 A Name - - Location: work email. - /* A - block comment - */ - - - -01.03 Another ID // With a trailing comment diff --git a/tests/with_jdex/single_file_jdex/result.json b/tests/with_jdex/single_file_jdex/result.json deleted file mode 100644 index 76f3864..0000000 --- a/tests/with_jdex/single_file_jdex/result.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "ID_DIFFERENT_FROM_JDEX", - "id": "01.02", - "jdex_name": "01.02 A Name" - }, - "files": [ - { - "name": "01.02 A Naem", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/without_jdex/category_in_wrong_area/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder b/tests/without_jdex/category_in_wrong_area/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/category_in_wrong_area/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID b/tests/without_jdex/category_in_wrong_area/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/category_in_wrong_area/files/00-09 System/11 Whoops/11.01 Inbox/.placeholder b/tests/without_jdex/category_in_wrong_area/files/00-09 System/11 Whoops/11.01 Inbox/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/category_in_wrong_area/result.json b/tests/without_jdex/category_in_wrong_area/result.json deleted file mode 100644 index c5e1bf8..0000000 --- a/tests/without_jdex/category_in_wrong_area/result.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "CATEGORY_IN_WRONG_AREA", - "category_area": "1", - "file_area": "0" - }, - "files": [ - { - "name": "11 Whoops", - "nested_under": [ - "00-09 System" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/without_jdex/duplicate_area/files/00-09 A Reuse/02 Another Category/02.00 An ID/Directory Inside Id/.placeholder b/tests/without_jdex/duplicate_area/files/00-09 A Reuse/02 Another Category/02.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/duplicate_area/files/00-09 A Reuse/02 Another Category/02.00 An ID/File Inside ID b/tests/without_jdex/duplicate_area/files/00-09 A Reuse/02 Another Category/02.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/duplicate_area/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder b/tests/without_jdex/duplicate_area/files/00-09 An Area/01 A Category/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/duplicate_area/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID b/tests/without_jdex/duplicate_area/files/00-09 An Area/01 A Category/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/duplicate_area/result.json b/tests/without_jdex/duplicate_area/result.json deleted file mode 100644 index ed17559..0000000 --- a/tests/without_jdex/duplicate_area/result.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "errors": [ - { - "error": { - "area": "0", - "type": "DUPLICATE_AREA" - }, - "files": [ - { - "name": "00-09 A Reuse", - "nested_under": [] - }, - { - "name": "00-09 An Area", - "nested_under": [] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/without_jdex/duplicate_category/files/00-09 System/01 A Category/01.00 An ID/Directory Inside Id/.placeholder b/tests/without_jdex/duplicate_category/files/00-09 System/01 A Category/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/duplicate_category/files/00-09 System/01 A Category/01.00 An ID/File Inside ID b/tests/without_jdex/duplicate_category/files/00-09 System/01 A Category/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/duplicate_category/files/00-09 System/01 A Reuse/01.02 Another ID/Directory Inside Id/.placeholder b/tests/without_jdex/duplicate_category/files/00-09 System/01 A Reuse/01.02 Another ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/duplicate_category/files/00-09 System/01 A Reuse/01.02 Another ID/File Inside ID b/tests/without_jdex/duplicate_category/files/00-09 System/01 A Reuse/01.02 Another ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/duplicate_category/result.json b/tests/without_jdex/duplicate_category/result.json deleted file mode 100644 index ea222e5..0000000 --- a/tests/without_jdex/duplicate_category/result.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "DUPLICATE_CATEGORY", - "category": "01" - }, - "files": [ - { - "name": "01 A Category", - "nested_under": [ - "00-09 System" - ] - }, - { - "name": "01 A Reuse", - "nested_under": [ - "00-09 System" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/without_jdex/duplicate_id/files/00-09 System/01 System Stuff/01.00 A Reuse/Other File b/tests/without_jdex/duplicate_id/files/00-09 System/01 System Stuff/01.00 A Reuse/Other File deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/duplicate_id/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder b/tests/without_jdex/duplicate_id/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/duplicate_id/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID b/tests/without_jdex/duplicate_id/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/duplicate_id/result.json b/tests/without_jdex/duplicate_id/result.json deleted file mode 100644 index 84eb334..0000000 --- a/tests/without_jdex/duplicate_id/result.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "DUPLICATE_ID", - "id": "01.00" - }, - "files": [ - { - "name": "01.00 A Reuse", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - }, - { - "name": "01.00 An ID", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/without_jdex/file_outside_id/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder b/tests/without_jdex/file_outside_id/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/file_outside_id/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID b/tests/without_jdex/file_outside_id/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/file_outside_id/files/00-09 System/01 System Stuff/File Outside Id b/tests/without_jdex/file_outside_id/files/00-09 System/01 System Stuff/File Outside Id deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/file_outside_id/files/00-09 System/File Outside Category b/tests/without_jdex/file_outside_id/files/00-09 System/File Outside Category deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/file_outside_id/files/File Outside Area b/tests/without_jdex/file_outside_id/files/File Outside Area deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/file_outside_id/result.json b/tests/without_jdex/file_outside_id/result.json deleted file mode 100644 index 29718ac..0000000 --- a/tests/without_jdex/file_outside_id/result.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "FILE_OUTSIDE_ID" - }, - "files": [ - { - "name": "File Outside Area", - "nested_under": [] - } - ] - }, - { - "error": { - "type": "FILE_OUTSIDE_ID" - }, - "files": [ - { - "name": "File Outside Category", - "nested_under": [ - "00-09 System" - ] - } - ] - }, - { - "error": { - "type": "FILE_OUTSIDE_ID" - }, - "files": [ - { - "name": "File Outside Id", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/without_jdex/id_in_wrong_category/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder b/tests/without_jdex/id_in_wrong_category/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/id_in_wrong_category/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID b/tests/without_jdex/id_in_wrong_category/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/id_in_wrong_category/files/00-09 System/01 System Stuff/11.01 Whoops/.placeholder b/tests/without_jdex/id_in_wrong_category/files/00-09 System/01 System Stuff/11.01 Whoops/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/id_in_wrong_category/result.json b/tests/without_jdex/id_in_wrong_category/result.json deleted file mode 100644 index 5ddcf4c..0000000 --- a/tests/without_jdex/id_in_wrong_category/result.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "ID_IN_WRONG_CATEGORY", - "id_ac": "11", - "file_ac": "01" - }, - "files": [ - { - "name": "11.01 Whoops", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/without_jdex/ignore_files/files/.ignoreme b/tests/without_jdex/ignore_files/files/.ignoreme deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/ignore_files/files/00-09 System/01 System Stuff/.ignoreme2 b/tests/without_jdex/ignore_files/files/00-09 System/01 System Stuff/.ignoreme2 deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/ignore_files/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder b/tests/without_jdex/ignore_files/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/ignore_files/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID b/tests/without_jdex/ignore_files/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/ignore_files/files/00-09 System/01 System Stuff/ignoreme b/tests/without_jdex/ignore_files/files/00-09 System/01 System Stuff/ignoreme deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/ignore_files/files/00-09 System/ignoreme b/tests/without_jdex/ignore_files/files/00-09 System/ignoreme deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/ignore_files/ignore b/tests/without_jdex/ignore_files/ignore deleted file mode 100644 index 0c9b690..0000000 --- a/tests/without_jdex/ignore_files/ignore +++ /dev/null @@ -1,2 +0,0 @@ -.* -*/ignoreme diff --git a/tests/without_jdex/ignore_files/result.json b/tests/without_jdex/ignore_files/result.json deleted file mode 100644 index 169672d..0000000 --- a/tests/without_jdex/ignore_files/result.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "errors": [], - "jdex_errors": [] -} diff --git a/tests/without_jdex/invalid_area_name/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder b/tests/without_jdex/invalid_area_name/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/invalid_area_name/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID b/tests/without_jdex/invalid_area_name/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/invalid_area_name/files/10-18 Malformed/.placeholder b/tests/without_jdex/invalid_area_name/files/10-18 Malformed/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/invalid_area_name/files/No ID/.placeholder b/tests/without_jdex/invalid_area_name/files/No ID/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/invalid_area_name/result.json b/tests/without_jdex/invalid_area_name/result.json deleted file mode 100644 index e607ff7..0000000 --- a/tests/without_jdex/invalid_area_name/result.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "INVALID_AREA_NAME" - }, - "files": [ - { - "name": "10-18 Malformed", - "nested_under": [] - } - ] - }, - { - "error": { - "type": "INVALID_AREA_NAME" - }, - "files": [ - { - "name": "No ID", - "nested_under": [] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/without_jdex/invalid_category_name/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder b/tests/without_jdex/invalid_category_name/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/invalid_category_name/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID b/tests/without_jdex/invalid_category_name/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/invalid_category_name/files/00-09 System/2 Malformed/.placeholder b/tests/without_jdex/invalid_category_name/files/00-09 System/2 Malformed/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/invalid_category_name/files/00-09 System/No ID/.placeholder b/tests/without_jdex/invalid_category_name/files/00-09 System/No ID/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/invalid_category_name/result.json b/tests/without_jdex/invalid_category_name/result.json deleted file mode 100644 index da84288..0000000 --- a/tests/without_jdex/invalid_category_name/result.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "INVALID_CATEGORY_NAME" - }, - "files": [ - { - "name": "2 Malformed", - "nested_under": [ - "00-09 System" - ] - } - ] - }, - { - "error": { - "type": "INVALID_CATEGORY_NAME" - }, - "files": [ - { - "name": "No ID", - "nested_under": [ - "00-09 System" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/without_jdex/invalid_id_name/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder b/tests/without_jdex/invalid_id_name/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/invalid_id_name/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID b/tests/without_jdex/invalid_id_name/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/invalid_id_name/files/00-09 System/01 System Stuff/01.1 Malformed/.placeholder b/tests/without_jdex/invalid_id_name/files/00-09 System/01 System Stuff/01.1 Malformed/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/invalid_id_name/files/00-09 System/01 System Stuff/No ID/.placeholder b/tests/without_jdex/invalid_id_name/files/00-09 System/01 System Stuff/No ID/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/invalid_id_name/result.json b/tests/without_jdex/invalid_id_name/result.json deleted file mode 100644 index 8e5524f..0000000 --- a/tests/without_jdex/invalid_id_name/result.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "INVALID_ID_NAME" - }, - "files": [ - { - "name": "01.1 Malformed", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - } - ] - }, - { - "error": { - "type": "INVALID_ID_NAME" - }, - "files": [ - { - "name": "No ID", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - } - ] - } - ], - "jdex_errors": [] -} diff --git a/tests/without_jdex/nonempty_inbox/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder b/tests/without_jdex/nonempty_inbox/files/00-09 System/01 System Stuff/01.00 An ID/Directory Inside Id/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/nonempty_inbox/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID b/tests/without_jdex/nonempty_inbox/files/00-09 System/01 System Stuff/01.00 An ID/File Inside ID deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/nonempty_inbox/files/00-09 System/01 System Stuff/01.01 Inbox/Not This b/tests/without_jdex/nonempty_inbox/files/00-09 System/01 System Stuff/01.01 Inbox/Not This deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/nonempty_inbox/files/00-09 System/01 System Stuff/01.01 Inbox/Or This/.placeholder b/tests/without_jdex/nonempty_inbox/files/00-09 System/01 System Stuff/01.01 Inbox/Or This/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/tests/without_jdex/nonempty_inbox/result.json b/tests/without_jdex/nonempty_inbox/result.json deleted file mode 100644 index 5c96c7c..0000000 --- a/tests/without_jdex/nonempty_inbox/result.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "errors": [ - { - "error": { - "type": "NONEMPTY_INBOX", - "num_items": 2 - }, - "files": [ - { - "name": "01.01 Inbox", - "nested_under": [ - "00-09 System", - "01 System Stuff" - ] - } - ] - } - ], - "jdex_errors": [] -}