From 6cf0e31515061dfe86c5d9d4a402057bb65fd563 Mon Sep 17 00:00:00 2001 From: Roman Dvornov Date: Wed, 8 Nov 2023 17:51:23 +0100 Subject: [PATCH] Add TOC for builtin methods page --- docs/articles/functions.md | 4 +- docs/articles/methods-builtin.md | 50 +++++++------- docs/discovery/common.css | 2 +- docs/discovery/data.js | 12 +++- docs/discovery/pages/article.css | 65 ++++++++++++++++++ docs/discovery/pages/article.js | 109 +++++++++++++++++++++++++++++-- 6 files changed, 206 insertions(+), 36 deletions(-) diff --git a/docs/articles/functions.md b/docs/articles/functions.md index a6578a4..42a6d2f 100644 --- a/docs/articles/functions.md +++ b/docs/articles/functions.md @@ -33,7 +33,7 @@ $example: => [$, $$]; // Result: [1, 2] ``` -The following example demonstrates how to sum up an array using [`reduce()`](./methods-builtin.md#reducefn-initvalue) method and a function, where `$` is an array element and `$$` is an accumulator value: +The following example demonstrates how to sum up an array using [`reduce()`](./methods-builtin.md#reduce) method and a function, where `$` is an array element and `$$` is an accumulator value: ```jora [1, 2, 3, 4].reduce(=> $$ + $, 0) @@ -80,7 +80,7 @@ foo asc, bar.size() desc // 0 ``` -These functions are useful for built-in methods like [`sort()`](./sort.md), [`min()`](./methods-builtin.md#mincompare), [`max()`](./methods-builtin.md#maxcompare) and others. +These functions are useful for built-in methods like [`sort()`](./sort.md), [`min()`](./methods-builtin.md#min), [`max()`](./methods-builtin.md#max) and others. ```jora $input: [{ foo: 3 }, { foo: 1 }, { foo: 5 }]; diff --git a/docs/articles/methods-builtin.md b/docs/articles/methods-builtin.md index 1dd7356..dcd5708 100644 --- a/docs/articles/methods-builtin.md +++ b/docs/articles/methods-builtin.md @@ -1,6 +1,6 @@ # Built-in methods -## avg(getter) +## avg() The `avg(getter)` method calculates the [arithmetic mean](https://en.wikipedia.org/wiki/Arithmetic_mean), also known as the average, of a collection of numbers. The arithmetic mean is computed by adding all the numbers in the collection and then dividing by the total count of numbers. This method is equivalent to the expressions `numbers() | sum() / size()` or `sum() / count()`. @@ -42,7 +42,7 @@ Similar to `Boolean()` in JavaScript, but treats *empty arrays* and *objects wit // Result: true ``` -## count(getter) +## count() The `count()` method calculates the number of non-undefined values present in the input array. It processes each value in the array through a `getter` function (default function is `=> $`). If the processed value is not `undefined`, it increments the count by 1. If the input is not an array, the method returns `0`. This method is functionally equivalent to the expression `numbers().size()`. @@ -89,7 +89,7 @@ Similar to `Object.entries()` in JavaScript, using `{ key, value }` objects for // Result: [] ``` -## filter(fn) +## filter() The same as `Array#filter()` in JavaScript, `filter(fn)` is equivalent to `.[fn()]` (see [Filtering](./filter.md)). @@ -112,11 +112,11 @@ Similar to `Object.fromEntries()` in JavaScript, expects array `{ key, value }` // Result: { a: 42, b: 123 } ``` -## group(fn, fn) +## group() Group array items by a value fetched with the first getter and return an array of `{ key, value }` entries (see [Grouping](./group.md)). -## indexOf(value, fromIndex) +## indexOf() Returns the first index of the specified value, starting the search at `fromIndex`. If `fromIndex` is not provided or cannot be converted to a number, the search starts from index `0`. The method returns `-1` if the value is not found or if the input doesn't implement the `indexOf()` method. Unlike JavaScript, this method supports index searching for `NaN` values. @@ -137,7 +137,7 @@ Returns the first index of the specified value, starting the search at `fromInde // Result: 1 ``` -## join(separator) +## join() The same as `Array#join()` in JavaScript. When `separator` is not specified, `","` is used. @@ -167,7 +167,7 @@ The same as `Object.keys()` in JavaScript. // Result: [] ``` -## lastIndexOf(value, fromIndex) +## lastIndexOf() Returns the first index of the specified value starting from the end at `fromIndex`. If `fromIndex` is not specified or cannot be converted to a number, it defaults to array or string length. The method returns `-1` if the value is not found or if the input doesn't implement the `lastIndexOf()` method. Unlike JavaScript, this method supports index searching for `NaN` values. @@ -188,7 +188,7 @@ Returns the first index of the specified value starting from the end at `fromInd // Result: 3 ``` -## map(fn) +## map() The same as `Array#map()` in JavaScript, is equivalent to `.(fn())` (see [Mapping](./map.md)). @@ -202,7 +202,7 @@ $getA: => a; // Result: [1, 2] ``` -## match(pattern, matchAll) +## match() Similar to `String#match()`. `pattern` might be a RegExp or string. When `matchAll` is truthy, returns an array of all occurrences of the `pattern`. Expressions `match(/…/g)` and `match(/…/, true)` are equivalent. @@ -259,7 +259,7 @@ Similar to `String#match()`. `pattern` might be a RegExp or string. When `matchA // }] ``` -## max(compare) +## max() The `max(compare)` method returns the maximum value from an array or a string, excluding `undefined`. It uses natural comparison for string values by default. When applied to an array, the method returns `undefined` if the array is empty or if a comparator function returns `0` for all values when compared with `undefined`. @@ -293,7 +293,7 @@ $input.max(a desc) // Result: 'w' ``` -## median(getter) +## median() Computes the [median](https://en.wikipedia.org/wiki/Median) (the second [quartile](https://en.wikipedia.org/wiki/Quartile)) of the values in an array. It's a shortcut for `percentile(50)` or `p(50)` (see [percentile()](#percentilevalue-getter)). @@ -306,7 +306,7 @@ Computes the [median](https://en.wikipedia.org/wiki/Median) (the second [quartil // Result: 3.5 ``` -## min(compare) +## min() The `min()` method returns the minimum value from an array or a string. It uses natural comparison for string values by default. When applied to an array, the method returns `undefined` if the array is empty or if a comparator function returns `0` for all values when compared with `undefined`. @@ -335,7 +335,7 @@ $input.min(a desc) // Result: ' ' ``` -## numbers(getter) +## numbers() The `numbers()` method returns an array of numbers derived from the input values. It ignores `undefined` values returned by the `getter` function (the default `getter` function is `=> $`, which returns the value itself). All other values are converted to numbers including `NaN` and `Infinity`. When converting a value to a number, any objects and arrays are converted to `NaN`. @@ -356,11 +356,11 @@ The `numbers()` method is utilized internally by statistical methods such as `su > Note: When applying a statistical computation to an array of objects, it is recommended to use a custom `getter` with the method rather than using dot notation or mapping. This is because dot notation and mapping ignore duplicate values. For instance, the query `[…].age.numbers()` might return `[10, 20]` for the last example instead of the expected `[10, 20, 10]`, which would be correctly returned by the query `[…].numbers(=> age)`. -## p(k, getter) +## p() Alias for [`percentile()`](#percentilek-getter) method. -## percentile(k, getter) +## percentile() This function computes the [percentile](https://en.wikipedia.org/wiki/Percentile) of values in an array. It returns `undefined` if the input is an empty array, not an array, or if the `k` parameter is not specified or falls outside the range of `[0..100]`. The function utilizes the same numbers as the [`numbers()`](#numbersgetter) method, given the same `getter` parameter. If the input (after processing through `getter`) contains a `NaN`, the function will always return `NaN`. @@ -401,7 +401,7 @@ Get a value by a key, index, or function. The method repeats behaviour of [Brack // Result: 2 ``` -## reduce(fn, initValue) +## reduce() The same as `Array#reduce()` in JS. Use `$$` to access the accumulator and `$` for the current value, e.g., find the max value: @@ -410,7 +410,7 @@ The same as `Array#reduce()` in JS. Use `$$` to access the accumulator and `$` f // Result: 5 ``` -## replace(pattern, replacement) +## replace() The same as `String#replaceAll()` in JavaScript, but also works for arrays. When `pattern` is RegExp, a `g` flags adds automatically if omitted. When applying to arrays it's similar to `.($ = pattern ? replacement : $)`, but without dropping duplicate values and inlining arrays. @@ -472,19 +472,19 @@ Returns count of entries in an object, otherwise returns `length` property value // Result: 0 ``` -## slice(from, to) +## slice() The same as `Array#slice()` and `String#slice()` in JavaScript (see also [Slice notation](./slice-notation.md)). -## sort(compare) +## sort() Sort an array by a value fetched with getter (`fn`). Can use sorting function definition syntax with `asc` and `desc` (see [Sorting](./sort.md)) -## split(pattern) +## split() The same as `String#split()` in JavaScript. `pattern` may be a string or regex. -## stdev(getter) +## stdev() Returns the [standard deviation](https://en.wikipedia.org/wiki/Standard_deviation) (`𝜎`) of a population, is the square root of the variance. @@ -497,7 +497,7 @@ Returns the [standard deviation](https://en.wikipedia.org/wiki/Standard_deviatio // Result: 1 ``` -## sum(getter) +## sum() Computes the sum of the values in an array. It returns `undefined` for non-array values and empty arrays. The method uses the same numbers as [`numbers()`](#numbersgetter) method with the same `getter` parameter returns. The method employs the [Kahan–Babuška summation algorithm](https://en.wikipedia.org/wiki/Kahan_summation_algorithm) to minimize numerical errors in the result. @@ -546,7 +546,7 @@ Since arrays are always converting to `NaN`. To summing array of arrays, a summa // Result: 7 ``` -## toLowerCase(locales) +## toLowerCase() The same as `String#toLocaleLowerCase()` in JavaScript. @@ -555,7 +555,7 @@ The same as `String#toLocaleLowerCase()` in JavaScript. // Result: "hello world!" ``` -## toUpperCase(locales) +## toUpperCase() The same as `String#toLocaleUpperCase()` in JavaScript. @@ -577,7 +577,7 @@ The same as `String#trim()` in JavaScript. The same as `Object.values()` in JavaScript. -## variance(getter) +## variance() Returns the [variance](http://en.wikipedia.org/wiki/Variance) (`𝜎²`) of a [population](https://en.wikipedia.org/wiki/Variance#Population_variance) (the squared deviation from the mean). diff --git a/docs/discovery/common.css b/docs/discovery/common.css index 81c3ef5..16b5b8c 100644 --- a/docs/discovery/common.css +++ b/docs/discovery/common.css @@ -86,7 +86,7 @@ .view-struct_code-postlude { padding-top: 1px; padding-bottom: 1px; - padding-left: 29px; + padding-left: 30px; } .view-struct_code-postlude:not(.struct-expanded-value, :hover) { background-color: transparent; diff --git a/docs/discovery/data.js b/docs/discovery/data.js index 598f448..bd6d3f9 100644 --- a/docs/discovery/data.js +++ b/docs/discovery/data.js @@ -4,6 +4,12 @@ const assert = require('assert'); const marked = require('marked'); const jora = require('jora'); const { parseExample } = require('./parse-example.js'); +const mathMethods = new Set([ + 'abs', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', + 'cbrt', 'ceil', 'clz32', 'cos', 'cosh', 'exp', 'expm1', 'floor', + 'fround', 'hypot', 'imul', 'ln', 'log10', 'ln1p', 'log2', 'pow', + 'round', 'sign', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc' +]); function md(filename) { return fs.readFileSync(path.join(__dirname, filename) + '.md', 'utf8'); @@ -152,7 +158,11 @@ function processChangelog(changelog, methods) { module.exports = function() { const examples = []; - const methods = Object.keys(jora.methods).sort().map(name => ({ name, examples: [] })); + const methods = Object.keys(jora.methods).sort().map(name => ({ + name, + namespace: mathMethods.has(name) ? 'math' : undefined, + examples: [] + })); const changelog = { slug: 'changelog', title: 'Changelog', headers: true, content: md('../../CHANGELOG') }; const articles = [ { slug: 'getting-started', title: 'Getting started', expanded: true, headers: true }, diff --git a/docs/discovery/pages/article.css b/docs/discovery/pages/article.css index ba0e6f2..874b3f2 100644 --- a/docs/discovery/pages/article.css +++ b/docs/discovery/pages/article.css @@ -9,3 +9,68 @@ .page-article .prev-next-nav { margin-top: 2em; } + +.page-article .view-page-header__content { + display: flex; + align-items: center; + gap: 1ex; +} +.page-article .scroll-to-top { + margin-top: 5px; + transition: .25s ease-in; + transition-property: opacity, visibility; + opacity: 0; + visibility: hidden; +} +.page-article.page_overscrolled .scroll-to-top { + opacity: 1; + visibility: visible; +} +.page-article .scroll-to-top-button { + font-size: 12px; + padding: 4px 8px; +} + +.page-article .toc-section-header { + text-transform: uppercase; + font-size: 11px; + opacity: .85; + margin: 8px 0 0 0; +} +.page-article .toc-group-item { + white-space: nowrap; + margin-right: 1ex; +} +.page-article .toc-litera { + display: inline-block; + color: #888; + text-transform: uppercase; + margin-right: 1ex; +} +.page-article .toc-group { + display: inline-flex; + gap: .75ex; +} + +.page-article .toc-filter { + margin-top: -20px; + margin-left: -10px; + margin-right: -10px; + max-width: 870px; +} +.page-article .toc-filter > .view-input { + margin-bottom: .5em; +} +.page-article .toc-filter > .content .view-list { + margin-left: 10px; +} +.page-article .toc-filter > .content .view-list::before { + padding: 0; +} + +.page-article .toc-filter .view-text-match { + background: #68624685; + text-decoration-color: #8b7b42; + border: none; + color: #b6aa6a; +} diff --git a/docs/discovery/pages/article.js b/docs/discovery/pages/article.js index 4b6c599..be7385c 100644 --- a/docs/discovery/pages/article.js +++ b/docs/discovery/pages/article.js @@ -1,23 +1,118 @@ /* global discovery */ +/* eslint-env browser */ + +const toc = { + view: 'content-filter', + className: 'toc-filter', + content: [ + { + view: 'list', + data: ` + #.data.methods + .[name ~= #.filter] + .group(=>namespace or "") + .({ + namespace: key, + methodGroups: value.sort(name ascN) + .group(=> name[0]) + .({ litera: key, methods: value }) + }) + .sort(namespace ascN) + `, + item: [ + { + view: 'block', + when: 'namespace', + className: 'toc-section-header', + content: 'text:namespace' + }, + { + view: 'inline-list', + data: 'methodGroups', + limit: false, + itemConfig: { + className: 'toc-group-item' + }, + item: [ + { + view: 'block', + className: 'toc-litera', + when: 'litera', + content: 'text:litera.toUpperCase() + " "' + }, + { + view: 'inline-list', + className: 'toc-group', + data: 'methods', + limit: false, + item: [ + { + view: 'link', + data: '{ href: `#${#.page}:${#.id}&!anchor=` + name, text: name, match: #.filter }', + content: 'text-match' + } + ] + } + ] + } + ] + } + ] +}; + discovery.page.define('article', { view: 'context', data: 'articles | $ + ..($parent:$; children.({ ..., $parent })) | $[=>slug=#.id]', content: [ { view: 'page-header', - content: { - view: 'h1', - data: '$ + ..parent | reverse().title', - content: { - view: 'inline-list', - className: 'article-path' + content: [ + { + view: 'h1', + data: '$ + ..parent | reverse().title', + content: [ + { + view: 'inline-list', + className: 'article-path' + } + ] + }, { + view: 'block', + when: '#.id = "jora-syntax-methods-builtin"', + className: 'scroll-to-top', + content: { + view: 'button', + className: 'scroll-to-top-button', + content: 'text:"Scroll to top"', + onClick(el) { + el.closest('.discovery-content').scrollTop = 0; + discovery.setPageParams({}); + } + } } - } + ] + }, + + { + view: 'context', + when: '#.id = "jora-syntax-methods-builtin"', + content: toc }, + { view: 'markdown', data: 'content', codeConfig: 'example', + postRender(el, _, __, context) { + if (context.id === 'jora-syntax-methods-builtin') { + [...el.querySelectorAll('.view-h2')].forEach(h2 => { + const comment = h2.childNodes[2]; + if (comment?.nodeType === 8) { + h2.replaceChild(document.createTextNode(comment.nodeValue), comment); + } + }); + } + }, sectionPrelude: { view: 'block', className: 'changelog',