Socket
Socket
Sign inDemoInstall

music-library-index

Package Overview
Dependencies
1
Maintainers
2
Versions
15
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.4.0 to 2.0.0

432

index.js

@@ -18,4 +18,2 @@ var removeDiacritics = require('diacritics').remove;

];
MusicLibraryIndex.parseQuery = parseQuery;
MusicLibraryIndex.tokenizeQuery = tokenizeQuery;

@@ -32,3 +30,5 @@ function MusicLibraryIndex(options) {

this.trackComparator = this.trackComparator.bind(this);
this.clear();
this.labelComparator = this.labelComparator.bind(this);
this.clearTracks();
this.clearLabels();
}

@@ -95,2 +95,6 @@

MusicLibraryIndex.prototype.labelComparator = function(a, b) {
return this.titleCompare(a.name, b.name);
}
MusicLibraryIndex.prototype.getAlbumKey = function(track) {

@@ -106,3 +110,3 @@ var artistName = track.albumArtistName ||

MusicLibraryIndex.prototype.clear = function() {
MusicLibraryIndex.prototype.clearTracks = function() {
this.trackTable = {};

@@ -113,9 +117,12 @@ this.artistTable = {};

this.albumList = [];
this.dirty = false;
this.dirtyAlbumTable = false;
this.dirtyTracks = false;
};
MusicLibraryIndex.prototype.clearLabels = function() {
this.labelTable = {};
this.labelList = [];
this.dirtyLabels = false;
};
MusicLibraryIndex.prototype.rebuildAlbumTable = function() {
if (!this.dirtyAlbumTable) return;
// builds everything from trackTable

@@ -153,4 +160,2 @@ this.artistTable = {};

this.dirtyAlbumTable = false;
function createAlbum() {

@@ -168,4 +173,4 @@ var album = {

MusicLibraryIndex.prototype.rebuild = function() {
if (!this.dirty) return;
MusicLibraryIndex.prototype.rebuildTracks = function() {
if (!this.dirtyTracks) return;
this.rebuildAlbumTable();

@@ -233,3 +238,3 @@ this.albumList.sort(this.albumComparator);

this.dirty = false;
this.dirtyTracks = false;

@@ -245,14 +250,22 @@ function createArtist() {

MusicLibraryIndex.prototype.rebuildLabels = function() {
if (!this.dirtyLabels) return;
this.labelList = [];
for (var id in this.labelTable) {
var label = this.labelTable[id];
this.labelList.push(label);
}
this.labelList.sort(this.labelComparator);
this.labelList.forEach(function(label, index) {
label.index = index;
});
this.dirtyLabels = false;
}
MusicLibraryIndex.prototype.addTrack = function(track) {
var oldTrack = this.trackTable[track.key];
this.dirty = this.dirty ||
oldTrack == null ||
oldTrack.artistName !== track.artistName ||
oldTrack.albumArtistName !== track.albumArtistName ||
oldTrack.albumName !== track.albumName ||
oldTrack.track !== track.track ||
oldTrack.disc !== track.disc ||
oldTrack.year !== track.year;
this.dirtyAlbumTable = this.dirty;
this.trackTable[track.key] = track;
this.dirtyTracks = true;
}

@@ -262,6 +275,15 @@

delete this.trackTable[key];
this.dirty = true;
this.dirtyAlbumTable = true;
this.dirtyTracks = true;
}
MusicLibraryIndex.prototype.addLabel = function(label) {
this.labelTable[label.id] = label;
this.dirtyLabels = true;
}
MusicLibraryIndex.prototype.removeLabel = function(id) {
delete this.labelTable[id];
this.dirtyLabels = true;
}
MusicLibraryIndex.prototype.search = function(query) {

@@ -275,3 +297,3 @@ var searchResults = new MusicLibraryIndex({

var matcher = parseQuery(query);
var matcher = this.parseQuery(query);

@@ -285,5 +307,4 @@ var track;

}
searchResults.dirty = true;
searchResults.dirtyAlbumTable = true;
searchResults.rebuild();
searchResults.dirtyTracks = true;
searchResults.rebuildTracks();

@@ -294,45 +315,2 @@ return searchResults;

function makeFuzzyTextMatcher(term) {
// make this publicly modifiable
fuzzyTextMatcher.fuzzyTerm = formatSearchable(term);;
fuzzyTextMatcher.toString = function() {
return "(fuzzy " + JSON.stringify(fuzzyTextMatcher.fuzzyTerm) + ")"
};
return fuzzyTextMatcher;
function fuzzyTextMatcher(track) {
return track.fuzzySearchTags.indexOf(fuzzyTextMatcher.fuzzyTerm) !== -1;
}
}
function makeExactTextMatcher(term) {
exactTextMatcher.toString = function() {
return "(exact " + JSON.stringify(term) + ")"
};
return exactTextMatcher;
function exactTextMatcher(track) {
return track.exactSearchTags.indexOf(term) !== -1;
}
}
function makeAndMatcher(children) {
if (children.length === 1) return children[0];
andMatcher.toString = function() {
return "(" + children.join(" AND ") + ")";
};
return andMatcher;
function andMatcher(track) {
for (var i = 0; i < children.length; i++) {
if (!children[i](track)) return false;
}
return true;
}
}
function makeNotMatcher(subMatcher) {
notMatcher.toString = function() {
return "(not " + subMatcher.toString() + ")";
};
return notMatcher;
function notMatcher(track) {
return !subMatcher(track);
}
}
var tokenizerRegex = new RegExp(

@@ -343,4 +321,5 @@ '( +)' +'|'+ // 1: whitespace between terms (not in quotes)

'(not:)' +'|'+ // 4: not: prefix
'("(?:[^"\\\\]|\\\\.)*"\\)*)' +'|'+ // 5: quoted thing. can end with parentheses
'([^ ]+)', // 6: normal word. can end with parentheses
'(label:)' +'|'+ // 5: label: prefix
'("(?:[^"\\\\]|\\\\.)*"\\)*)' +'|'+ // 6: quoted thing. can end with parentheses
'([^ ]+)', // 7: normal word. can end with parentheses
"g");

@@ -351,119 +330,228 @@ var WHITESPACE = 1;

var NOT = 4;
var QUOTED_THING = 5;
var NORMAL_WORD = 6;
function tokenizeQuery(query) {
tokenizerRegex.lastIndex = 0;
var tokens = [];
while (true) {
var match = tokenizerRegex.exec(query);
if (match == null) break;
var term = match[0];
var type;
for (var i = 1; i < match.length; i++) {
if (match[i] != null) {
type = i;
break;
var LABEL = 5;
var QUOTED_THING = 6;
var NORMAL_WORD = 7;
MusicLibraryIndex.prototype.parseQuery = function(query) {
var self = this;
return parse(query);
function parse(query) {
var tokens = tokenizeQuery(query);
var tokenIndex = 0;
return parseAnd(null);
function parseAnd(waitForTokenType) {
var matchers = [];
var justSawWhitespace = true;
while (tokenIndex < tokens.length) {
var token = tokens[tokenIndex++];
switch (token.type) {
case OPEN_PARENTHESIS:
var subMatcher = parseAnd(CLOSE_PARENTHESIS);
matchers.push(subMatcher);
break;
case CLOSE_PARENTHESIS:
if (waitForTokenType === CLOSE_PARENTHESIS) return makeAndMatcher(matchers);
// misplaced )
var previousMatcher = matchers[matchers.length - 1];
if (!justSawWhitespace && previousMatcher != null && previousMatcher.fuzzyTerm != null) {
// slap it on the back of the last guy
previousMatcher.fuzzyTerm += token.text;
} else {
// it's its own term
matchers.push(makeFuzzyTextMatcher(token.text));
}
break;
case NOT:
matchers.push(parseNot());
break;
case LABEL:
matchers.push(parseLabel());
break;
case QUOTED_THING:
if (token.text.length !== 0) {
matchers.push(makeExactTextMatcher(token.text));
}
break;
case NORMAL_WORD:
matchers.push(makeFuzzyTextMatcher(token.text));
break;
}
var justSawWhitespace = token.type === WHITESPACE;
}
return makeAndMatcher(matchers);
}
switch (type) {
case WHITESPACE:
case OPEN_PARENTHESIS:
case CLOSE_PARENTHESIS:
case NOT:
tokens.push({type: type, text: term});
break;
case QUOTED_THING:
case NORMAL_WORD:
var endParensCount = /\)*$/.exec(term)[0].length;
term = term.substr(0, term.length - endParensCount);
if (type === QUOTED_THING) {
// strip quotes
term = /^"(.*)"$/.exec(term)[1];
// handle escapes
term = term.replace(/\\(.)/g, "$1");
}
tokens.push({type: type, text: term});
for (var i = 0; i < endParensCount; i++) {
tokens.push({type: CLOSE_PARENTHESIS, text: ")"});
}
break;
function parseNot() {
if (tokenIndex >= tokens.length) {
// "not:" then EOF. treat it as a fuzzy matcher for "not:"
return makeFuzzyTextMatcher(tokens[tokenIndex - 1].text);
}
var token = tokens[tokenIndex++];
switch (token.type) {
case WHITESPACE:
case CLOSE_PARENTHESIS:
// "not: " or "not:)"
// Treat the "not:" as a fuzzy matcher,
// and let the parent deal with this token
tokenIndex--;
return makeFuzzyTextMatcher(tokens[tokenIndex - 1].text);
case OPEN_PARENTHESIS:
// "not:("
return makeNotMatcher(parseAnd(CLOSE_PARENTHESIS));
case NOT:
// double negative all the way.
return makeNotMatcher(parseNot());
case LABEL:
return makeNotMatcher(parseLabel());
case QUOTED_THING:
return makeNotMatcher(makeExactTextMatcher(token.text));
case NORMAL_WORD:
return makeNotMatcher(makeFuzzyTextMatcher(token.text));
}
throw new Error("unreachable");
}
}
return tokens;
}
function parseQuery(query) {
var tokens = tokenizeQuery(query);
var tokenIndex = 0;
return parseAnd(null);
function parseAnd(waitForTokenType) {
var matchers = [];
var justSawWhitespace = true;
while (tokenIndex < tokens.length) {
function parseLabel() {
if (tokenIndex >= tokens.length) {
// "label:" then EOF. treat it as a fuzzy matcher for "label:"
return makeFuzzyTextMatcher(tokens[tokenIndex - 1].text);
}
var token = tokens[tokenIndex++];
switch (token.type) {
case WHITESPACE:
case CLOSE_PARENTHESIS:
// "label: " or "label:)"
// Treat the "label:" as a fuzzy matcher,
// and let the parent deal with this token
tokenIndex--;
return makeFuzzyTextMatcher(tokens[tokenIndex - 1].text);
case OPEN_PARENTHESIS:
var subMatcher = parseAnd(CLOSE_PARENTHESIS);
matchers.push(subMatcher);
case NOT:
case LABEL:
case QUOTED_THING:
case NORMAL_WORD:
// "label:(" or "label:not:" or "label:label:" or 'label:"Asdf"' or "label:Asdf"
return makeLabelMatcher(token.text);
}
throw new Error("unreachable");
}
}
function makeFuzzyTextMatcher(term) {
// make this publicly modifiable
fuzzyTextMatcher.fuzzyTerm = formatSearchable(term);;
fuzzyTextMatcher.toString = function() {
return "(fuzzy " + JSON.stringify(fuzzyTextMatcher.fuzzyTerm) + ")"
};
return fuzzyTextMatcher;
function fuzzyTextMatcher(track) {
return track.fuzzySearchTags.indexOf(fuzzyTextMatcher.fuzzyTerm) !== -1;
}
}
function makeExactTextMatcher(term) {
exactTextMatcher.toString = function() {
return "(exact " + JSON.stringify(term) + ")"
};
return exactTextMatcher;
function exactTextMatcher(track) {
return track.exactSearchTags.indexOf(term) !== -1;
}
}
function makeAndMatcher(children) {
if (children.length === 1) return children[0];
andMatcher.toString = function() {
return "(" + children.join(" AND ") + ")";
};
return andMatcher;
function andMatcher(track) {
for (var i = 0; i < children.length; i++) {
if (!children[i](track)) return false;
}
return true;
}
}
function makeNotMatcher(subMatcher) {
notMatcher.toString = function() {
return "(not " + subMatcher.toString() + ")";
};
return notMatcher;
function notMatcher(track) {
return !subMatcher(track);
}
}
function makeLabelMatcher(text) {
var id = (function() {
for (var id in self.labelTable) {
if (self.labelTable[id].name === text) {
return id;
}
}
return null;
})();
if (id != null) {
labelMatcher.toString = function() {
return "(label " + JSON.stringify(id) + ")";
};
return labelMatcher;
} else {
// not even a real label
alwaysFail.toString = function() {
return "(label <none>)";
};
return alwaysFail;
}
function labelMatcher(track) {
return track.labels != null && track.labels[id];
}
function alwaysFail() {
return false;
}
}
function tokenizeQuery(query) {
tokenizerRegex.lastIndex = 0;
var tokens = [];
while (true) {
var match = tokenizerRegex.exec(query);
if (match == null) break;
var term = match[0];
var type;
for (var i = 1; i < match.length; i++) {
if (match[i] != null) {
type = i;
break;
}
}
switch (type) {
case WHITESPACE:
case OPEN_PARENTHESIS:
case CLOSE_PARENTHESIS:
if (waitForTokenType === CLOSE_PARENTHESIS) return makeAndMatcher(matchers);
// misplaced )
var previousMatcher = matchers[matchers.length - 1];
if (!justSawWhitespace && previousMatcher != null && previousMatcher.fuzzyTerm != null) {
// slap it on the back of the last guy
previousMatcher.fuzzyTerm += token.text;
} else {
// it's its own term
matchers.push(makeFuzzyTextMatcher(token.text));
}
break;
case NOT:
matchers.push(parseNot());
case LABEL:
tokens.push({type: type, text: term});
break;
case QUOTED_THING:
if (token.text.length !== 0) {
matchers.push(makeExactTextMatcher(token.text));
case NORMAL_WORD:
var endParensCount = /\)*$/.exec(term)[0].length;
term = term.substr(0, term.length - endParensCount);
if (type === QUOTED_THING) {
// strip quotes
term = /^"(.*)"$/.exec(term)[1];
// handle escapes
term = term.replace(/\\(.)/g, "$1");
}
tokens.push({type: type, text: term});
for (var i = 0; i < endParensCount; i++) {
tokens.push({type: CLOSE_PARENTHESIS, text: ")"});
}
break;
case NORMAL_WORD:
matchers.push(makeFuzzyTextMatcher(token.text));
break;
}
var justSawWhitespace = token.type === WHITESPACE;
}
return makeAndMatcher(matchers);
return tokens;
}
function parseNot() {
if (tokenIndex >= tokens.length) {
// "not:" then EOF. treat it as a fuzzy matcher for "not:"
return makeFuzzyTextMatcher(tokens[tokenIndex - 1].text);
}
var token = tokens[tokenIndex++];
switch (token.type) {
case WHITESPACE:
case CLOSE_PARENTHESIS:
// "not: " or "not:)"
// Treat the "not:" as a fuzzy matcher,
// and let the parent deal with this token
tokenIndex--;
return makeFuzzyTextMatcher(tokens[tokenIndex - 1].text);
case OPEN_PARENTHESIS:
// "not:("
return makeNotMatcher(parseAnd(CLOSE_PARENTHESIS));
case NOT:
// double negative all the way.
return makeNotMatcher(parseNot());
case QUOTED_THING:
return makeNotMatcher(makeExactTextMatcher(token.text));
case NORMAL_WORD:
return makeNotMatcher(makeFuzzyTextMatcher(token.text));
}
throw new Error("unreachable");
}
};
}
function getOrCreate(key, table, initObjFunc) {

@@ -470,0 +558,0 @@ var result = table[key];

{
"name": "music-library-index",
"version": "1.4.0",
"version": "2.0.0",
"description": "build a searchable javascript object model given track metadata objects",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -58,6 +58,14 @@ # Music Library Index

albumArtistName: "Anberlin",
label: {"favorites_id": 1},
});
library.rebuild();
library.rebuildTracks();
library.addLabel({
id: "favorites_id",
name: "favorites",
});
library.rebuildLabels();
console.log(library.artistList[0]);

@@ -64,0 +72,0 @@ console.log(library.trackTable);

@@ -15,4 +15,4 @@ // usage: node benchmark.js path/to/index.json ["search query" ...]

}
timed("rebuild()", function() {
library.rebuild();
timed("rebuildTracks()", function() {
library.rebuildTracks();
});

@@ -19,0 +19,0 @@ for (var i = 3; i < process.argv.length; i++) {

@@ -29,3 +29,3 @@ var assert = require('assert');

library.rebuild();
library.rebuildTracks();

@@ -132,3 +132,3 @@ it("trackTable", function() {

library.rebuild();
library.rebuildTracks();

@@ -182,3 +182,3 @@ it("filed in various artists", function() {

library.rebuild();
library.rebuildTracks();

@@ -215,3 +215,3 @@ it("still knows they're in the same album", function() {

library.rebuild();
library.rebuildTracks();

@@ -249,3 +249,3 @@ it("detects that they are different", function() {

library.rebuild();
library.rebuildTracks();

@@ -279,3 +279,3 @@ it("only creates one album", function() {

library.rebuild();
library.rebuildTracks();

@@ -342,3 +342,3 @@ it("should be filed under the artist", function() {

library.rebuild();
library.rebuildTracks();

@@ -372,3 +372,3 @@ it("sorts by disc before track", function() {

library.rebuild();
library.rebuildTracks();

@@ -399,3 +399,3 @@ it("shouldn't be various artists", function() {

library.rebuild();
library.rebuildTracks();
var results = library;

@@ -450,3 +450,3 @@

});
library.rebuild();
library.rebuildTracks();

@@ -460,26 +460,86 @@ it("shouldn't be various artists", function() {

describe("label management", function() {
var library = new MusicLibraryIndex();
library.addLabel({
id: "wrong_id",
name: "wrong",
});
library.rebuildLabels();
library.clearLabels();
library.addLabel({
id: "techno_id",
name: "techno",
});
library.addLabel({
id: "jazz_id",
name: "jazz",
});
library.rebuildLabels();
it("clearLabels, addLabel", function() {
assert.strictEqual(library.labelList[0].name, "jazz");
assert.strictEqual(library.labelList[1].name, "techno");
});
});
describe("parseQuery", function() {
var library = new MusicLibraryIndex();
it("works", function() {
assert.strictEqual(MusicLibraryIndex.parseQuery('').toString(), '()');
assert.strictEqual(MusicLibraryIndex.parseQuery('a').toString(), '(fuzzy "a")');
assert.strictEqual(MusicLibraryIndex.parseQuery(' ab cd ').toString(), '((fuzzy "ab") AND (fuzzy "cd"))');
assert.strictEqual(MusicLibraryIndex.parseQuery('"a b"').toString(), '(exact "a b")');
assert.strictEqual(MusicLibraryIndex.parseQuery('"a b\\" c"').toString(), '(exact "a b\\\" c")');
assert.strictEqual(MusicLibraryIndex.parseQuery('\\"a b"').toString(), '((fuzzy "\\\\\\"a") AND (fuzzy "b\\""))');
assert.strictEqual(MusicLibraryIndex.parseQuery('"').toString(), '(fuzzy "\\\"")');
assert.strictEqual(MusicLibraryIndex.parseQuery('\\').toString(), '(fuzzy "\\\\")');
assert.strictEqual(MusicLibraryIndex.parseQuery('""').toString(), '()');
assert.strictEqual(MusicLibraryIndex.parseQuery('a" b"c').toString(), '((fuzzy "a\\\"") AND (fuzzy "b\\\"c"))');
assert.strictEqual(library.parseQuery('').toString(), '()');
assert.strictEqual(library.parseQuery('a').toString(), '(fuzzy "a")');
assert.strictEqual(library.parseQuery(' ab cd ').toString(), '((fuzzy "ab") AND (fuzzy "cd"))');
assert.strictEqual(library.parseQuery('"a b"').toString(), '(exact "a b")');
assert.strictEqual(library.parseQuery('"a b\\" c"').toString(), '(exact "a b\\\" c")');
assert.strictEqual(library.parseQuery('\\"a b"').toString(), '((fuzzy "\\\\\\"a") AND (fuzzy "b\\""))');
assert.strictEqual(library.parseQuery('"').toString(), '(fuzzy "\\\"")');
assert.strictEqual(library.parseQuery('\\').toString(), '(fuzzy "\\\\")');
assert.strictEqual(library.parseQuery('""').toString(), '()');
assert.strictEqual(library.parseQuery('a" b"c').toString(), '((fuzzy "a\\\"") AND (fuzzy "b\\\"c"))');
assert.strictEqual(MusicLibraryIndex.parseQuery('not:A').toString(), '(not (fuzzy "a"))');
assert.strictEqual(MusicLibraryIndex.parseQuery('not:"A"').toString(), '(not (exact "A"))');
assert.strictEqual(MusicLibraryIndex.parseQuery('not:(a b)').toString(), '(not ((fuzzy "a") AND (fuzzy "b")))');
assert.strictEqual(MusicLibraryIndex.parseQuery('not:(a)').toString(), '(not (fuzzy "a"))');
assert.strictEqual(MusicLibraryIndex.parseQuery('not:not:a').toString(), '(not (not (fuzzy "a")))');
assert.strictEqual(MusicLibraryIndex.parseQuery('not:').toString(), '(fuzzy "not:")');
assert.strictEqual(MusicLibraryIndex.parseQuery('not: a').toString(), '((fuzzy "not:") AND (fuzzy "a"))');
assert.strictEqual(MusicLibraryIndex.parseQuery('not:)a').toString(), '((fuzzy "not:)") AND (fuzzy "a"))');
assert.strictEqual(library.parseQuery('not:A').toString(), '(not (fuzzy "a"))');
assert.strictEqual(library.parseQuery('not:"A"').toString(), '(not (exact "A"))');
assert.strictEqual(library.parseQuery('not:(a b)').toString(), '(not ((fuzzy "a") AND (fuzzy "b")))');
assert.strictEqual(library.parseQuery('not:(a)').toString(), '(not (fuzzy "a"))');
assert.strictEqual(library.parseQuery('not:not:a').toString(), '(not (not (fuzzy "a")))');
assert.strictEqual(library.parseQuery('not:').toString(), '(fuzzy "not:")');
assert.strictEqual(library.parseQuery('not: a').toString(), '((fuzzy "not:") AND (fuzzy "a"))');
assert.strictEqual(library.parseQuery('not:)a').toString(), '((fuzzy "not:)") AND (fuzzy "a"))');
});
});
describe("parseQuery with labels", function() {
var library = new MusicLibraryIndex();
library.addLabel({
id: "techno_id",
name: "techno",
});
library.addLabel({
id: "jazz_id",
name: "jazz music",
});
library.addLabel({
id: "not_id",
name: "not:",
});
library.rebuildLabels();
it("works", function() {
assert.strictEqual(library.parseQuery('label:techno').toString(), '(label "techno_id")');
assert.strictEqual(library.parseQuery('not:label:techno').toString(), '(not (label "techno_id"))');
assert.strictEqual(library.parseQuery('label:asdf').toString(), '(label <none>)');
assert.strictEqual(library.parseQuery('label:Techno').toString(), '(label <none>)');
assert.strictEqual(library.parseQuery('label:"jazz music"').toString(), '(label "jazz_id")');
assert.strictEqual(library.parseQuery('label:jazz music').toString(), '((label <none>) AND (fuzzy "music"))');
assert.strictEqual(library.parseQuery('label:""').toString(), '(label <none>)');
assert.strictEqual(library.parseQuery('label:').toString(), '(fuzzy "label:")');
assert.strictEqual(library.parseQuery('label: ').toString(), '(fuzzy "label:")');
assert.strictEqual(library.parseQuery('label:not:').toString(), '(label "not_id")');
assert.strictEqual(library.parseQuery('not:(this label:)').toString(), '(not ((fuzzy "this") AND (fuzzy "label:")))');
});
});
describe("searching with quoted seach terms", function() {

@@ -531,3 +591,3 @@ var library = new MusicLibraryIndex();

library.rebuild();
library.rebuildTracks();

@@ -572,2 +632,12 @@ it("single search term returns both", function() {

var library = new MusicLibraryIndex();
library.addLabel({
id: "techno_id",
name: "techno",
});
library.addLabel({
id: "jazz_id",
name: "jazz",
});
library.rebuildLabels();
library.addTrack({

@@ -578,2 +648,3 @@ key: "fUPmxjMc",

albumName: "Varieté",
labels: {"jazz_id": 1},
});

@@ -585,2 +656,3 @@ library.addTrack({

albumName: "Varieté",
labels: {"techno_id": 1, "jazz_id": 1},
});

@@ -593,3 +665,3 @@ library.addTrack({

});
library.rebuild();
library.rebuildTracks();

@@ -604,2 +676,14 @@ it("'not:'", function() {

});
it("'label:'", function () {
assert.strictEqual(library.search('label:techno').artistList.length, 1);
assert.strictEqual(library.search('label:jazz').artistList.length, 2);
assert.strictEqual(library.search('not:label:techno').artistList.length, 2);
assert.strictEqual(library.search('"label:techno"').artistList.length, 0);
assert.strictEqual(library.search('not:"label:techno"').artistList.length, 3);
assert.strictEqual(library.search('label:wrong').artistList.length, 0);
assert.strictEqual(library.search('not:label:wrong').artistList.length, 3);
assert.strictEqual(library.search('not:(label:jazz not:label:techno)').artistList.length, 2);
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc