can now generate mdx from nunjucks

This commit is contained in:
Felix Roos 2022-05-24 00:03:59 +02:00
parent b5b0fbbd38
commit 4acdabe439
10 changed files with 627 additions and 274 deletions

570
doc.json

File diff suppressed because it is too large Load Diff

View File

@ -16,8 +16,9 @@ import drawLine from './drawLine.mjs';
/** @class Class representing a pattern. */ /** @class Class representing a pattern. */
export class Pattern { export class Pattern {
/** /**
* Create a pattern. * Create a pattern. As an end user, you will most likely not create a Pattern directly.
* @param {function} query - The function that maps a State to Haps . *
* @param {function} query - The function that maps a {@link State} to an array of {@link Hap}.
*/ */
constructor(query) { constructor(query) {
this.query = query; this.query = query;
@ -731,11 +732,31 @@ export class Pattern {
return this._compress(span.begin, span.end); return this._compress(span.begin, span.end);
} }
/**
* Speed up a pattern by the given factor.
*
* @name fast
* @memberof Pattern
* @param {number | Pattern} factor speed up factor
* @returns Pattern
* @example
* seq(e5, b4, d5, c5).fast(2)
*/
_fast(factor) { _fast(factor) {
const fastQuery = this.withQueryTime((t) => t.mul(factor)); const fastQuery = this.withQueryTime((t) => t.mul(factor));
return fastQuery.withHapTime((t) => t.div(factor)); return fastQuery.withHapTime((t) => t.div(factor));
} }
/**
* Slow down a pattern over the given number of cycles.
*
* @name slow
* @memberof Pattern
* @param {number | Pattern} factor slow down factor
* @returns Pattern
* @example
* seq(e5, b4, d5, c5).slow(2)
*/
_slow(factor) { _slow(factor) {
return this._fast(Fraction(1).div(factor)); return this._fast(Fraction(1).div(factor));
} }
@ -1022,6 +1043,7 @@ export class Pattern {
return this._withContext((context) => ({ ...context, velocity: (context.velocity || 1) * velocity })); return this._withContext((context) => ({ ...context, velocity: (context.velocity || 1) * velocity }));
} }
// move this to controls? (speed and unit are controls)
_loopAt(factor, cps = 1) { _loopAt(factor, cps = 1) {
return this.speed((1 / factor) * cps) return this.speed((1 / factor) * cps)
.unit('c') .unit('c')
@ -1265,8 +1287,8 @@ export function slowcatPrime(...pats) {
* @return {Pattern} * @return {Pattern}
* @example * @example
* fastcat(e5, b4, [d5, c5]) * fastcat(e5, b4, [d5, c5])
* sequence(e5, b4, [d5, c5]) * // sequence(e5, b4, [d5, c5])
* seq(e5, b4, [d5, c5]) * // seq(e5, b4, [d5, c5])
*/ */
export function fastcat(...pats) { export function fastcat(...pats) {
return slowcat(...pats)._fast(pats.length); return slowcat(...pats)._fast(pats.length);

View File

@ -8,7 +8,8 @@ function ApiDoc() {
if (!visible) { if (!visible) {
return ( return (
<p> <p>
The API Docs are a work in progress, but you can preview it by clicking <a href="?api=true#api-docs">here</a> There remaining function documentation is a work in progress, but you can preview it by clicking{' '}
<a href="?api=true#everything-else">here</a>. Beware that everything is not properly ordered from this point.
</p> </p>
); );
} }
@ -16,8 +17,8 @@ function ApiDoc() {
return ( return (
<div> <div>
<p> <p>
The following Chapter is the technical API documentation. It is autogenerated from the jsdoc comments in the The following Chapter is autogenerated from the jsdoc comments in the source files.{' '}
source files. <a href="?#api-docs">hide</a> <a href="?#everything-else">hide</a>. Beware that everything is not properly ordered from this point.
</p> </p>
{docs {docs
.filter((item) => !item.name?.startsWith('_') && item.kind !== 'package') .filter((item) => !item.name?.startsWith('_') && item.kind !== 'package')

View File

@ -7,6 +7,8 @@ This program is free software: you can redistribute it and/or modify it under th
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import Tutorial from './tutorial.mdx'; import Tutorial from './tutorial.mdx';
import ApiDoc from './ApiDoc'
import Api from './api.mdx';
import './style.scss'; import './style.scss';
import '@strudel.cycles/react/dist/style.css'; import '@strudel.cycles/react/dist/style.css';
@ -30,6 +32,8 @@ ReactDOM.render(
</header> </header>
<main className="p-4 pl-6 max-w-3xl prose"> <main className="p-4 pl-6 max-w-3xl prose">
<Tutorial /> <Tutorial />
<Api />
<ApiDoc />
</main> </main>
</div> </div>
</React.StrictMode>, </React.StrictMode>,

123
tutorial/api.mdx Normal file
View File

@ -0,0 +1,123 @@
import { MiniRepl } from './MiniRepl';
The following is generated from the source documentation.
## TOC
## Pattern Factories
The following functions will return a pattern. We will see later what that means.
### pure
<p>A discrete value that repeats once per cycle:</p>
**Parameters**
- value (any): The value to repeat
**Examples**
<div className="space-y-2">
<MiniRepl tune={`pure('e4')`} />
</div>
### slowcat
<p>Concatenation: combines a list of patterns, switching between them successively, one per cycle:</p>
<p>synonyms: <a href="#cat">cat</a></p>
**Parameters**
- items (any): The items to concatenate
**Examples**
<div className="space-y-2">
<MiniRepl tune={`slowcat(e5, b4, [d5, c5])`} />
</div>
### fastcat
<p>Concatenation: as with <a href="#slowcat">slowcat</a>, but squashes a cycle from each pattern into one cycle</p>
<p>Synonyms: <a href="#seq">seq</a>, <a href="#sequence">sequence</a></p>
**Parameters**
- items (any): The items to concatenate
**Examples**
<div className="space-y-2">
<MiniRepl tune={`fastcat(e5, b4, [d5, c5])
// sequence(e5, b4, [d5, c5])
// seq(e5, b4, [d5, c5])`} />
</div>
### stack
<p>The given items are played at the same time at the same length:</p>
**Parameters**
- items (any): The items to stack
**Examples**
<div className="space-y-2">
<MiniRepl tune={`stack(g3, b3, [e4, d4])`} />
</div>
### timeCat
<p>Like <a href="#fastcat">fastcat</a>, but where each step has a temporal weight:</p>
**Parameters**
- items (Array): The items to concatenate
**Examples**
<div className="space-y-2">
<MiniRepl tune={`timeCat([3,e3],[1, g3])`} />
</div>
## Pattern Modifiers
### Pattern.slow
<p>Slow down a pattern over the given number of cycles.</p>
**Parameters**
- factor (number|Pattern): slow down factor
**Examples**
<div className="space-y-2">
<MiniRepl tune={`seq(e5, b4, d5, c5).slow(2)`} />
</div>
### Pattern.fast
<p>Speed up a pattern by the given factor.</p>
**Parameters**
- factor (number|Pattern): speed up factor
**Examples**
<div className="space-y-2">
<MiniRepl tune={`seq(e5, b4, d5, c5).fast(2)`} />
</div>
## Everything Else

View File

@ -21,6 +21,7 @@
"autoprefixer": "^10.4.7", "autoprefixer": "^10.4.7",
"install": "^0.13.0", "install": "^0.13.0",
"npm": "^8.10.0", "npm": "^8.10.0",
"nunjucks": "^3.2.3",
"postcss": "^8.4.13", "postcss": "^8.4.13",
"rehype-autolink-headings": "^6.1.1", "rehype-autolink-headings": "^6.1.1",
"rehype-slug": "^5.0.1", "rehype-slug": "^5.0.1",
@ -795,6 +796,12 @@
"semver": "bin/semver.js" "semver": "bin/semver.js"
} }
}, },
"node_modules/a-sync-waterfall": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
"integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==",
"dev": true
},
"node_modules/acorn": { "node_modules/acorn": {
"version": "7.4.1", "version": "7.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
@ -858,6 +865,12 @@
"integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==", "integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==",
"dev": true "dev": true
}, },
"node_modules/asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
"dev": true
},
"node_modules/autoprefixer": { "node_modules/autoprefixer": {
"version": "10.4.7", "version": "10.4.7",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.7.tgz", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.7.tgz",
@ -1146,6 +1159,15 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/commander": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
"dev": true,
"engines": {
"node": ">= 6"
}
},
"node_modules/convert-source-map": { "node_modules/convert-source-map": {
"version": "1.8.0", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
@ -4825,6 +4847,31 @@
"inBundle": true, "inBundle": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/nunjucks": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.3.tgz",
"integrity": "sha512-psb6xjLj47+fE76JdZwskvwG4MYsQKXUtMsPh6U0YMvmyjRtKRFcxnlXGWglNybtNTNVmGdp94K62/+NjF5FDQ==",
"dev": true,
"dependencies": {
"a-sync-waterfall": "^1.0.0",
"asap": "^2.0.3",
"commander": "^5.1.0"
},
"bin": {
"nunjucks-precompile": "bin/precompile"
},
"engines": {
"node": ">= 6.9.0"
},
"peerDependencies": {
"chokidar": "^3.3.0"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
}
},
"node_modules/object-assign": { "node_modules/object-assign": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@ -6992,6 +7039,12 @@
} }
} }
}, },
"a-sync-waterfall": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
"integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==",
"dev": true
},
"acorn": { "acorn": {
"version": "7.4.1", "version": "7.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
@ -7040,6 +7093,12 @@
"integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==", "integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==",
"dev": true "dev": true
}, },
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
"dev": true
},
"autoprefixer": { "autoprefixer": {
"version": "10.4.7", "version": "10.4.7",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.7.tgz", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.7.tgz",
@ -7224,6 +7283,12 @@
"integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==",
"dev": true "dev": true
}, },
"commander": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
"dev": true
},
"convert-source-map": { "convert-source-map": {
"version": "1.8.0", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
@ -9740,6 +9805,17 @@
} }
} }
}, },
"nunjucks": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.3.tgz",
"integrity": "sha512-psb6xjLj47+fE76JdZwskvwG4MYsQKXUtMsPh6U0YMvmyjRtKRFcxnlXGWglNybtNTNVmGdp94K62/+NjF5FDQ==",
"dev": true,
"requires": {
"a-sync-waterfall": "^1.0.0",
"asap": "^2.0.3",
"commander": "^5.1.0"
}
},
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",

View File

@ -7,7 +7,8 @@
"start": "vite", "start": "vite",
"build": "npm run jsdoc-json && vite build", "build": "npm run jsdoc-json && vite build",
"preview": "vite preview", "preview": "vite preview",
"jsdoc-json": "jsdoc ../packages/ --template ../node_modules/jsdoc-json --destination ../doc.json -c ../jsdoc.config.json" "jsdoc-json": "jsdoc ../packages/ --template ../node_modules/jsdoc-json --destination ../doc.json -c ../jsdoc.config.json",
"render": "npm run jsdoc-json && node ./render.js > api.mdx"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
@ -24,6 +25,7 @@
"autoprefixer": "^10.4.7", "autoprefixer": "^10.4.7",
"install": "^0.13.0", "install": "^0.13.0",
"npm": "^8.10.0", "npm": "^8.10.0",
"nunjucks": "^3.2.3",
"postcss": "^8.4.13", "postcss": "^8.4.13",
"rehype-autolink-headings": "^6.1.1", "rehype-autolink-headings": "^6.1.1",
"rehype-slug": "^5.0.1", "rehype-slug": "^5.0.1",

49
tutorial/render.js Normal file
View File

@ -0,0 +1,49 @@
import nunjucks from 'nunjucks';
import jsdoc from '../doc.json' assert { type: 'json' };
// TODO: load tutorial.mdx and append rendered api.mdx to the bottom (to make sure TOC works)
// TODO: split
const env = nunjucks.configure('templates', { autoescape: false });
const docs = jsdoc.docs.reduce((acc, obj) => Object.assign(acc, { [obj.longname]: obj }), {});
function renderAsMDX(name) {
const item = docs[name];
if (!item) {
console.warn('Not found: ' + name);
return '';
}
return `### ${item.longname}
${item.description.replaceAll(/\{\@link ([a-zA-Z]+)?\#?([a-zA-Z]*)\}/g, (_, a, b) => {
// console.log(_, 'a', a, 'b', b);
return `<a href="#${a}${b ? `-${b}` : ''}">${a}${b ? `#${b}` : ''}</a>`;
})}
${!!item.params?.length ? '**Parameters**' : ''}
${
item.params
?.map(
(param, i) =>
`- ${param.name} (${param.type?.names?.join('|')}): ${param.description?.replace(/(<([^>]+)>)/gi, '')}`,
)
.join('\n') || ''
}
${
item.examples?.length
? `**Examples**
<div className="space-y-2">
${item.examples?.map((example, k) => `<MiniRepl tune={\`${example}\`} />`).join('\n\n')}
</div>`
: ''
}`;
}
env.addFilter('jsdoc', renderAsMDX);
const rendered = nunjucks.render('api.mdx', { docs });
console.log(rendered);

