m3u8parse
Version:
Structural parsing of Apple HTTP Live Streaming .m3u8 format
99 lines (98 loc) • 3.2 kB
JavaScript
import deserialize from './attr-deserialize.js';
import serialize from './attr-serialize.js';
import { Attr } from './attr-types.js';
export { Attr as AttrType };
const tokenify = function (attr) {
if (typeof attr !== 'string') {
throw new TypeError('Attributes must be a "string"');
}
return attr.toLowerCase();
};
// AttrList's are handled without any implicit knowledge of key/type mapping
// eslint-disable-next-line @typescript-eslint/ban-types
export class AttrList extends Map {
constructor(attrs) {
super();
const set = (key, value, format) => {
if (value !== null && value !== undefined) {
super.set(key, format ? format(value) : value);
}
};
if (attrs instanceof AttrList) {
for (const [key, value] of attrs) {
set(key, value);
}
}
else if (typeof attrs === 'string') {
// TODO: handle newline escapes in quoted-string's
const re = /(.+?)=((?:\".*?\")|.*?)(?:,|$)/g;
let match;
while ((match = re.exec(attrs)) !== null) {
const attr = tokenify(match[1]);
if (super.has(attr)) {
throw new Error('Duplicate attribute key: ' + attr);
}
set(tokenify(attr), match[2]);
}
}
else if (!(attrs instanceof Map) && !Array.isArray(attrs)) {
for (const attr in attrs) {
set(tokenify(attr), attrs[attr], (val) => `${val || ''}`);
}
}
else {
for (const [key, value] of attrs) {
set(tokenify(key), value, (val) => `${val}`);
}
}
}
get(attr, type = Attr.Enum) {
attr = tokenify(attr);
const stringValue = super.get(attr);
if (stringValue !== undefined) {
const formatter = deserialize[type];
if (!formatter) {
throw new TypeError('Invalid type: ' + type);
}
return formatter(stringValue);
}
return stringValue;
}
set(attr, value, type = Attr.Enum) {
attr = tokenify(attr);
if (value === undefined || value === null) {
super.delete(attr);
return this;
}
const formatter = serialize[type];
if (!formatter) {
throw new TypeError('Invalid type: ' + type);
}
const stringValue = formatter(value);
super.set(attr, stringValue);
return this;
}
has(attr) {
return super.has(tokenify(attr));
}
delete(attr) {
return super.delete(tokenify(attr));
}
toString() {
let res = '';
for (const [key, value] of this) {
const comma = (res.length !== 0) ? ',' : '';
res += `${comma}${key.toUpperCase()}=${value}`;
}
return res;
}
// eslint-disable-next-line @typescript-eslint/ban-types
toJSON() {
const obj = Object.create(null);
for (const [key, value] of this) {
obj[key] = value;
}
return obj;
}
}
AttrList.Types = Attr;