Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Further improve Boolean help messages #2770

Merged
merged 26 commits into from Apr 13, 2024
Merged

Conversation

claremacrae
Copy link
Collaborator

Description

Provide more meaningful information to help users trouble-shoot any problems with Boolean filters.

Note: more improvements are coming so I am not updating the documentation yet.

  1. When there is an error parsing a Boolean filter, show the user which sub-expressions have any problems that need fixing. (See 'Screenshots' heading below...)
  2. When there is an error parsing any statement, show any continuation lines, and placeholders, to aid in locating the error in the query.
  3. Add some sample problem queries to the test vault, to inspect the results of this PR.
    • See resources/sample_vaults/Tasks-Demo/Filters/Boolean Combinations.md
    • The new descriptive text may be useful in updating the docs for Boolean filters.

Motivation and Context

Try to make it easier still for users to diagnose errors with:

  • multi-line filters in general,
  • and Boolean filters in particular.

How has this been tested?

  • Automated tests
  • Exploratory testing

Screenshots (if appropriate)

Consider the error output generated for this line:

( filter by function ! 'NON_TASK,CANCELLED'.includes(task.status.type) ) OR ( filter by function const date = task.due.moment; return date ? !date.isValid() : false; ) OR ( filter by function task.due.moment?.isSameOrBefore(moment(), 'day') || false ) OR ( filter by function task.urgency.toFixed(2) === 1.95.toFixed(2) ) OR ( filter by function (!task.isRecurring) && task.originalMarkdown.includes('🔁') ) OR ( filter by function task.file.path.toLocaleLowerCase() === 'TASKS RELEASES/4.1.0 RELEASE.MD'.toLocaleLowerCase() ) OR ( filter by function const taskDate = task.due.moment; const now = moment(); return taskDate?.isSame(now, 'day') || ( !taskDate && task.heading?.includes(now.format('YYYY-MM-DD')) ) || false ) OR ( filter by function const wanted = '#context/home'; return task.heading?.includes(wanted) || task.tags.find( (tag) => tag === wanted ) && true || false; )

The error message will contain a list of the sub-expressions extracted.

Before this PR, that list looked like this:

Where the sub-expressions in the simplified line are:
    'f1': 'filter by function ! 'NON_TASK,CANCELLED'.includes(task.status.type'
    'f2': 'filter by function const date = task.due.moment; return date ? !date.isValid() : false;'
    'f3': 'filter by function task.due.moment?.isSameOrBefore(moment(), 'day') || false'
    'f4': 'filter by function task.urgency.toFixed(2) === 1.95.toFixed(2'
    'f5': 'filter by function (!task.isRecurring) && task.originalMarkdown.includes('🔁''
    'f6': 'filter by function task.file.path.toLocaleLowerCase() === 'TASKS RELEASES/4.1.0 RELEASE.MD'.toLocaleLowerCase('
    'f7': 'filter by function const taskDate = task.due.moment; const now = moment(); return taskDate?.isSame(now, 'day') || ( !taskDate && task.heading?.includes(now.format('YYYY-MM-DD')) ) || false'
    'f8': 'filter by function const wanted = '#context/home'; return task.heading?.includes(wanted) || task.tags.find( (tag) => tag === wanted ) && true || false;'

After this PR, the list looks like this, where the ERROR and OK comments should help identify the source of any problems:

Where the sub-expressions in the simplified line are:
    'f1': 'filter by function ! 'NON_TASK,CANCELLED'.includes(task.status.type'
        => ERROR:
           Error: Failed parsing expression "! 'NON_TASK,CANCELLED'.includes(task.status.type".
           The error message was:
           "SyntaxError: missing ) after argument list"
    'f2': 'filter by function const date = task.due.moment; return date ? !date.isValid() : false;'
        => OK
    'f3': 'filter by function task.due.moment?.isSameOrBefore(moment(), 'day') || false'
        => OK
    'f4': 'filter by function task.urgency.toFixed(2) === 1.95.toFixed(2'
        => ERROR:
           Error: Failed parsing expression "task.urgency.toFixed(2) === 1.95.toFixed(2".
           The error message was:
           "SyntaxError: missing ) after argument list"
    'f5': 'filter by function (!task.isRecurring) && task.originalMarkdown.includes('🔁''
        => ERROR:
           Error: Failed parsing expression "(!task.isRecurring) && task.originalMarkdown.includes('🔁'".
           The error message was:
           "SyntaxError: missing ) after argument list"
    'f6': 'filter by function task.file.path.toLocaleLowerCase() === 'TASKS RELEASES/4.1.0 RELEASE.MD'.toLocaleLowerCase('
        => ERROR:
           Error: Failed parsing expression "task.file.path.toLocaleLowerCase() === 'TASKS RELEASES/4.1.0 RELEASE.MD'.toLocaleLowerCase(".
           The error message was:
           "SyntaxError: Unexpected token '}'"
    'f7': 'filter by function const taskDate = task.due.moment; const now = moment(); return taskDate?.isSame(now, 'day') || ( !taskDate && task.heading?.includes(now.format('YYYY-MM-DD')) ) || false'
        => OK
    'f8': 'filter by function const wanted = '#context/home'; return task.heading?.includes(wanted) || task.tags.find( (tag) => tag === wanted ) && true || false;'
        => OK

Types of changes

Changes visible to users:

  • New feature (prefix: feat - non-breaking change which adds functionality)
  • Documentation (prefix: docs - improvements to any documentation content for users)
  • Sample vault (prefix: vault - improvements to the Tasks-Demo sample vault)

Internal changes:

  • Tests (prefix: test - additions and improvements to unit tests and the smoke tests)

Checklist

  • My code follows the code style of this project and passes yarn run lint.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
    • Will be done later
  • My change has adequate Unit Test coverage.

Terms

'ignore global query' simplifies the explanation.
To be able to easily review error messages.
One is skipped as it's failing - and it.failing() doesn't work with inline snapshot tests.
@claremacrae claremacrae added the scope: query logic Boolean combinations of filters - and, or, not label Apr 13, 2024
@claremacrae claremacrae changed the title Boolean error info feat: Further improve Boolean help messages Apr 13, 2024
@claremacrae claremacrae merged commit c1ba1bc into main Apr 13, 2024
2 checks passed
@claremacrae claremacrae deleted the boolean-error-info branch April 13, 2024 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
scope: query logic Boolean combinations of filters - and, or, not
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant