Repository: blacksmithgu/obsidian-dataview
Pull request #1988 (2023-07-09 19:31:41)

chore(deps): bump tough-cookie from 4.0.0 to 4.1.3
Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) from 4.0.0 to 4.1.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/salesforce/tough-cookie/releases">tough-cookie's releases</a>.</em></p>
<blockquote>
<h2>4.1.3</h2>
<p>Security fix for Prototype Pollution discovery in <a href="https://redirect.github.com/salesforce/tough-cookie/issues/282">#282</a>. This is a minor release, although output from the <code>inspect</code> utility is affected by this change, we felt this change was important enough to be pushed into the next patch.</p>
<h2>4.1.2 -- Patch and Bugfix Release</h2>
<h2>What's Changed</h2>
<ul>
<li>fix: allow set cookies with localhost by <a href="https://github.com/colincasey"><code>@​colincasey</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/253">salesforce/tough-cookie#253</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/salesforce/tough-cookie/compare/v4.1.1...v4.1.2">https://github.com/salesforce/tough-cookie/compare/v4.1.1...v4.1.2</a></p>
<h2>4.1.1</h2>
<h2>Patch Release</h2>
<h2>What's Changed</h2>
<ul>
<li>fix: allow special use domains by default by <a href="https://github.com/colincasey"><code>@​colincasey</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/249">salesforce/tough-cookie#249</a></li>
<li>4.1.1 Patch -- allow special use domains by default by <a href="https://github.com/awaterma"><code>@​awaterma</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/250">salesforce/tough-cookie#250</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/salesforce/tough-cookie/compare/v4.1.0...v4.1.1">https://github.com/salesforce/tough-cookie/compare/v4.1.0...v4.1.1</a></p>
<h2>4.1.0</h2>
<p>v4.1.0</p>
<p>Minor release, focused mainly on resolving reported issues and some minor feature work.</p>
<h2>What's Changed</h2>
<ul>
<li>Create CHANGELOG.md by <a href="https://github.com/ShivanKaul"><code>@​ShivanKaul</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/189">salesforce/tough-cookie#189</a></li>
<li>Missing param validation issue145 by <a href="https://github.com/medelibero-sfdc"><code>@​medelibero-sfdc</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/193">salesforce/tough-cookie#193</a></li>
<li>Create SECURITY.md by <a href="https://github.com/ShivanKaul"><code>@​ShivanKaul</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/201">salesforce/tough-cookie#201</a></li>
<li>Create CODE_OF_CONDUCT.md by <a href="https://github.com/ShivanKaul"><code>@​ShivanKaul</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/200">salesforce/tough-cookie#200</a></li>
<li>Fix for issue <a href="https://redirect.github.com/salesforce/tough-cookie/issues/195">#195</a> by <a href="https://github.com/medelibero-sfdc"><code>@​medelibero-sfdc</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/202">salesforce/tough-cookie#202</a></li>
<li>Add explanation and more special-use domains by <a href="https://github.com/ShivanKaul"><code>@​ShivanKaul</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/203">salesforce/tough-cookie#203</a></li>
<li>Sync of constructor options for serialization by <a href="https://github.com/medelibero-sfdc"><code>@​medelibero-sfdc</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/204">salesforce/tough-cookie#204</a></li>
<li>Returned null in case of empty cookie value by <a href="https://github.com/vsin12"><code>@​vsin12</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/196">salesforce/tough-cookie#196</a></li>
<li>132 str trim not a function by <a href="https://github.com/awaterma"><code>@​awaterma</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/209">salesforce/tough-cookie#209</a></li>
<li>Fix for issue <a href="https://redirect.github.com/salesforce/tough-cookie/issues/153">#153</a> by <a href="https://github.com/medelibero-sfdc"><code>@​medelibero-sfdc</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/210">salesforce/tough-cookie#210</a></li>
<li>Fix permuteDomain with trailing dot by <a href="https://github.com/ruoho-sfdc"><code>@​ruoho-sfdc</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/216">salesforce/tough-cookie#216</a></li>
<li>Issue <a href="https://redirect.github.com/salesforce/tough-cookie/issues/213">#213</a> -- added gh-actions flow for building and testing tough-co… by <a href="https://github.com/awaterma"><code>@​awaterma</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/218">salesforce/tough-cookie#218</a></li>
<li>Issue <a href="https://redirect.github.com/salesforce/tough-cookie/issues/210">#210</a> -- Updated workflow to use npm install. by <a href="https://github.com/awaterma"><code>@​awaterma</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/220">salesforce/tough-cookie#220</a></li>
<li>@<a href="https://redirect.github.com/salesforce/tough-cookie/issues/215">GH-215</a> -- Tests that document localhost behavior when set as domain. by <a href="https://github.com/awaterma"><code>@​awaterma</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/221">salesforce/tough-cookie#221</a></li>
<li>fix: MemoryCookieStore methods should exist on the prototype, not on the class. by <a href="https://github.com/wjhsf"><code>@​wjhsf</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/226">salesforce/tough-cookie#226</a></li>
<li>Unit test cases for <code>allowSpecialUseDomain</code> option by <a href="https://github.com/colincasey"><code>@​colincasey</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/225">salesforce/tough-cookie#225</a></li>
<li>[Snyk] Upgrade universalify from 0.1.2 to 0.2.0 by <a href="https://github.com/snyk-bot"><code>@​snyk-bot</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/228">salesforce/tough-cookie#228</a></li>
<li>React Native Support by <a href="https://github.com/colincasey"><code>@​colincasey</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/227">salesforce/tough-cookie#227</a></li>
<li>Adding Updating CODEOWNERS with ECCN as per Export Control Compliance by <a href="https://github.com/svc-scm"><code>@​svc-scm</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/223">salesforce/tough-cookie#223</a></li>
<li>fix: domain match routine by <a href="https://github.com/colincasey"><code>@​colincasey</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/236">salesforce/tough-cookie#236</a></li>
<li>Stop using the internal NodeJS punycode module by <a href="https://github.com/gboer"><code>@​gboer</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/238">salesforce/tough-cookie#238</a></li>
<li>Initial documentation review by <a href="https://github.com/mcarey86"><code>@​mcarey86</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/234">salesforce/tough-cookie#234</a></li>
<li>fix: distinguish between no samesite and samesite=none by <a href="https://github.com/colincasey"><code>@​colincasey</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/240">salesforce/tough-cookie#240</a></li>
<li>Prepare tough-cookie 4.1 for publishing (updated GitHub actions, move… by <a href="https://github.com/awaterma"><code>@​awaterma</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/242">salesforce/tough-cookie#242</a></li>
<li>4.1.0 release to NPM by <a href="https://github.com/awaterma"><code>@​awaterma</code></a> in <a href="https://redirect.github.com/salesforce/tough-cookie/pull/245">salesforce/tough-cookie#245</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/salesforce/tough-cookie/commit/4ff4d29f6cefd279a412b8d62a21142ebd410b36"><code>4ff4d29</code></a> 4.1.3 release preparation, update the package and lib/version to 4.1.3. (<a href="https://redirect.github.com/salesforce/tough-cookie/issues/284">#284</a>)</li>
<li><a href="https://github.com/salesforce/tough-cookie/commit/12d474791bb856004e858fdb1c47b7608d09cf6e"><code>12d4747</code></a> Prevent prototype pollution in cookie memstore (<a href="https://redirect.github.com/salesforce/tough-cookie/issues/283">#283</a>)</li>
<li><a href="https://github.com/salesforce/tough-cookie/commit/f06b72d1d447f33dfa6222c0a3c0c5e063558248"><code>f06b72d</code></a> Fix documentation for store.findCookies, missing allowSpecialUseDomain proper...</li>
<li><a href="https://github.com/salesforce/tough-cookie/commit/b1a8898ee3f8af52c6c1c355555d9f50ebe626ce"><code>b1a8898</code></a> fix: allow set cookies with localhost (<a href="https://redirect.github.com/salesforce/tough-cookie/issues/253">#253</a>)</li>
<li><a href="https://github.com/salesforce/tough-cookie/commit/ec707966e68a48199e646e2fa6b3055df6a280f0"><code>ec70796</code></a> 4.1.1 Patch -- allow special use domains by default (<a href="https://redirect.github.com/salesforce/tough-cookie/issues/250">#250</a>)</li>
<li><a href="https://github.com/salesforce/tough-cookie/commit/d4ac5801dd2c2d53eec51329e5380bbffb23bfaf"><code>d4ac580</code></a> fix: allow special use domains by default (<a href="https://redirect.github.com/salesforce/tough-cookie/issues/249">#249</a>)</li>
<li><a href="https://github.com/salesforce/tough-cookie/commit/79c2f7d373e39918605c270ecd965f507701233d"><code>79c2f7d</code></a> 4.1.0 release to NPM (<a href="https://redirect.github.com/salesforce/tough-cookie/issues/245">#245</a>)</li>
<li><a href="https://github.com/salesforce/tough-cookie/commit/4fafc179a798a570e32fc698034f0480c07d9afa"><code>4fafc17</code></a> Prepare tough-cookie 4.1 for publishing (updated GitHub actions, move Dockerf...</li>
<li><a href="https://github.com/salesforce/tough-cookie/commit/aa4396da7abcb2dbe607db7b31606f7dd0f45709"><code>aa4396d</code></a> fix: distinguish between no samesite and samesite=none (<a href="https://redirect.github.com/salesforce/tough-cookie/issues/240">#240</a>)</li>
<li><a href="https://github.com/salesforce/tough-cookie/commit/b8d751188da697157e5eed81fa1e5f806fdfb541"><code>b8d7511</code></a> Modernize README (<a href="https://redirect.github.com/salesforce/tough-cookie/issues/234">#234</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/salesforce/tough-cookie/compare/v4.0.0...v4.1.3">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tough-cookie&package-manager=npm_and_yarn&previous-version=4.0.0&new-version=4.1.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

You can trigger a rebase of this PR by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/blacksmithgu/obsidian-dataview/network/alerts).

</details>

> **Note**
> Automatic rebases have been disabled on this pull request as it has been open for over 30 days.



Patch:
diff --git a/.gitignore b/.gitignore
index 28c4916..da6d9d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,10 +12,20 @@ node_modules
 # build
 build/
 
-test-vault/.obsidian/workspace
-test-vault/.obsidian/plugins/dataview/*.css
-test-vault/.obsidian/plugins/dataview/*.js
-test-vault/.obsidian/plugins/dataview/*.json
+# Ignore .obsidian
+# No one will commit these files, they just spam 'git status'
+test-vault/.obsidian/*
+# Tells obsidian what plugins are enabled
+!test-vault/.obsidian/community-plugins.json
+# This plugin should still be tracked by git.
+# It might need updated at some point
+!test-vault/.obsidian/hot-reload-master/*
+
+# Don't track this folder. For random things to try.
+# If its import to test though, add it somewhere where other
+# people can test it too.
+test-vault/untracked/*
+!test-vault/untracked/README.md
 
 lib
 yarn.lock
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3d668d0..0585098 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# Unreleased
+
+- DQL: New math rounding functions, `trunc(number)`, `floor(number)`, `ceil(number)`.
+
 # 0.5.56
 
 - Includes some performance fixes on recent versions of Obsidian 1.3+ due to some API changes. Thanks @kometenstaub.
diff --git a/docs/docs/annotation/add-metadata.md b/docs/docs/annotation/add-metadata.md
index 935d76e..017c5a6 100644
--- a/docs/docs/annotation/add-metadata.md
+++ b/docs/docs/annotation/add-metadata.md
@@ -34,7 +34,7 @@ With this your note has metadata fields named `alias`, `last-reviewed`, and `tho
 - `last-reviewed` is a [date](../types-of-metadata/#date), because it follows the ISO date format
 - `thoughts` is a [object](../types-of-metadata/#object) field, because it uses the YAML Frontmatter object syntax
 
-You could i.e. query for this note with the following query, because `thoughts` is a object with the value `rating`:
+You could query for this note with the following query:
 
 ~~~
 ```dataview
@@ -106,7 +106,7 @@ Like you can see in the table, if you are using **spaces or capitalized letters*
 
 **Keys with spaces** cannot be used in a query as-is. You have two possibilities here: Either use the sanitized name, that is always all lowercase and with dashes instead of spaces or use the **row** variable syntax. Find out more [in the FAQ](../resources/faq.md).
 
-**Keys with capitalized letters** can be used as-is, if you wish. The sanitized version allows you to query for a key independent of its capitalization and makes it easier to use: You can query the same field thats, for example, in one file named `someMetadata` and in another `someMetaData` when using the sanitized key `somemetadata`. 
+**Keys with capitalized letters** can be used as-is, if you wish. The sanitized version allows you to query for a key independent of its capitalization and makes it easier to use: You can query the same field that's, for example, in one file named `someMetadata` and in another `someMetaData` when using the sanitized key `somemetadata`. 
 
 In addition, the **bold field key is missing its formatting tokens**. Even though the `**` used to make it appear bold are part of the key name in the file, they are left out when indexing your note. The same goes for all other built-in formatting, like strike through or italic. This means formatted keys can only be queried without their formatting. This allows you to format the key in context of the note without worrying that you might create different keys for the same type of information. 
 
diff --git a/docs/docs/annotation/metadata-tasks.md b/docs/docs/annotation/metadata-tasks.md
index 59fd0f8..b5f50d8 100644
--- a/docs/docs/annotation/metadata-tasks.md
+++ b/docs/docs/annotation/metadata-tasks.md
@@ -62,7 +62,7 @@ As with pages, Dataview adds a number of implicit fields to each task or list it
 | `completed` |  Boolean  | Whether or not this *specific* task has been completed; this does not consider the completionnon-completion of any child tasks. A task is explicitly considered "completed" if it has been marked with an 'x'. If you use a custom status, i.e. `[-]`, `checked` will be true, whereas `completed` will be false. |
 | `fullyCompleted` |  Boolean  | Whether or not this task and **all** of its subtasks are completed. |
 | `text` |  Text  | The plain text of this task, including any metadata field annotations. |
-| `visual` | Text | The text of this task, which is rendered by Dataview. It can be modified to render arbitary text. |
+| `visual` | Text | The text of this task, which is rendered by Dataview. It can be modified to render arbitrary text. |
 | `line` |  Number  | The line of the file this task shows up on. |
 | `lineCount` |  Number  | The number of Markdown lines that this task takes up. |
 | `path` |  Text  | The full path of the file this task is in. Equals to `file.path` for [pages](./metadata-pages.md) |
diff --git a/docs/docs/annotation/types-of-metadata.md b/docs/docs/annotation/types-of-metadata.md
index 3a2c677..62ea6ce 100644
--- a/docs/docs/annotation/types-of-metadata.md
+++ b/docs/docs/annotation/types-of-metadata.md
@@ -25,7 +25,7 @@ Most of the time you do not need to worry too much about the type of your fields
 
     | File (1) | date1 | date2 |
     | -------- | ----- | ----- |
-    | Untitled 2 | 3:15 PM - Februar 26, 2021 | 2021-04-17 18:00 |
+    | Untitled 2 | 3:15 PM - February 26, 2021 | 2021-04-17 18:00 |
 
     `date1` is recognized as a **Date** while `date2` is a normal **Text** to dataview, that's why `date1` is parsed differently for you. Find out more on [Dates below](#date). 
 
@@ -121,7 +121,7 @@ WHERE birthday.month = date(now).month
 gives you back all birthdays happening this month. Curious about `date(now)`? Read more about it under [literals](./../../reference/literals/#dates).
 
 !!! info "Displaying of date objects"
-    Dataview renders date objects in a human readable format, i.e. `3:15 PM - Februar 26, 2021`. You can adjust how this format looks like in Dataview's Setting under "General" with "Date Format" and "Date + Time Format". If you want to adjust the format in a specific query only, use the [dateformat function](../../reference/functions/#dateformatdatedatetime-string).
+    Dataview renders date objects in a human readable format, i.e. `3:15 PM - February 26, 2021`. You can adjust how this format looks like in Dataview's Setting under "General" with "Date Format" and "Date + Time Format". If you want to adjust the format in a specific query only, use the [dateformat function](../../reference/functions/#dateformatdatedatetime-string).
 
 ### Duration
 
diff --git a/docs/docs/api/code-reference.md b/docs/docs/api/code-reference.md
index 0f2a99d..a83b961 100644
--- a/docs/docs/api/code-reference.md
+++ b/docs/docs/api/code-reference.md
@@ -135,6 +135,46 @@ views/custom
 View scripts have access to the `dv` object (the API object), and an `input` object which is exactly whatever the second
 argument of `dv.view()` was.
 
+Bear in mind, `dv.view()` cannot read from directories starting with a dot, like `.views`. Example of an incorrect usage:
+
+```js
+await dv.view(".views/view1", { arg1: 'a', arg2: 'b' });
+```
+Attempting this will yield the following exception:
+
+```
+Dataview: custom view not found for '.views/view1/view.js' or '.views/view1.js'.
+```
+
+Also note, directory paths always originate from the vault root.
+
+#### Example
+In this example, we have a custom script file named `view1.js` in the `scripts` directory. 
+
+**File:** `scripts/view1.js`
+```js
+console.log(`Loading view1`);
+
+function foo(...args) {
+  console.log('foo is called with args', ...args);
+}
+foo(input)
+```
+
+And we have an Obsidian document located under `projects`. We'll call `dv.view()` from this document using the `scripts/view1.js` path.
+
+**Document:** `projects/customViews.md`
+```js
+await dv.view("scripts/view1", { arg1: 'a', arg2: 'b' }) 
+```
+
+When the above script is executed, it will print the following:
+
+```
+Loading view1
+foo is called with args {arg1: 'a', arg2: 'b'}
+```
+
 ## Dataviews
 
 ### `dv.list(elements)`
@@ -233,7 +273,7 @@ dv.paragraph(markdown);
 
 ### `dv.array(value)`
 
-Convert a given value or array into a Dataview [data array](data-array). If the value is already a data array, returns
+Convert a given value or array into a Dataview [data array](../data-array). If the value is already a data array, returns
 it unchanged.
 
 ```js
@@ -408,7 +448,7 @@ Equivalent to `dv.query()`, but returns rendered Markdown.
 
 ```js
 await dv.queryMarkdown("LIST FROM #tag") =>
-    { successfult: true, value: { "- [[Page 1]]\n- [[Page 2]]" } }
+    { successful: true, value: { "- [[Page 1]]\n- [[Page 2]]" } }
 ```
 
 ### ⌛ `dv.tryQueryMarkdown(source, [file], [settings])`
diff --git a/docs/docs/api/data-array.md b/docs/docs/api/data-array.md
index 2f741f6..f68ea24 100644
--- a/docs/docs/api/data-array.md
+++ b/docs/docs/api/data-array.md
@@ -54,7 +54,7 @@ export interface DataArray<T> {
     /** Limit the total number of entries in the array to the given value. */
     limit(count: number): DataArray<T>;
     /**
-     * Take a slice of the array. If `start` is undefined, it is assumed to be 0; if `end` is undefined, it is assumbed
+     * Take a slice of the array. If `start` is undefined, it is assumed to be 0; if `end` is undefined, it is assumed
      * to be the end of the array.
      */
     slice(start?: number, end?: number): DataArray<T>;
@@ -109,7 +109,7 @@ export interface DataArray<T> {
     to(key: string): DataArray<any>;
     /**
      * Recursively expand the given key, flattening a tree structure based on the key into a flat array. Useful for handling
-     * heirarchical data like tasks with 'subtasks'.
+     * hierarchical data like tasks with 'subtasks'.
      */
     expand(key: string): DataArray<any>;
 
diff --git a/docs/docs/queries/query-types.md b/docs/docs/queries/query-types.md
index 3162dee..7f70a45 100644
--- a/docs/docs/queries/query-types.md
+++ b/docs/docs/queries/query-types.md
@@ -215,7 +215,7 @@ TABLE
 !!! info "Disabling Result count"
     The first column always shows the result count. If you do not want to get it displayed, you can disable it in Dataview's settings ("Display result count", available since 0.5.52).
 
-Of course, a `TABLE` is made for specifying one to multiple additional informations:  
+Of course, a `TABLE` is made for specifying one to multiple additional information:  
 
 ~~~
 ```dataview
@@ -461,7 +461,7 @@ WHERE urgent
 
 ## CALENDAR
 
-The `CALENDAR` Query outputs a monthly based calendar where every result is depicted as a dot on it reffering date. The `CALENDAR` is the only Query Type that requires an additional information. This additional information needs to be a [date](../annotation/types-of-metadata.md#date) (or unset) on all queried pages. 
+The `CALENDAR` Query outputs a monthly based calendar where every result is depicted as a dot on it referring date. The `CALENDAR` is the only Query Type that requires an additional information. This additional information needs to be a [date](../annotation/types-of-metadata.md#date) (or unset) on all queried pages. 
 
 !!! summary "`CALENDAR` Query Type"
     The `CALENDAR` Query Types renders a calendar view where every result is represented by a dot on the given meta data field date.
diff --git a/docs/docs/queries/structure.md b/docs/docs/queries/structure.md
index 8c1ab4b..31efe78 100644
--- a/docs/docs/queries/structure.md
+++ b/docs/docs/queries/structure.md
@@ -115,7 +115,7 @@ FROM (#assignment AND "30 School") OR ("30 School/32 Homeworks" AND outgoing([[S
 
 In addition to the Query Types and the **Data command** `FROM` that's explained above, you have several other **Data Commands** available that help you restrict, refine, sort or group your query results. 
 
-All data commands except the `FROM` command can be used **multiple times in any order** (as long as they come after the Query Type and `FROM`, if `FROM` is used at all). They'll be excuted in the order they are written.
+All data commands except the `FROM` command can be used **multiple times in any order** (as long as they come after the Query Type and `FROM`, if `FROM` is used at all). They'll be executed in the order they are written.
 
 Available are:
 
diff --git a/docs/docs/reference/expressions.md b/docs/docs/reference/expressions.md
index 306e491..1a030e2 100644
--- a/docs/docs/reference/expressions.md
+++ b/docs/docs/reference/expressions.md
@@ -134,7 +134,7 @@ WHERE status != "done"
     WHERE typeof(due) = "date" AND due <= date(today)
     ```
     ~~~
-    Most often, it is sufficient to check if the meta data is available via `WHERE due AND due <= date(today)`, but checking the type is the safer way to get forseeable results. 
+    Most often, it is sufficient to check if the meta data is available via `WHERE due AND due <= date(today)`, but checking the type is the safer way to get foreseeable results. 
 
 ### List/Object Indexing
 
diff --git a/docs/docs/reference/functions.md b/docs/docs/reference/functions.md
index fce1f8b..7aa1aaa 100644
--- a/docs/docs/reference/functions.md
+++ b/docs/docs/reference/functions.md
@@ -1,6 +1,6 @@
 # Functions
 
-Dataview functions provide more advanced ways to manipulate data. You can use functions **in [data commands](../queries/data-commands.md)** (except FROM) to filter or group or use them **as [additional informations](../queries/query-types.md)** like TABLE columns or extra output for LIST queries to see your data in a new light.
+Dataview functions provide more advanced ways to manipulate data. You can use functions **in [data commands](../queries/data-commands.md)** (except FROM) to filter or group or use them **as [additional information](../queries/query-types.md)** like TABLE columns or extra output for LIST queries to see your data in a new light.
 
 ## How functions work
 
@@ -59,7 +59,7 @@ Parses a date from the provided string, date, or link object, if possible, retur
 
 ```js
 date("2020-04-18") = <date object representing April 18th, 2020>
-date([[2021-04-16]]) = <date object for the given page, refering to file.day>
+date([[2021-04-16]]) = <date object for the given page, referring to file.day>
 ```
 
 ### `date(text, format)`
@@ -162,6 +162,38 @@ round(16.555555) = 7
 round(16.555555, 2) = 16.56
 ```
 
+### `trunc(number)`
+
+Truncates ("cuts off") the decimal point from a number.
+
+```js
+trunc(12.937) = 12
+trunc(-93.33333) = -93
+trunc(-0.837764) = 0
+```
+
+### `floor(number)`
+
+Always rounds down and returns the largest integer less than or equal to a given number.
+This means that negative numbers become more negative.
+
+```js
+floor(12.937) = 12
+floor(-93.33333) = -94
+floor(-0.837764) = -1
+```
+
+### `ceil(number)`
+
+Always rounds up and returns the smallest integer greater than or equal to a given number.
+This means negative numbers become less negative.
+
+```js
+ceil(12.937) = 13
+ceil(-93.33333) = -93
+ceil(-0.837764) = 0
+```
+
 ### `min(a, b, ..)`
 
 Compute the minimum value of a list of arguments, or an array.
diff --git a/docs/docs/reference/literals.md b/docs/docs/reference/literals.md
index dff487f..0dc7a6c 100644
--- a/docs/docs/reference/literals.md
+++ b/docs/docs/reference/literals.md
@@ -46,7 +46,7 @@ Literal|Description
 `0`|The number zero
 `1337`|The positive number 1337
 `-200`| The negative number -200
-`"The quick brown fox jumps over the lazy dog"`| Text (sometimes reffered to as "string")
+`"The quick brown fox jumps over the lazy dog"`| Text (sometimes referred to as "string")
 `[[Science]]`|A link to the file named "Science"
 `[[]]`| A link to the current file
 `[1, 2, 3]`|A list of numbers 1, 2, and 3
diff --git a/package-lock.json b/package-lock.json
index 50a1fb8..e761c1d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "obsidian-dataview",
-  "version": "0.5.55",
+  "version": "0.5.56",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "obsidian-dataview",
-      "version": "0.5.55",
+      "version": "0.5.56",
       "license": "MIT",
       "dependencies": {
         "@codemirror/language": "https://github.com/lishid/cm-language",
@@ -32,7 +32,7 @@
         "@zerollup/ts-transform-paths": "^1.7.18",
         "compare-versions": "^4.1.1",
         "jest": "^27.1.0",
-        "obsidian": "^1.2.8",
+        "obsidian": "^1.4.0",
         "prettier": "2.3.2",
         "rollup": "^2.67.2",
         "rollup-jest": "^1.1.3",
@@ -41,7 +41,7 @@
         "rollup-plugin-web-worker-loader": "^1.6.1",
         "ts-jest": "^27.0.5",
         "tslib": "^2.3.1",
-        "ttypescript": "^1.5.12",
+        "ttypescript": "^1.5.15",
         "typescript": "^4.4.2"
       }
     },
@@ -1480,9 +1480,9 @@
       }
     },
     "node_modules/@types/codemirror": {
-      "version": "0.0.108",
-      "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.108.tgz",
-      "integrity": "sha512-3FGFcus0P7C2UOGCNUVENqObEb4SFk+S8Dnxq7K6aIsLVs/vDtlangl3PEO0ykaKXyK56swVF6Nho7VsA44uhw==",
+      "version": "5.60.8",
+      "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.8.tgz",
+      "integrity": "sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==",
       "dependencies": {
         "@types/tern": "*"
       }
@@ -5568,11 +5568,12 @@
       "dev": true
     },
     "node_modules/obsidian": {
-      "version": "1.2.8",
-      "resolved": "git+ssh://git@github.com/obsidianmd/obsidian-api.git#583ba39e3f6c0546de5e5e8742256a60e2d78ebc",
-      "license": "MIT",
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.4.0.tgz",
+      "integrity": "sha512-fsZMPlxgflGSBSP6P4BjQi5+0MqZl3h6FEDEZ3CNnweNdDw0doyqN3FMO/PGWfuxPT77WicVwUxekuI3e6eCGg==",
+      "dev": true,
       "dependencies": {
-        "@types/codemirror": "0.0.108",
+        "@types/codemirror": "5.60.8",
         "moment": "2.29.4"
       },
       "peerDependencies": {
@@ -5607,6 +5608,19 @@
         "obsidian-daily-notes-interface": "dist/main.js"
       }
     },
+    "node_modules/obsidian-daily-notes-interface/node_modules/obsidian": {
+      "version": "1.4.4",
+      "resolved": "git+ssh://git@github.com/obsidianmd/obsidian-api.git#5178e27f0eb12741c79914f52146de8ff827e390",
+      "license": "MIT",
+      "dependencies": {
+        "@types/codemirror": "5.60.8",
+        "moment": "2.29.4"
+      },
+      "peerDependencies": {
+        "@codemirror/state": "^6.0.0",
+        "@codemirror/view": "^6.0.0"
+      }
+    },
     "node_modules/obsidian-daily-notes-interface/node_modules/tslib": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
@@ -5906,6 +5920,12 @@
         "node": ">=6"
       }
     },
+    "node_modules/querystringify": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+      "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+      "dev": true
+    },
     "node_modules/queue-microtask": {
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -5941,6 +5961,12 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/requires-port": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+      "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+      "dev": true
+    },
     "node_modules/resolve": {
       "version": "1.22.0",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
@@ -6470,19 +6496,29 @@
       }
     },
     "node_modules/tough-cookie": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
-      "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==",
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
+      "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
       "dev": true,
       "dependencies": {
         "psl": "^1.1.33",
         "punycode": "^2.1.1",
-        "universalify": "^0.1.2"
+        "universalify": "^0.2.0",
+        "url-parse": "^1.5.3"
       },
       "engines": {
         "node": ">=6"
       }
     },
+    "node_modules/tough-cookie/node_modules/universalify": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
+      "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
     "node_modules/ts-jest": {
       "version": "27.1.5",
       "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.5.tgz",
@@ -6644,9 +6680,9 @@
       "dev": true
     },
     "node_modules/ttypescript": {
-      "version": "1.5.13",
-      "resolved": "https://registry.npmjs.org/ttypescript/-/ttypescript-1.5.13.tgz",
-      "integrity": "sha512-KT/RBfGGlVJFqEI8cVvI3nMsmYcFvPSZh8bU0qX+pAwbi7/ABmYkzn7l/K8skw0xmYjVCoyaV6WLsBQxdadybQ==",
+      "version": "1.5.15",
+      "resolved": "https://registry.npmjs.org/ttypescript/-/ttypescript-1.5.15.tgz",
+      "integrity": "sha512-48ykDNHzFnPMnv4hYX1P8Q84TvCZyL1QlFxeuxsuZ48X2+ameBgPenvmCkHJtoOSxpoWTWi8NcgNrRnVDOmfSg==",
       "dev": true,
       "dependencies": {
         "resolve": ">=1.9.0"
@@ -6736,6 +6772,16 @@
         "tslib": "^2"
       }
     },
+    "node_modules/url-parse": {
+      "version": "1.5.10",
+      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+      "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+      "dev": true,
+      "dependencies": {
+        "querystringify": "^2.1.1",
+        "requires-port": "^1.0.0"
+      }
+    },
     "node_modules/v8-compile-cache-lib": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
@@ -6805,9 +6851,9 @@
       }
     },
     "node_modules/word-wrap": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
-      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
+      "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
       "dev": true,
       "engines": {
         "node": ">=0.10.0"
@@ -8091,9 +8137,9 @@
       }
     },
     "@types/codemirror": {
-      "version": "0.0.108",
-      "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.108.tgz",
-      "integrity": "sha512-3FGFcus0P7C2UOGCNUVENqObEb4SFk+S8Dnxq7K6aIsLVs/vDtlangl3PEO0ykaKXyK56swVF6Nho7VsA44uhw==",
+      "version": "5.60.8",
+      "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.8.tgz",
+      "integrity": "sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==",
       "requires": {
         "@types/tern": "*"
       }
@@ -11373,10 +11419,12 @@
       "dev": true
     },
     "obsidian": {
-      "version": "git+ssh://git@github.com/obsidianmd/obsidian-api.git#583ba39e3f6c0546de5e5e8742256a60e2d78ebc",
-      "from": "obsidian@^1.2.8",
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.4.0.tgz",
+      "integrity": "sha512-fsZMPlxgflGSBSP6P4BjQi5+0MqZl3h6FEDEZ3CNnweNdDw0doyqN3FMO/PGWfuxPT77WicVwUxekuI3e6eCGg==",
+      "dev": true,
       "requires": {
-        "@types/codemirror": "0.0.108",
+        "@types/codemirror": "5.60.8",
         "moment": "2.29.4"
       }
     },
@@ -11406,6 +11454,14 @@
         "tslib": "2.1.0"
       },
       "dependencies": {
+        "obsidian": {
+          "version": "git+ssh://git@github.com/obsidianmd/obsidian-api.git#5178e27f0eb12741c79914f52146de8ff827e390",
+          "from": "obsidian@github:obsidianmd/obsidian-api#master",
+          "requires": {
+            "@types/codemirror": "5.60.8",
+            "moment": "2.29.4"
+          }
+        },
         "tslib": {
           "version": "2.1.0",
           "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
@@ -11630,6 +11686,12 @@
       "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
       "dev": true
     },
+    "querystringify": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+      "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+      "dev": true
+    },
     "queue-microtask": {
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -11648,6 +11710,12 @@
       "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
       "dev": true
     },
+    "requires-port": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+      "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+      "dev": true
+    },
     "resolve": {
       "version": "1.22.0",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
@@ -12038,14 +12106,23 @@
       }
     },
     "tough-cookie": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
-      "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==",
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
+      "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
       "dev": true,
       "requires": {
         "psl": "^1.1.33",
         "punycode": "^2.1.1",
-        "universalify": "^0.1.2"
+        "universalify": "^0.2.0",
+        "url-parse": "^1.5.3"
+      },
+      "dependencies": {
+        "universalify": {
+          "version": "0.2.0",
+          "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
+          "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
+          "dev": true
+        }
       }
     },
     "ts-jest": {
@@ -12149,9 +12226,9 @@
       "dev": true
     },
     "ttypescript": {
-      "version": "1.5.13",
-      "resolved": "https://registry.npmjs.org/ttypescript/-/ttypescript-1.5.13.tgz",
-      "integrity": "sha512-KT/RBfGGlVJFqEI8cVvI3nMsmYcFvPSZh8bU0qX+pAwbi7/ABmYkzn7l/K8skw0xmYjVCoyaV6WLsBQxdadybQ==",
+      "version": "1.5.15",
+      "resolved": "https://registry.npmjs.org/ttypescript/-/ttypescript-1.5.15.tgz",
+      "integrity": "sha512-48ykDNHzFnPMnv4hYX1P8Q84TvCZyL1QlFxeuxsuZ48X2+ameBgPenvmCkHJtoOSxpoWTWi8NcgNrRnVDOmfSg==",
       "dev": true,
       "requires": {
         "resolve": ">=1.9.0"
@@ -12211,6 +12288,16 @@
         "tslib": "^2"
       }
     },
+    "url-parse": {
+      "version": "1.5.10",
+      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+      "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+      "dev": true,
+      "requires": {
+        "querystringify": "^2.1.1",
+        "requires-port": "^1.0.0"
+      }
+    },
     "v8-compile-cache-lib": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
@@ -12270,9 +12357,9 @@
       }
     },
     "word-wrap": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
-      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
+      "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
       "dev": true
     },
     "wrap-ansi": {
diff --git a/package.json b/package.json
index 0af5283..ac277b4 100644
--- a/package.json
+++ b/package.json
@@ -34,7 +34,7 @@
     "@zerollup/ts-transform-paths": "^1.7.18",
     "compare-versions": "^4.1.1",
     "jest": "^27.1.0",
-    "obsidian": "^1.2.8",
+    "obsidian": "^1.4.0",
     "prettier": "2.3.2",
     "rollup": "^2.67.2",
     "rollup-jest": "^1.1.3",
@@ -43,7 +43,7 @@
     "rollup-plugin-web-worker-loader": "^1.6.1",
     "ts-jest": "^27.0.5",
     "tslib": "^2.3.1",
-    "ttypescript": "^1.5.12",
+    "ttypescript": "^1.5.15",
     "typescript": "^4.4.2"
   },
   "dependencies": {
diff --git a/src/api/inline-api.ts b/src/api/inline-api.ts
index fbbd3db..de1ba28 100644
--- a/src/api/inline-api.ts
+++ b/src/api/inline-api.ts
@@ -316,46 +316,28 @@ export class DataviewInlineApi {
      */
     public async view(viewName: string, input: any) {
         // Look for `${viewName}.js` first, then for `${viewName}/view.js`.
-        let simpleViewFile = this.app.metadataCache.getFirstLinkpathDest(viewName + ".js", this.currentFilePath);
-        if (simpleViewFile) {
-            let contents = await this.app.vault.read(simpleViewFile);
-            if (contents.contains("await")) contents = "(async () => { " + contents + " })()";
-            let func = new Function("dv", "input", contents);
-
-            try {
-                // This may directly render, in which case it will likely return undefined or null.
-                let result = await Promise.resolve(func(this, input));
-                if (result)
-                    await renderValue(
-                        result as any,
-                        this.container,
-                        this.currentFilePath,
-                        this.component,
-                        this.settings,
-                        true
-                    );
-            } catch (ex) {
-                renderErrorPre(this.container, `Dataview: Failed to execute view '${simpleViewFile.path}'.\n\n${ex}`);
-            }
-
-            return;
+        const simpleViewPath = `${viewName}.js`;
+        const complexViewPath = `${viewName}/view.js`;
+        let checkForCss = false;
+        let viewFile = this.app.metadataCache.getFirstLinkpathDest(simpleViewPath, this.currentFilePath);
+        if (!viewFile) {
+            viewFile = this.app.metadataCache.getFirstLinkpathDest(complexViewPath, this.currentFilePath);
+            checkForCss = true;
         }
 
-        // No `{viewName}.js`, so look for a folder instead.
-        let viewPath = `${viewName}/view.js`;
-        let viewFile = this.app.metadataCache.getFirstLinkpathDest(viewPath, this.currentFilePath);
-
         if (!viewFile) {
-            renderErrorPre(this.container, `Dataview: custom view not found for '${viewPath}' or '${viewName}.js'.`);
+            renderErrorPre(this.container, `Dataview: custom view not found for '${simpleViewPath}' or '${complexViewPath}'.`);
             return;
         }
 
-        let viewContents = await this.app.vault.read(viewFile);
-        if (viewContents.contains("await")) viewContents = "(async () => { " + viewContents + " })()";
-        let viewFunction = new Function("dv", "input", viewContents);
+        let contents = await this.app.vault.read(viewFile);
+        if (contents.contains("await")) contents = "(async () => { " + contents + " })()";
+        contents += `\n//# sourceURL=${viewFile.path}`;
+        let func = new Function("dv", "input", contents);
 
         try {
-            let result = await Promise.resolve(viewFunction(this, input));
+            // This may directly render, in which case it will likely return undefined or null.
+            let result = await Promise.resolve(func(this, input));
             if (result)
                 await renderValue(
                     result as any,
@@ -366,7 +348,11 @@ export class DataviewInlineApi {
                     true
                 );
         } catch (ex) {
-            renderErrorPre(this.container, `Dataview: Error while executing view '${viewFile.path}'.\n\n${ex}`);
+            renderErrorPre(this.container, `Dataview: Failed to execute view '${viewFile.path}'.\n\n${ex}`);
+        }
+
+        if (!checkForCss) {
+            return;
         }
 
         // Check for optional CSS.
@@ -374,6 +360,7 @@ export class DataviewInlineApi {
         if (!cssFile) return;
 
         let cssContents = await this.app.vault.read(cssFile);
+        cssContents += `\n/*# sourceURL=${location.origin}/${cssFile.path} */`
         this.container.createEl("style", { text: cssContents, attr: { scope: " " } });
     }
 
diff --git a/src/api/plugin-api.ts b/src/api/plugin-api.ts
index e467c84..ba2ecec 100644
--- a/src/api/plugin-api.ts
+++ b/src/api/plugin-api.ts
@@ -358,25 +358,19 @@ export class DataviewApi {
      * execution via `result.successful` and obtain `result.value` or `result.error` resultingly. If
      * you'd rather this method throw on an error, use `dv.tryEvaluate`.
      */
-    public evaluate(
-        expression: string,
-        context?: DataObject,
-        originFile?: string): Result<Literal, string> {
+    public evaluate(expression: string, context?: DataObject, originFile?: string): Result<Literal, string> {
         let field = EXPRESSION.field.parse(expression);
         if (!field.status) return Result.failure(`Failed to parse expression "${expression}"`);
 
         let evaluationContext = originFile
             ? new Context(defaultLinkHandler(this.index, originFile), this.settings)
-            : this.evaluationContext
+            : this.evaluationContext;
 
         return evaluationContext.evaluate(field.value, context);
     }
 
     /** Error-throwing version of `dv.evaluate`. */
-    public tryEvaluate(
-        expression: string,
-        context?: DataObject,
-        originFile?: string): Literal {
+    public tryEvaluate(expression: string, context?: DataObject, originFile?: string): Literal {
         return this.evaluate(expression, context, originFile).orElseThrow();
     }
 
diff --git a/src/data-import/markdown-file.ts b/src/data-import/markdown-file.ts
index 22f5f5e..e223da8 100644
--- a/src/data-import/markdown-file.ts
+++ b/src/data-import/markdown-file.ts
@@ -35,6 +35,14 @@ export function parsePage(path: string, contents: string, stat: FileStats, metad
         }
     }
 
+    // Add frontmatter links to links.
+    if (metadata.frontmatterLinks) {
+        for (let rawLink of metadata.frontmatterLinks || []) {
+            const link = Link.infer(rawLink.link, false, rawLink.displayText);
+            links.push(link);
+        }
+    }
+
     // Links in metadata.
     const linksByLine: Record<number, Link[]> = {};
     for (let rawLink of metadata.links || []) {
diff --git a/src/expression/functions.ts b/src/expression/functions.ts
index a286419..be00c31 100644
--- a/src/expression/functions.ts
+++ b/src/expression/functions.ts
@@ -353,6 +353,24 @@ export namespace DefaultFunctions {
         .vectorize(2, [0])
         .build();
 
+    export const trunc = new FunctionBuilder("trunc")
+        .add1("number", n => Math.trunc(n))
+        .add1("null", () => null)
+        .vectorize(1, [0])
+        .build();
+
+    export const floor = new FunctionBuilder("floor")
+        .add1("number", n => Math.floor(n))
+        .add1("null", () => null)
+        .vectorize(1, [0])
+        .build();
+
+    export const ceil = new FunctionBuilder("ceil")
+        .add1("number", n => Math.ceil(n))
+        .add1("null", () => null)
+        .vectorize(1, [0])
+        .build();
+
     export const min: FunctionImpl = new FunctionBuilder("min")
         .add2("*", "null", (a, _n) => a)
         .add2("null", "*", (_n, a) => a)
@@ -811,6 +829,9 @@ export const DEFAULT_FUNCTIONS: Record<string, FunctionImpl> = {
 
     // Math Operations.
     round: DefaultFunctions.round,
+    trunc: DefaultFunctions.trunc,
+    floor: DefaultFunctions.floor,
+    ceil: DefaultFunctions.ceil,
     min: DefaultFunctions.min,
     max: DefaultFunctions.max,
     minby: DefaultFunctions.minby,
diff --git a/src/query/parse.ts b/src/query/parse.ts
index 8572c33..c0f185e 100644
--- a/src/query/parse.ts
+++ b/src/query/parse.ts
@@ -62,6 +62,12 @@ function stripNewlines(text: string): string {
         .join("");
 }
 
+/** Given `parser`, return the parser that returns `if_eof()` if EOF is found,
+ * otherwise `parser` preceded by (non-optional) whitespace */
+function precededByWhitespaceIfNotEof<T>(if_eof: (_: undefined) => T, parser: P.Parser<T>): P.Parser<T> {
+    return P.eof.map(if_eof).or(P.whitespace.then(parser));
+}
+
 /** A parsimmon-powered parser-combinator implementation of the query language. */
 export const QUERY_LANGUAGE = P.createLanguage<QueryLanguageTypes>({
     // Simple atom parsing, like words, identifiers, numbers.
@@ -98,45 +104,53 @@ export const QUERY_LANGUAGE = P.createLanguage<QueryLanguageTypes>({
 
     headerClause: q =>
         q.queryType
-            .skip(P.whitespace)
-            .chain(qtype => {
-                switch (qtype) {
-                    case "table":
-                        return P.seqMap(
-                            P.regexp(/WITHOUT\s+ID/i)
-                                .skip(P.optWhitespace)
-                                .atMost(1),
-                            P.sepBy(q.namedField, P.string(",").trim(P.optWhitespace)),
-                            (withoutId, fields) => {
-                                return { type: "table", fields, showId: withoutId.length == 0 } as QueryHeader;
-                            }
+            .chain(type => {
+                switch (type) {
+                    case "table": {
+                        return precededByWhitespaceIfNotEof(
+                            () => ({ type, fields: [], showId: true }),
+                            P.seqMap(
+                                P.regexp(/WITHOUT\s+ID/i)
+                                    .skip(P.optWhitespace)
+                                    .atMost(1),
+                                P.sepBy(q.namedField, P.string(",").trim(P.optWhitespace)),
+                                (withoutId, fields) => {
+                                    return { type, fields, showId: withoutId.length == 0 };
+                                }
+                            )
                         );
+                    }
                     case "list":
-                        return P.seqMap(
-                            P.regexp(/WITHOUT\s+ID/i)
-                                .skip(P.optWhitespace)
-                                .atMost(1),
-                            EXPRESSION.field.atMost(1),
-                            (withoutId, format) => {
-                                return {
-                                    type: "list",
-                                    format: format.length == 1 ? format[0] : undefined,
-                                    showId: withoutId.length == 0,
-                                } as QueryHeader;
-                            }
+                        return precededByWhitespaceIfNotEof(
+                            () => ({ type, format: undefined, showId: true }),
+                            P.seqMap(
+                                P.regexp(/WITHOUT\s+ID/i)
+                                    .skip(P.optWhitespace)
+                                    .atMost(1),
+                                EXPRESSION.field.atMost(1),
+                                (withoutId, format) => {
+                                    return {
+                                        type,
+                                        format: format.length == 1 ? format[0] : undefined,
+                                        showId: withoutId.length == 0,
+                                    };
+                                }
+                            )
                         );
                     case "task":
-                        return P.succeed({ type: "task" } as QueryHeader);
+                        return P.succeed({ type });
                     case "calendar":
-                        return P.seqMap(q.namedField, field => {
-                            return {
-                                type: "calendar",
-                                showId: true,
-                                field,
-                            } as QueryHeader;
-                        });
+                        return P.whitespace.then(
+                            P.seqMap(q.namedField, field => {
+                                return {
+                                    type,
+                                    showId: true,
+                                    field,
+                                } as QueryHeader;
+                            })
+                        );
                     default:
-                        return P.fail(`Unrecognized query type '${qtype}'`);
+                        return P.fail(`Unrecognized query type '${type}'`);
                 }
             })
             .desc("TABLE or LIST or TASK or CALENDAR"),
diff --git a/src/ui/views/task-view.tsx b/src/ui/views/task-view.tsx
index c52750e..9be0577 100644
--- a/src/ui/views/task-view.tsx
+++ b/src/ui/views/task-view.tsx
@@ -346,7 +346,7 @@ export function setTaskCompletion(
     completionDateFormat: string,
     complete: boolean
 ): string {
-    const blockIdRegex = /\^[a-z0-9\-]+/i;
+    const blockIdRegex = /(?<!#)\^[a-z0-9\-]+/i;
 
     if (!complete && !useEmojiShorthand)
         return trimEndingLines(setInlineField(originalText.trimEnd(), completionKey)).trimEnd();


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 8a9ca4a..479d304 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -15,6 +15,7 @@ jobs:
         uses: actions/setup-node@v3
         with:
           node-version: 16
+      - run: npm install
       - run: npm run check-format
   build:
     runs-on: ubuntu-latest
diff --git a/src/test/parse/parse.query.test.ts b/src/test/parse/parse.query.test.ts
index b3f7323..d78b4c2 100644
--- a/src/test/parse/parse.query.test.ts
+++ b/src/test/parse/parse.query.test.ts
@@ -1,9 +1,26 @@
-import { TableQuery, ListQuery, CalendarQuery, SortByStep, QueryFields } from "query/query";
+import { TableQuery, ListQuery, CalendarQuery, SortByStep, QueryFields, Query } from "query/query";
 import { QUERY_LANGUAGE, parseQuery } from "query/parse";
 import { Sources } from "data-index/source";
 import { DEFAULT_QUERY_SETTINGS } from "settings";
 import { Fields } from "expression/field";
 
+function testQueryTypeAlone(name: string) {
+    const upper = name.toUpperCase();
+    const lower = name.toLowerCase();
+
+    function expectQ(q: Query) {
+        expect(q.header.type).toBe(lower);
+    }
+
+    const tests = [upper, lower].flatMap(type => ["", " ", "\n", " \n", "\n "].map(suffix => type + suffix));
+
+    test(`Just ${upper}`, () => {
+        for (const test of tests) {
+            expectQ(parseQuery(test).orElseThrow());
+        }
+    });
+}
+
 test("Parse Query Type", () => {
     let unknown = QUERY_LANGUAGE.queryType.parse("vehicle");
     expect(unknown.status).toBe(false);
@@ -56,14 +73,20 @@ test("Sort Fields", () => {
 
 // <-- Full Queries -->
 
-test("Task query with no fields", () => {
-    let q = parseQuery("task from #games").orElseThrow();
-    expect(typeof q).toBe("object");
-    expect(q.header.type).toBe("task");
-    expect(q.source).toEqual(Sources.tag("#games"));
+describe("Task Queries", () => {
+    testQueryTypeAlone("task");
+
+    test("Task query with no fields", () => {
+        let q = parseQuery("task from #games").orElseThrow();
+        expect(typeof q).toBe("object");
+        expect(q.header.type).toBe("task");
+        expect(q.source).toEqual(Sources.tag("#games"));
+    });
 });
 
 describe("List Queries", () => {
+    testQueryTypeAlone("list");
+
     test("With Format", () => {
         let query = parseQuery("LIST file.name FROM #games").orElseThrow();
         expect(query.header.type).toBe("list");
@@ -79,6 +102,8 @@ describe("List Queries", () => {
 });
 
 describe("Table Queries", () => {
+    testQueryTypeAlone("table");
+
     test("Minimal Query", () => {
         let simple = parseQuery("TABLE time-played, rating, length FROM #games").orElseThrow();
         expect(simple.header.type).toBe("table");
diff --git a/test-vault/.obsidian/app.json b/test-vault/.obsidian/app.json
deleted file mode 100644
index 9e26dfe..0000000
--- a/test-vault/.obsidian/app.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{}
\ No newline at end of file
diff --git a/test-vault/.obsidian/appearance.json b/test-vault/.obsidian/appearance.json
deleted file mode 100644
index eb8b005..0000000
--- a/test-vault/.obsidian/appearance.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "baseFontSize": 11,
-  "theme": "moonstone"
-}
\ No newline at end of file
diff --git a/test-vault/.obsidian/core-plugins.json b/test-vault/.obsidian/core-plugins.json
deleted file mode 100644
index 26bc70e..0000000
--- a/test-vault/.obsidian/core-plugins.json
+++ /dev/null
@@ -1,14 +0,0 @@
-[
-  "file-explorer",
-  "global-search",
-  "switcher",
-  "graph",
-  "backlink",
-  "page-preview",
-  "note-composer",
-  "command-palette",
-  "markdown-importer",
-  "word-count",
-  "open-with-default-app",
-  "file-recovery"
-]
\ No newline at end of file
diff --git a/test-vault/.obsidian/hotkeys.json b/test-vault/.obsidian/hotkeys.json
deleted file mode 100644
index 9e26dfe..0000000
--- a/test-vault/.obsidian/hotkeys.json
+++ /dev/null
@@ -1,1 +0,0 @@
-{}
\ No newline at end of file
diff --git a/test-vault/untracked/README.md b/test-vault/untracked/README.md
new file mode 100644
index 0000000..bc5bad2
--- /dev/null
+++ b/test-vault/untracked/README.md
@@ -0,0 +1,3 @@
+Git will not track files in this folder. (except this one)
+
+Feel free to write whatever for anything you want to try. Git won't see it and it won't clog up your `git status`. But if its an important thing to test, maybe include it somewhere where other people can test it too. Thanks :)