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 () => {
const tune = `// @by Sam, Sandy`;
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 () => {
const tune = ` // @title Awesome song
// @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 () => {
const tune = `const str1 = '@title Awesome song'`;
// 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.
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.
# 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
```
The `title` tag has an alternative syntax using quotes (must be defined at the very begining):
```js
// "Hey Hoo" @by Sam Tagada
```
## Tags list
Available tags are:

View File

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

View File

@ -121,7 +121,7 @@ stack(
.room(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/
// @by Felix Roos
@ -186,7 +186,7 @@ export const barryHarris = `// adapted from a Barry Harris excercise
.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/
// @by Felix Roos
@ -230,7 +230,7 @@ stack(
).fast(3/2)
//.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/
// @by Felix Roos
@ -262,7 +262,7 @@ stack(
.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/
// @by Felix Roos
@ -279,7 +279,7 @@ stack(
.note().piano()`;
// 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/
// @by Felix Roos
// @details inspired by Friendship - Let's not talk about it (1979) :)
@ -307,7 +307,7 @@ stack(
.fast(2/3)
.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/
// @by Felix Roos, bassline by BDP - The Bridge Is Over
@ -330,7 +330,7 @@ stack(
.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/
// @by Felix Roos
@ -375,7 +375,7 @@ stack(
.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/
// @by Felix Roos
@ -424,7 +424,7 @@ stack(
.legato(.5)
).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/
// @by Felix Roos
@ -449,7 +449,7 @@ stack(
.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/
// @by Felix Roos
@ -467,7 +467,7 @@ n(
.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/
// @by Felix Roos
@ -520,7 +520,7 @@ stack(
).slow(2)
// 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/
// @by Felix Roos
@ -540,7 +540,7 @@ export const festivalOfFingers3 = `// @title Festival of fingers 3
.note().piano()
//.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/
// @by Felix Roos
@ -580,7 +580,7 @@ stack(
)
.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/
// @by Felix Roos
@ -611,7 +611,7 @@ samples({
//.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/
// @by Felix Roos
@ -639,7 +639,7 @@ x=>x.add(7).color('steelblue')
.stack(s("bd:1*2,~ sd:0,[~ hh:0]*2"))
.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/
// @by Felix Roos
@ -654,7 +654,7 @@ s("p")
.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/
// @by Felix Roos
@ -665,7 +665,7 @@ stack(
.delayfeedback(".6 | .8")
).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/
// @by Felix Roos
@ -681,7 +681,7 @@ stack(
.orbit(2)
).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/
// @by Felix Roos
@ -716,7 +716,7 @@ stack(
.mask("<1 0>/8")
).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/
// @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)
)`;
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/
// @by Felix Roos
@ -757,7 +757,7 @@ stack(
.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/
// @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})
`;
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/
// @by Felix Roos
@ -797,7 +797,7 @@ stack(
.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/
// @by Felix Roos
@ -833,7 +833,7 @@ stack(
n("0 1").s("east").delay(.5).degradeBy(.8).speed(rand.range(.5,1.5))
).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/
// @by Felix Roos
@ -848,7 +848,7 @@ note("c3 eb3 g3 bb3").palindrome()
.delay(.5).delaytime(.1).delayfeedback(.4)
.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/
// @by Felix Roos
@ -884,7 +884,7 @@ endin\`
//.pianoroll()
.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/
// @by Felix Roos, livecode.orc by Steven Yi
@ -904,7 +904,7 @@ stack(
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/
// @by Felix Roos