View File

@ -0,0 +1,35 @@
import { MiniRepl } from './MiniRepl';
The following is generated from the source documentation.
## TOC
## Pattern Factories
The following functions will return a pattern. We will see later what that means.
{{ 'pure' | jsdoc }}
{{ 'slowcat' | jsdoc }}
{{ 'fastcat' | jsdoc }}
{{ 'stack' | jsdoc }}
{{ 'timeCat' | jsdoc }}
{{ 'polyrhythm' | jsdoc }}
## Pattern Modifiers
{{ 'Pattern.slow' | jsdoc }}
{{ 'Pattern.fast' | jsdoc }}
{{ 'Pattern.early' | jsdoc }}
{{ 'Pattern.late' | jsdoc }}
{{ 'Pattern.rev' | jsdoc }}
## Everything Else

View File

@ -694,11 +694,8 @@ If you want to contribute in another way, either
- [Join the Discord Channel](https://discord.gg/remJ6gQA) - [Join the Discord Channel](https://discord.gg/remJ6gQA)
- [play with the Strudel REPL](https://strudel.tidalcycles.org/) - [play with the Strudel REPL](https://strudel.tidalcycles.org/)
import ApiDoc from './ApiDoc';
<br /> <br />
<br /> <br />
# API Docs # API Docs
<ApiDoc />