metadata: add quotes syntax for titles

This commit is contained in:
Roipoussiere 2023-06-07 12:26:23 +02:00
parent 185318a70c
commit 51e8174689
5 changed files with 102 additions and 40 deletions

View File

@ -63,6 +63,51 @@ describe.concurrent('Metadata parser', () => {
}); });
}); });
it('loads a title tag with quotes syntax', async () => {
const tune = `// "Awesome song"`;
expect(getMetadata(tune)).toStrictEqual({
title: 'Awesome song',
});
});
it('loads a title tag with quotes syntax among other tags', async () => {
const tune = `// "Awesome song" made @by Sam`;
expect(getMetadata(tune)).toStrictEqual({
title: 'Awesome song',
by: ['Sam'],
});
});
it('loads a title tag with quotes syntax from block comment', async () => {
const tune = `/* "Awesome song"
@by Sam */`;
expect(getMetadata(tune)).toStrictEqual({
title: 'Awesome song',
by: ['Sam'],
});
});
it('does not load a title tag with quotes syntax after a prefix', async () => {
const tune = `// I don't care about those "metadata".`;
expect(getMetadata(tune)).toStrictEqual({});
});
it('does not load a title tag with quotes syntax after an other comment', async () => {
const tune = `// I don't care about those
// "metadata"`;
expect(getMetadata(tune)).toStrictEqual({});
});
it('does not load a title tag with quotes syntax after other tags', async () => {
const tune = `/*
@by Sam aka "Lady Strudel"
"Sandyyy"
*/`;
expect(getMetadata(tune)).toStrictEqual({
by: ['Sam aka "Lady Strudel"', '"Sandyyy"'],
});
});
it('loads a tag list with comma-separated values syntax', async () => { it('loads a tag list with comma-separated values syntax', async () => {
const tune = `// @by Sam, Sandy`; const tune = `// @by Sam, Sandy`;
expect(getMetadata(tune)).toStrictEqual({ expect(getMetadata(tune)).toStrictEqual({
@ -159,15 +204,6 @@ describe.concurrent('Metadata parser', () => {
}); });
}); });
it('loads empty tags from block comment', async () => {
const tune = `/* @title
@by */`;
expect(getMetadata(tune)).toStrictEqual({
title: '',
by: [],
});
});
it('loads tags with whitespaces from inline comments', async () => { it('loads tags with whitespaces from inline comments', async () => {
const tune = ` // @title Awesome song const tune = ` // @title Awesome song
// @by Sam Tagada `; // @by Sam Tagada `;
@ -186,6 +222,20 @@ describe.concurrent('Metadata parser', () => {
}); });
}); });
it('loads empty tags from block comment', async () => {
const tune = `/* @title
@by */`;
expect(getMetadata(tune)).toStrictEqual({
title: '',
by: [],
});
});
it('does not load tags if there is not', async () => {
const tune = `note("a3 c#4 e4 a4")`;
expect(getMetadata(tune)).toStrictEqual({});
});
it('does not load code that looks like a metadata tag', async () => { it('does not load code that looks like a metadata tag', async () => {
const tune = `const str1 = '@title Awesome song'`; const tune = `const str1 = '@title Awesome song'`;
// need a lexer to avoid this one, but it's a pretty rare use case: // need a lexer to avoid this one, but it's a pretty rare use case:

View File

@ -67,7 +67,7 @@ It is a handy way to quickly turn code on and off.
Try uncommenting this line by deleting `//` and refreshing the pattern. Try uncommenting this line by deleting `//` and refreshing the pattern.
You can also use the keyboard shortcut `cmd-/` to toggle comments on and off. You can also use the keyboard shortcut `cmd-/` to toggle comments on and off.
You might noticed that some comments in the REPL samples include some words starting with a "@", like `@title` or `@license`. You might noticed that some comments in the REPL samples include some words starting with a "@", like `@by` or `@license`.
Those are just a convention to define some information about the music. We will talk about it in the [Music metadata](/learn/metadata) section. Those are just a convention to define some information about the music. We will talk about it in the [Music metadata](/learn/metadata) section.
# Strings # Strings

View File

@ -38,6 +38,12 @@ Or define multiple tags in one line:
// @title Hey Hoo @by Sam Tagada @license CC BY-NC-SA // @title Hey Hoo @by Sam Tagada @license CC BY-NC-SA
``` ```
The `title` tag has an alternative syntax using quotes (must be defined at the very begining):
```js
// "Hey Hoo" @by Sam Tagada
```
## Tags list ## Tags list
Available tags are: Available tags are:

View File

@ -2,10 +2,16 @@ const ALLOW_MANY = ['by', 'url', 'genre', 'license'];
export function getMetadata(raw_code) { export function getMetadata(raw_code) {
const comment_regexp = /\/\*([\s\S]*?)\*\/|\/\/(.*)$/gm; const comment_regexp = /\/\*([\s\S]*?)\*\/|\/\/(.*)$/gm;
const comments = [...raw_code.matchAll(comment_regexp)].map((c) => (c[1] || c[2] || '').trim());
const tags = {}; const tags = {};
for (const match of raw_code.matchAll(comment_regexp)) { const [prefix, title] = (comments[0] || '').split('"');
const tag_matches = (match[1] || match[2] || '').trim().split('@').slice(1); if (prefix.trim() === '' && title !== undefined) {
tags['title'] = title;
}
for (const comment of comments) {
const tag_matches = comment.split('@').slice(1);
for (const tag_match of tag_matches) { for (const tag_match of tag_matches) {
let [tag, tag_value] = tag_match.split(/ (.*)/s); let [tag, tag_value] = tag_match.split(/ (.*)/s);
tag = tag.trim(); tag = tag.trim();

View File

@ -121,7 +121,7 @@ stack(
.room(1) .room(1)
//.pianoroll({fold:1})`; //.pianoroll({fold:1})`;
export const caverave = `// @title Caverave export const caverave = `// "Caverave"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -186,7 +186,7 @@ export const barryHarris = `// adapted from a Barry Harris excercise
.color('#00B8D4') .color('#00B8D4')
`; `;
export const blippyRhodes = `// @title Blippy Rhodes export const blippyRhodes = `// "Blippy Rhodes"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -230,7 +230,7 @@ stack(
).fast(3/2) ).fast(3/2)
//.pianoroll({fold:1})`; //.pianoroll({fold:1})`;
export const wavyKalimba = `// @title Wavy kalimba export const wavyKalimba = `// "Wavy kalimba"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -262,7 +262,7 @@ stack(
.delay(.2) .delay(.2)
`; `;
export const festivalOfFingers = `// @title Festival of fingers export const festivalOfFingers = `// "Festival of fingers"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -279,7 +279,7 @@ stack(
.note().piano()`; .note().piano()`;
// iter, echo, echoWith // iter, echo, echoWith
export const undergroundPlumber = `// @title Underground plumber export const undergroundPlumber = `// "Underground plumber"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
// @details inspired by Friendship - Let's not talk about it (1979) :) // @details inspired by Friendship - Let's not talk about it (1979) :)
@ -307,7 +307,7 @@ stack(
.fast(2/3) .fast(2/3)
.pianoroll({})`; .pianoroll({})`;
export const bridgeIsOver = `// @title Bridge is over export const bridgeIsOver = `// "Bridge is over"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos, bassline by BDP - The Bridge Is Over // @by Felix Roos, bassline by BDP - The Bridge Is Over
@ -330,7 +330,7 @@ stack(
.pianoroll() .pianoroll()
`; `;
export const goodTimes = `// @title Good times export const goodTimes = `// "Good times"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -375,7 +375,7 @@ stack(
.pianoroll({maxMidi:100,minMidi:20})`; .pianoroll({maxMidi:100,minMidi:20})`;
*/ */
export const echoPiano = `// @title Echo piano export const echoPiano = `// "Echo piano"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -424,7 +424,7 @@ stack(
.legato(.5) .legato(.5)
).fast(2).note()`; ).fast(2).note()`;
export const randomBells = `// @title Random bells export const randomBells = `// "Random bells"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -449,7 +449,7 @@ stack(
.pianoroll({minMidi:20,maxMidi:120,background:'transparent'}) .pianoroll({minMidi:20,maxMidi:120,background:'transparent'})
`; `;
export const waa2 = `// @title Waa2 export const waa2 = `// "Waa2"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -467,7 +467,7 @@ n(
.room(.5) .room(.5)
`; `;
export const hyperpop = `// @title Hyperpop export const hyperpop = `// "Hyperpop"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -520,7 +520,7 @@ stack(
).slow(2) ).slow(2)
// strudel disable-highlighting`; // strudel disable-highlighting`;
export const festivalOfFingers3 = `// @title Festival of fingers 3 export const festivalOfFingers3 = `// "Festival of fingers 3"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -540,7 +540,7 @@ export const festivalOfFingers3 = `// @title Festival of fingers 3
.note().piano() .note().piano()
//.pianoroll({maxMidi:160})`; //.pianoroll({maxMidi:160})`;
export const meltingsubmarine = `// @title Melting submarine export const meltingsubmarine = `// "Melting submarine"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -580,7 +580,7 @@ stack(
) )
.slow(3/2)`; .slow(3/2)`;
export const outroMusic = `// @title Outro music export const outroMusic = `// "Outro music"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -611,7 +611,7 @@ samples({
//.pianoroll({autorange:1,vertical:1,fold:0}) //.pianoroll({autorange:1,vertical:1,fold:0})
`; `;
export const bassFuge = `// @title Bass fuge export const bassFuge = `// "Bass fuge"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -639,7 +639,7 @@ x=>x.add(7).color('steelblue')
.stack(s("bd:1*2,~ sd:0,[~ hh:0]*2")) .stack(s("bd:1*2,~ sd:0,[~ hh:0]*2"))
.pianoroll({vertical:1})`; .pianoroll({vertical:1})`;
export const chop = `// @title Chop export const chop = `// "Chop"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -654,7 +654,7 @@ s("p")
.sustain(.6) .sustain(.6)
`; `;
export const delay = `// @title Delay export const delay = `// "Delay"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -665,7 +665,7 @@ stack(
.delayfeedback(".6 | .8") .delayfeedback(".6 | .8")
).sometimes(x=>x.speed("-1"))`; ).sometimes(x=>x.speed("-1"))`;
export const orbit = `// @title Orbit export const orbit = `// "Orbit"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -681,7 +681,7 @@ stack(
.orbit(2) .orbit(2)
).sometimes(x=>x.speed("-1"))`; ).sometimes(x=>x.speed("-1"))`;
export const belldub = `// @title Belldub export const belldub = `// "Belldub"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -716,7 +716,7 @@ stack(
.mask("<1 0>/8") .mask("<1 0>/8")
).slow(5)`; ).slow(5)`;
export const dinofunk = `// @title Dinofunk export const dinofunk = `// "Dinofunk"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -739,7 +739,7 @@ note("Abm7".voicings('lefthand').struct("x(3,8,1)".slow(2))),
note("<b4 eb4>").s('dino').delay(.8).slow(8).room(.5) note("<b4 eb4>").s('dino').delay(.8).slow(8).room(.5)
)`; )`;
export const sampleDemo = `// @title Sample demo export const sampleDemo = `// "Sample demo"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -757,7 +757,7 @@ stack(
.release(.1).room(.5) .release(.1).room(.5)
)`; )`;
export const holyflute = `// @title Holy flute export const holyflute = `// "Holy flute"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -772,7 +772,7 @@ export const holyflute = `// @title Holy flute
.pianoroll({fold:0,autorange:0,vertical:0,cycles:12,smear:0,minMidi:40}) .pianoroll({fold:0,autorange:0,vertical:0,cycles:12,smear:0,minMidi:40})
`; `;
export const flatrave = `// @title Flatrave export const flatrave = `// "Flatrave"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -797,7 +797,7 @@ stack(
.decay(.05).sustain(0).delay(.2).degradeBy(.5).mask("<0 1>/16") .decay(.05).sustain(0).delay(.2).degradeBy(.5).mask("<0 1>/16")
)`; )`;
export const amensister = `// @title Amensister export const amensister = `// "Amensister"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -833,7 +833,7 @@ stack(
n("0 1").s("east").delay(.5).degradeBy(.8).speed(rand.range(.5,1.5)) n("0 1").s("east").delay(.5).degradeBy(.8).speed(rand.range(.5,1.5))
).reset("<x@7 x(5,8,-1)>")`; ).reset("<x@7 x(5,8,-1)>")`;
export const juxUndTollerei = `// @title Jux und tollerei export const juxUndTollerei = `// "Jux und tollerei"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -848,7 +848,7 @@ note("c3 eb3 g3 bb3").palindrome()
.delay(.5).delaytime(.1).delayfeedback(.4) .delay(.5).delaytime(.1).delayfeedback(.4)
.pianoroll()`; .pianoroll()`;
export const csoundDemo = `// @title CSound demo export const csoundDemo = `// "CSound demo"
// @license with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
@ -884,7 +884,7 @@ endin\`
//.pianoroll() //.pianoroll()
.csound('CoolSynth')`; .csound('CoolSynth')`;
export const loungeSponge = `// @title Lounge sponge export const loungeSponge = `// "Lounge sponge"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos, livecode.orc by Steven Yi // @by Felix Roos, livecode.orc by Steven Yi
@ -904,7 +904,7 @@ stack(
s("bd*2,[~ hh]*2,~ cp").bank('RolandTR909') s("bd*2,[~ hh]*2,~ cp").bank('RolandTR909')
)`; )`;
export const arpoon = `// @title Arpoon export const arpoon = `// "Arpoon"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos