@amazon/vinyl-hls-parser 1.2.0 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/hlsTestAssets/types/current/tsconfig.tsbuildinfo +1 -1
  2. package/dist/index.cjs +132 -57
  3. package/dist/index.cjs.map +4 -4
  4. package/dist/index.js +131 -56
  5. package/dist/index.js.map +4 -4
  6. package/dist/test/benchmark.es5.js +52 -36
  7. package/dist/test/benchmark.js +428 -260
  8. package/dist/test/benchmark.js.map +4 -4
  9. package/dist/types/current/index.d.ts +11 -10
  10. package/dist/types/current/index.d.ts.map +1 -1
  11. package/dist/types/current/index.js +11 -10
  12. package/dist/types/current/parse/parseMainPlaylist.d.ts +8 -3
  13. package/dist/types/current/parse/parseMainPlaylist.d.ts.map +1 -1
  14. package/dist/types/current/parse/parseMainPlaylist.js +27 -3
  15. package/dist/types/current/parse/parseMediaPlaylist.d.ts +11 -4
  16. package/dist/types/current/parse/parseMediaPlaylist.d.ts.map +1 -1
  17. package/dist/types/current/parse/parseMediaPlaylist.js +111 -7
  18. package/dist/types/current/tsconfig.tsbuildinfo +1 -1
  19. package/dist/types/current/types/AlternativeRendition.d.ts +13 -0
  20. package/dist/types/current/types/AlternativeRendition.d.ts.map +1 -1
  21. package/dist/types/current/types/HlsDateRange.d.ts +51 -0
  22. package/dist/types/current/types/HlsDateRange.d.ts.map +1 -0
  23. package/dist/types/current/types/HlsDateRange.js +11 -0
  24. package/dist/types/current/types/{MainPlaylist.d.ts → HlsMainPlaylist.d.ts} +4 -4
  25. package/dist/types/current/types/HlsMainPlaylist.d.ts.map +1 -0
  26. package/dist/types/{ts4.1/types/MediaPlaylist.d.ts → current/types/HlsMediaPlaylist.d.ts} +11 -4
  27. package/dist/types/current/types/HlsMediaPlaylist.d.ts.map +1 -0
  28. package/dist/types/ts3.7/index.d.ts +11 -10
  29. package/dist/types/ts3.7/parse/parseMainPlaylist.d.ts +8 -3
  30. package/dist/types/ts3.7/parse/parseMediaPlaylist.d.ts +11 -4
  31. package/dist/types/ts3.7/types/AlternativeRendition.d.ts +13 -0
  32. package/dist/types/ts3.7/types/HlsDateRange.d.ts +51 -0
  33. package/dist/types/ts3.7/types/{MainPlaylist.d.ts → HlsMainPlaylist.d.ts} +4 -4
  34. package/dist/types/ts3.7/types/{MediaPlaylist.d.ts → HlsMediaPlaylist.d.ts} +11 -4
  35. package/dist/types/ts4.1/index.d.ts +11 -10
  36. package/dist/types/ts4.1/parse/parseMainPlaylist.d.ts +8 -3
  37. package/dist/types/ts4.1/parse/parseMediaPlaylist.d.ts +11 -4
  38. package/dist/types/ts4.1/types/AlternativeRendition.d.ts +13 -0
  39. package/dist/types/ts4.1/types/HlsDateRange.d.ts +51 -0
  40. package/dist/types/{ts4.7/types/MainPlaylist.d.ts → ts4.1/types/HlsMainPlaylist.d.ts} +4 -4
  41. package/dist/types/{ts4.7/types/MediaPlaylist.d.ts → ts4.1/types/HlsMediaPlaylist.d.ts} +11 -4
  42. package/dist/types/ts4.7/index.d.ts +11 -10
  43. package/dist/types/ts4.7/parse/parseMainPlaylist.d.ts +8 -3
  44. package/dist/types/ts4.7/parse/parseMediaPlaylist.d.ts +11 -4
  45. package/dist/types/ts4.7/types/AlternativeRendition.d.ts +13 -0
  46. package/dist/types/ts4.7/types/HlsDateRange.d.ts +51 -0
  47. package/dist/types/{ts4.1/types/MainPlaylist.d.ts → ts4.7/types/HlsMainPlaylist.d.ts} +4 -4
  48. package/dist/types/{current/types/MediaPlaylist.d.ts → ts4.7/types/HlsMediaPlaylist.d.ts} +11 -4
  49. package/package.json +14 -14
  50. package/dist/types/current/types/MainPlaylist.d.ts.map +0 -1
  51. package/dist/types/current/types/MediaPlaylist.d.ts.map +0 -1
  52. /package/dist/types/current/types/{MainPlaylist.js → HlsMainPlaylist.js} +0 -0
  53. /package/dist/types/current/types/{MediaPlaylist.js → HlsMediaPlaylist.js} +0 -0
@@ -33,11 +33,6 @@
33
33
  };
34
34
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
35
35
 
36
- // ../vinyl-util/src/util/type.ts
37
- function invariant() {
38
- return void 0;
39
- }
40
-
41
36
  // ../vinyl-util/src/error/ErrorOrigin.ts
42
37
  var ErrorOrigin = {
43
38
  /**
@@ -133,6 +128,11 @@
133
128
  return result;
134
129
  }
135
130
 
131
+ // ../vinyl-util/src/util/type.ts
132
+ function invariant() {
133
+ return void 0;
134
+ }
135
+
136
136
  // ../vinyl-util/src/util/string/string.ts
137
137
  var locale = {
138
138
  variableNotDefined: "Variable '{name}' is not defined"
@@ -180,6 +180,96 @@
180
180
  return str;
181
181
  }
182
182
 
183
+ // ../vinyl-util/src/util/object/object.ts
184
+ function ownKeys(obj) {
185
+ if (!obj) return /* @__PURE__ */ new Set();
186
+ if (typeof Reflect !== "undefined")
187
+ return new Set(Reflect.ownKeys(obj));
188
+ const properties = /* @__PURE__ */ new Set();
189
+ Object.getOwnPropertyNames(obj).forEach((item) => properties.add(item));
190
+ Object.getOwnPropertySymbols(obj).forEach((item) => properties.add(item));
191
+ return properties;
192
+ }
193
+ function isPlainObject(value) {
194
+ if (!value || typeof value !== "object" || Array.isArray(value))
195
+ return false;
196
+ const proto = Object.getPrototypeOf(value);
197
+ return !proto || !Object.getPrototypeOf(proto);
198
+ }
199
+
200
+ // ../vinyl-util/src/util/serialization/json.ts
201
+ function toJson(value) {
202
+ return toJsonInternal(value, /* @__PURE__ */ new Set());
203
+ }
204
+ function toJsonInternal(value, visited) {
205
+ switch (typeof value) {
206
+ case "object":
207
+ return objectToJsonInternal(value, visited);
208
+ case "undefined":
209
+ case "boolean":
210
+ case "number":
211
+ case "string":
212
+ return value;
213
+ case "function":
214
+ return `[function ${value.name}]`;
215
+ case "symbol":
216
+ return `[symbol ${value.toString().slice(7, -1)}]`;
217
+ case "bigint":
218
+ return value.toString();
219
+ }
220
+ }
221
+ function objectToJsonInternal(value, visited) {
222
+ if (value == null) return value;
223
+ if (visited.has(value)) return `<circular reference: ${String(value)}>`;
224
+ visited.add(value);
225
+ if ("toJSON" in value && typeof value.toJSON === "function")
226
+ return value.toJSON();
227
+ if (value instanceof Set) {
228
+ return Array.from(value).map((e) => toJsonInternal(e, visited));
229
+ } else if (Array.isArray(value)) {
230
+ return value.map((e) => toJsonInternal(e, visited));
231
+ } else {
232
+ if (isPlainObject(value)) {
233
+ const o = {};
234
+ for (const key in value) {
235
+ o[key] = toJsonInternal(value[key], visited);
236
+ }
237
+ return o;
238
+ } else if (value instanceof Error) {
239
+ return {
240
+ name: value.name,
241
+ message: value.message,
242
+ stack: value.stack
243
+ };
244
+ } else {
245
+ return value.toString();
246
+ }
247
+ }
248
+ }
249
+
250
+ // ../vinyl-util/src/error/ValidationError.ts
251
+ var ValidationError = class _ValidationError extends ReportableError {
252
+ /**
253
+ * @param message The validation error message.
254
+ * @param origin The error origin, typically API (default) or SERVICE_EXTERNAL
255
+ * @param path The property path to the invalid field.
256
+ */
257
+ constructor(message, origin = ErrorOrigin.API, path = []) {
258
+ super(message, origin);
259
+ __publicField(this, "path", path);
260
+ Object.setPrototypeOf(this, _ValidationError.prototype);
261
+ }
262
+ get [Symbol.toStringTag]() {
263
+ return "ValidationError";
264
+ }
265
+ toJSON() {
266
+ return __spreadProps(__spreadValues({}, super.toJSON()), {
267
+ origin: this.origin,
268
+ path: this.path
269
+ });
270
+ }
271
+ };
272
+
183
273
  // ../vinyl-util/src/util/math/math.ts
184
274
  function clamp(value, min, max) {
185
275
  return Math.min(Math.max(value, min), max);
@@ -213,6 +303,30 @@
213
303
  return out;
214
304
  }
215
305
 
306
+ // ../vinyl-util/src/util/serialization/stringifyForPrint.ts
307
+ function stringifyForPrint(value, maxLength, indicator = "\u2026") {
308
+ let str = JSON.stringify(
309
+ toJson(value),
310
+ (_, value2) => {
311
+ const type = typeof value2;
312
+ if (["undefined"].includes(type)) {
313
+ return `{{${String(value2)}}}`;
314
+ }
315
+ if (type === "number") {
316
+ if (Number.isNaN(value2) || !Number.isFinite(value2))
317
+ return `{{${value2.toString()}}}`;
318
+ }
319
+ return value2;
320
+ },
321
+ " "
322
+ );
323
+ str = str.replace(/("\{\{.*}}")/g, (_, s) => {
324
+ return s.substring(3, s.length - 3);
325
+ });
326
+ if (maxLength) str = truncate(str, maxLength, indicator);
327
+ return str;
328
+ }
329
+
216
330
  // ../vinyl-util/src/util/string/StringReader.ts
217
331
  var StringReader = class {
218
332
  /**
@@ -445,111 +559,34 @@
445
559
  }
446
560
  };
447
561
 
448
- // ../vinyl-util/src/util/object/object.ts
449
- function isPlainObject(value) {
450
- if (!value || typeof value !== "object" || Array.isArray(value))
451
- return false;
452
- const proto = Object.getPrototypeOf(value);
453
- return !proto || !Object.getPrototypeOf(proto);
454
- }
455
-
456
- // ../vinyl-util/src/util/serialization/json.ts
457
- function toJson(value) {
458
- return toJsonInternal(value, /* @__PURE__ */ new Set());
459
- }
460
- function toJsonInternal(value, visited) {
461
- switch (typeof value) {
462
- case "object":
463
- return objectToJsonInternal(value, visited);
464
- case "undefined":
465
- case "boolean":
466
- case "number":
467
- case "string":
468
- return value;
469
- case "function":
470
- return `[function ${value.name}]`;
471
- case "symbol":
472
- return `[symbol ${value.toString().slice(7, -1)}]`;
473
- case "bigint":
474
- return value.toString();
475
- }
476
- }
477
- function objectToJsonInternal(value, visited) {
478
- if (value == null) return value;
479
- if (visited.has(value)) return `<circular reference: ${String(value)}>`;
480
- visited.add(value);
481
- if ("toJSON" in value && typeof value.toJSON === "function")
482
- return value.toJSON();
483
- if (value instanceof Set) {
484
- return Array.from(value).map((e) => toJsonInternal(e, visited));
485
- } else if (Array.isArray(value)) {
486
- return value.map((e) => toJsonInternal(e, visited));
487
- } else {
488
- if (isPlainObject(value)) {
489
- const o = {};
490
- for (const key in value) {
491
- o[key] = toJsonInternal(value[key], visited);
492
- }
493
- return o;
494
- } else if (value instanceof Error) {
495
- return {
496
- name: value.name,
497
- message: value.message,
498
- stack: value.stack
499
- };
562
+ // src/parse/parseAttributes.ts
563
+ var EQUALS = char("=");
564
+ var COMMA = char(",");
565
+ var QUOTE = char('"');
566
+ function parseAttributes(reader) {
567
+ const attrs = {};
568
+ while (reader.hasNext() && reader.peek !== char("\n") && reader.peek !== char("\r")) {
569
+ const key = reader.substringUntilChar(EQUALS);
570
+ if (!key || !reader.hasNext()) break;
571
+ reader.next();
572
+ let value;
573
+ if (reader.peek === QUOTE) {
574
+ reader.next();
575
+ value = reader.substringUntilChar(QUOTE);
576
+ if (reader.hasNext()) reader.next();
500
577
  } else {
501
- return value.toString();
578
+ value = reader.substringUntil(
579
+ (cc) => cc === COMMA || cc === char("\n") || cc === char("\r")
580
+ );
581
+ }
582
+ attrs[key] = value;
583
+ if (reader.hasNext() && reader.peek === COMMA) {
584
+ reader.next();
502
585
  }
503
586
  }
587
+ return attrs;
504
588
  }
505
589
 
506
- // ../vinyl-util/src/util/serialization/stringifyForPrint.ts
507
- function stringifyForPrint(value, maxLength, indicator = "\u2026") {
508
- let str = JSON.stringify(
509
- toJson(value),
510
- (_, value2) => {
511
- const type = typeof value2;
512
- if (["undefined"].includes(type)) {
513
- return `{{${String(value2)}}}`;
514
- }
515
- if (type === "number") {
516
- if (Number.isNaN(value2) || !Number.isFinite(value2))
517
- return `{{${value2.toString()}}}`;
518
- }
519
- return value2;
520
- },
521
- " "
522
- );
523
- str = str.replace(/("\{\{.*}}")/g, (_, s) => {
524
- return s.substring(3, s.length - 3);
525
- });
526
- if (maxLength) str = truncate(str, maxLength, indicator);
527
- return str;
528
- }
529
-
530
- // ../vinyl-util/src/error/ValidationError.ts
531
- var ValidationError = class _ValidationError extends ReportableError {
532
- /**
533
- * @param message The validation error message.
534
- * @param origin The error origin, typically API (default) or SERVICE_EXTERNAL
535
- * @param path The property path to the invalid field.
536
- */
537
- constructor(message, origin = ErrorOrigin.API, path = []) {
538
- super(message, origin);
539
- __publicField(this, "path", path);
540
- Object.setPrototypeOf(this, _ValidationError.prototype);
541
- }
542
- get [Symbol.toStringTag]() {
543
- return "ValidationError";
544
- }
545
- toJSON() {
546
- return __spreadProps(__spreadValues({}, super.toJSON()), {
547
- origin: this.origin,
548
- path: this.path
549
- });
550
- }
551
- };
552
-
553
590
  // ../vinyl-validation/src/validation/Validator.ts
554
591
  var validatorLocale = {
555
592
  /**
@@ -568,9 +605,10 @@
568
605
  path: path.join(".")
569
606
  });
570
607
  }
571
- function createValidator(expectationMessage, isValid, inputStringify = (input) => stringifyForPrint(input, 500)) {
608
+ function createValidator(expectationMessage, isValid, inputStringify = (input) => stringifyForPrint(input, 500), jsonSchema) {
572
609
  return {
573
610
  description: expectationMessage,
611
+ jsonSchema,
574
612
  isValid(input) {
575
613
  return isValid(input);
576
614
  },
@@ -606,9 +644,10 @@
606
644
  }
607
645
  };
608
646
  }
609
- function createDeepValidator(description, validate) {
647
+ function createDeepValidator(description, validate, jsonSchema) {
610
648
  return {
611
649
  description,
650
+ jsonSchema,
612
651
  isValid(input) {
613
652
  return validate(input, { all: false }, []).length === 0;
614
653
  },
@@ -625,6 +664,31 @@
625
664
  };
626
665
  }
627
666
 
667
+ // ../vinyl-validation/src/validation/JsonSchema.ts
668
+ function mergeJsonSchema(...fragments) {
669
+ var _a;
670
+ const merged = {};
671
+ for (const fragment of fragments) {
672
+ if (fragment == null) continue;
673
+ for (const key of ownKeys(fragment)) {
674
+ if (fragment[key] === void 0) continue;
675
+ if (key === "properties") {
676
+ merged.properties = __spreadValues(__spreadValues({}, merged.properties), fragment.properties);
677
+ } else if (key === "required") {
678
+ merged.required = [
679
+ .../* @__PURE__ */ new Set([
680
+ ...(_a = merged.required) != null ? _a : [],
681
+ ...fragment.required
682
+ ])
683
+ ];
684
+ } else {
685
+ merged[key] = fragment[key];
686
+ }
687
+ }
688
+ }
689
+ return merged;
690
+ }
691
+
628
692
  // ../vinyl-validation/src/validation/andValidators.ts
629
693
  var locale3 = {
630
694
  /**
@@ -651,7 +715,8 @@
651
715
  if (errors.length) return errors;
652
716
  }
653
717
  return [];
654
- }
718
+ },
719
+ mergeJsonSchema(...validators.map((v) => v.jsonSchema))
655
720
  );
656
721
  }
657
722
 
@@ -666,36 +731,46 @@
666
731
  */
667
732
  separator: " | "
668
733
  };
734
+ function unionJsonSchema(validators) {
735
+ const branches = validators.map((v) => v.jsonSchema).filter((fragment) => fragment != null);
736
+ if (branches.length === 0) return void 0;
737
+ if (branches.length === 1) return branches[0];
738
+ return { anyOf: branches };
739
+ }
669
740
  function orValidators(...validators) {
670
741
  const description = substitute(locale4.template, {
671
742
  value: validators.map((v) => v.description).join(locale4.separator)
672
743
  });
673
- return createDeepValidator(description, (input, options, path) => {
674
- let longestErrors = [];
675
- let longestPath = 0;
676
- for (const validator of validators) {
677
- const errors = validator.validate(input, options, path);
678
- if (!errors.length) return errors;
679
- const pathLength = errors.reduce(
680
- (max, m) => Math.max(m.path.length, max),
681
- 0
682
- );
683
- if (pathLength >= longestPath) {
684
- longestErrors = errors;
685
- longestPath = pathLength;
744
+ return createDeepValidator(
745
+ description,
746
+ (input, options, path) => {
747
+ let longestErrors = [];
748
+ let longestPath = 0;
749
+ for (const validator of validators) {
750
+ const errors = validator.validate(input, options, path);
751
+ if (!errors.length) return errors;
752
+ const pathLength = errors.reduce(
753
+ (max, m) => Math.max(m.path.length, max),
754
+ 0
755
+ );
756
+ if (pathLength >= longestPath) {
757
+ longestErrors = errors;
758
+ longestPath = pathLength;
759
+ }
686
760
  }
687
- }
688
- return longestPath > path.length ? longestErrors : [
689
- {
690
- message: createValidationExpectationMessage(
691
- description,
692
- input,
761
+ return longestPath > path.length ? longestErrors : [
762
+ {
763
+ message: createValidationExpectationMessage(
764
+ description,
765
+ input,
766
+ path
767
+ ),
693
768
  path
694
- ),
695
- path
696
- }
697
- ];
698
- });
769
+ }
770
+ ];
771
+ },
772
+ unionJsonSchema(validators)
773
+ );
699
774
  }
700
775
 
701
776
  // ../vinyl-validation/src/validation/SchemaBase.ts
@@ -710,6 +785,7 @@
710
785
  __publicField(this, "__type", invariant());
711
786
  __publicField(this, "validator");
712
787
  __publicField(this, "_options", requiredValidationOptions);
788
+ __publicField(this, "_jsonSchemaDescription");
713
789
  __publicField(this, "assert", (input, origin, path) => {
714
790
  this.validator.assert(input, origin, path);
715
791
  });
@@ -723,6 +799,39 @@
723
799
  get description() {
724
800
  return this.validator.description;
725
801
  }
802
+ /**
803
+ * The composed JSON Schema fragment for this schema, including any {@link describe} description.
804
+ * Composes through chaining the same way {@link description} does; serialize a complete
805
+ * definition with {@link toJsonSchema}.
806
+ */
807
+ get jsonSchema() {
808
+ const base = this.validator.jsonSchema;
809
+ if (this._jsonSchemaDescription == null) return base;
810
+ return mergeJsonSchema(base, {
811
+ description: this._jsonSchemaDescription
812
+ });
813
+ }
814
+ /**
815
+ * Attaches a human-readable description to this schema, akin to zod's `describe`.
816
+ * The description is metadata only; it does not affect validation, and surfaces in the output
817
+ * of {@link toJsonSchema}.
818
+ *
819
+ * @param description The description to attach.
820
+ * @return A clone of this schema carrying the description.
821
+ */
822
+ describe(description) {
823
+ const cloned = this.clone();
824
+ cloned._jsonSchemaDescription = description;
825
+ return cloned;
826
+ }
827
+ /**
828
+ * Serializes this schema to a JSON Schema definition, suitable for describing the shape to an
829
+ * LLM or other consumer. Works similarly to zod-to-json-schema.
830
+ */
831
+ toJsonSchema() {
832
+ var _a;
833
+ return (_a = this.jsonSchema) != null ? _a : {};
834
+ }
726
835
  /**
727
836
  * Clones this schema, transforming all validators with the given mutator.
728
837
  *
@@ -737,6 +846,7 @@
737
846
  this.operation
738
847
  ) : this.self(transform(this.currentValidator));
739
848
  cloned._options = this._options;
849
+ cloned._jsonSchemaDescription = this._jsonSchemaDescription;
740
850
  return cloned;
741
851
  }
742
852
  self(current, previous, operation) {
@@ -786,15 +896,30 @@
786
896
  },
787
897
  /**
788
898
  * Creates a validator that asserts that the input is nullish.
899
+ * JSON Schema has no representation for `undefined`, so only `null` is expressed.
789
900
  */
790
901
  nullish() {
791
- return createValidator(locale5.nullish, (input) => input == null);
902
+ return createValidator(
903
+ locale5.nullish,
904
+ (input) => input == null,
905
+ void 0,
906
+ {
907
+ type: "null"
908
+ }
909
+ );
792
910
  },
793
911
  /**
794
912
  * Creates a validator that asserts that the input is strictly null.
795
913
  */
796
914
  null() {
797
- return createValidator(locale5.null, (input) => input === null);
915
+ return createValidator(
916
+ locale5.null,
917
+ (input) => input === null,
918
+ void 0,
919
+ {
920
+ type: "null"
921
+ }
922
+ );
798
923
  },
799
924
  /**
800
925
  * Creates a validator that asserts that the input is strictly undefined.
@@ -860,19 +985,13 @@
860
985
  substitute(locale6.isOneOf, {
861
986
  value: possibleValues.join(locale6.oneOfSeparator)
862
987
  }),
863
- (input) => possibleValues.includes(input)
988
+ (input) => possibleValues.includes(input),
989
+ void 0,
990
+ { enum: [...possibleValues] }
864
991
  )
865
992
  );
866
993
  }
867
994
 
868
- // src/types/EncryptionKey.ts
869
- var encryptionMethodValidator = isOneOf(
870
- "NONE",
871
- "AES-128",
872
- "SAMPLE-AES",
873
- "SAMPLE-AES-CTR"
874
- );
875
-
876
995
  // src/types/AlternativeRendition.ts
877
996
  var renditionTypeValidator = isOneOf(
878
997
  "AUDIO",
@@ -881,6 +1000,14 @@
881
1000
  "CLOSED-CAPTIONS"
882
1001
  );
883
1002
 
1003
+ // src/types/EncryptionKey.ts
1004
+ var encryptionMethodValidator = isOneOf(
1005
+ "NONE",
1006
+ "AES-128",
1007
+ "SAMPLE-AES",
1008
+ "SAMPLE-AES-CTR"
1009
+ );
1010
+
884
1011
  // src/parse/parseUtil.ts
885
1012
  var LF = char("\n");
886
1013
  var CR = char("\r");
@@ -913,36 +1040,8 @@
913
1040
  return obj;
914
1041
  }
915
1042
 
916
- // src/parse/parseAttributes.ts
917
- var EQUALS = char("=");
918
- var COMMA = char(",");
919
- var QUOTE = char('"');
920
- function parseAttributes(reader) {
921
- const attrs = {};
922
- while (reader.hasNext() && reader.peek !== char("\n") && reader.peek !== char("\r")) {
923
- const key = reader.substringUntilChar(EQUALS);
924
- if (!key || !reader.hasNext()) break;
925
- reader.next();
926
- let value;
927
- if (reader.peek === QUOTE) {
928
- reader.next();
929
- value = reader.substringUntilChar(QUOTE);
930
- if (reader.hasNext()) reader.next();
931
- } else {
932
- value = reader.substringUntil(
933
- (cc) => cc === COMMA || cc === char("\n") || cc === char("\r")
934
- );
935
- }
936
- attrs[key] = value;
937
- if (reader.hasNext() && reader.peek === COMMA) {
938
- reader.next();
939
- }
940
- }
941
- return attrs;
942
- }
943
-
944
1043
  // src/parse/parseMediaPlaylist.ts
945
- var HLS_VARIABLE_PATTERN = /\{\$([^}]+)}/g;
1044
+ var HLS_VARIABLE_PATTERN = /\{\$([^{}]+)}/g;
946
1045
  var EXTM3U = "#EXTM3U";
947
1046
  var EXTINF = "#EXTINF:";
948
1047
  var EXT_X_TARGETDURATION = "#EXT-X-TARGETDURATION:";
@@ -955,7 +1054,11 @@
955
1054
  var EXT_X_DISCONTINUITY = "#EXT-X-DISCONTINUITY";
956
1055
  var EXT_X_PROGRAM_DATE_TIME = "#EXT-X-PROGRAM-DATE-TIME:";
957
1056
  var EXT_X_MAP = "#EXT-X-MAP:";
958
- function parseMediaPlaylist(text, variables) {
1057
+ var EXT_X_DEFINE = "#EXT-X-DEFINE:";
1058
+ var EXT_X_DATERANGE = "#EXT-X-DATERANGE:";
1059
+ function parseMediaPlaylist(text, variables, queryParams) {
1060
+ const defines = __spreadValues({}, variables != null ? variables : {});
1061
+ const substituteVars = (v) => Object.keys(defines).length === 0 ? v : substitute(v, defines, HLS_VARIABLE_PATTERN);
959
1062
  const reader = new StringReader(text);
960
1063
  reader.white();
961
1064
  if (!reader.stringIf(EXTM3U)) {
@@ -973,6 +1076,7 @@
973
1076
  let pendingDiscontinuity = false;
974
1077
  let pendingDateTime;
975
1078
  const segments = [];
1079
+ const dateRanges = [];
976
1080
  let sequenceCounter = 0;
977
1081
  while (reader.hasNext()) {
978
1082
  if (skipWhitespaceLine(reader)) continue;
@@ -987,7 +1091,7 @@
987
1091
  if (skipWhitespaceLine(reader)) continue;
988
1092
  const nextLine = readLine(reader).trim();
989
1093
  if (!nextLine.startsWith("#")) {
990
- uri = variables ? substitute(nextLine, variables, HLS_VARIABLE_PATTERN) : nextLine;
1094
+ uri = substituteVars(nextLine);
991
1095
  break;
992
1096
  }
993
1097
  if (nextLine.startsWith(EXT_X_BYTERANGE)) {
@@ -1080,6 +1184,29 @@
1080
1184
  pendingDiscontinuity = true;
1081
1185
  } else if (trimmed.startsWith(EXT_X_PROGRAM_DATE_TIME)) {
1082
1186
  pendingDateTime = trimmed.substring(EXT_X_PROGRAM_DATE_TIME.length);
1187
+ } else if (trimmed.startsWith(EXT_X_DEFINE)) {
1188
+ const attrStr = trimmed.substring(EXT_X_DEFINE.length);
1189
+ const attrReader = new StringReader(attrStr);
1190
+ const attrs = parseAttributes(attrReader);
1191
+ const importName = attrs["IMPORT"];
1192
+ const queryParamName = attrs["QUERYPARAM"];
1193
+ if (importName) {
1194
+ const imported = variables == null ? void 0 : variables[importName];
1195
+ if (imported !== void 0) defines[importName] = imported;
1196
+ } else if (queryParamName) {
1197
+ const queryValue = queryParams == null ? void 0 : queryParams[queryParamName];
1198
+ if (queryValue !== void 0) {
1199
+ defines[queryParamName] = queryValue;
1200
+ }
1201
+ } else if (attrs["NAME"] && attrs["VALUE"]) {
1202
+ defines[attrs["NAME"]] = attrs["VALUE"];
1203
+ }
1204
+ } else if (trimmed.startsWith(EXT_X_DATERANGE)) {
1205
+ const dateRange = parseHlsDateRange(
1206
+ trimmed.substring(EXT_X_DATERANGE.length),
1207
+ substituteVars
1208
+ );
1209
+ if (dateRange) dateRanges.push(dateRange);
1083
1210
  }
1084
1211
  }
1085
1212
  return {
@@ -1088,9 +1215,40 @@
1088
1215
  mediaSequence,
1089
1216
  playlistType,
1090
1217
  ended,
1091
- segments
1218
+ segments,
1219
+ dateRanges
1092
1220
  };
1093
1221
  }
1222
+ var DATERANGE_RESERVED_ATTRS = /* @__PURE__ */ new Set([
1223
+ "ID",
1224
+ "CLASS",
1225
+ "START-DATE",
1226
+ "END-DATE",
1227
+ "DURATION",
1228
+ "PLANNED-DURATION",
1229
+ "END-ON-NEXT"
1230
+ ]);
1231
+ function parseHlsDateRange(attrStr, substituteVars) {
1232
+ const attrs = parseAttributes(new StringReader(attrStr));
1233
+ const id = attrs["ID"];
1234
+ const startDate = "START-DATE" in attrs ? attrs["START-DATE"] : "";
1235
+ const endOnNext = attrs["END-ON-NEXT"] === "YES";
1236
+ if (!id) return void 0;
1237
+ if (!startDate && !endOnNext) return void 0;
1238
+ const clientAttributes = {};
1239
+ for (const [key, value] of Object.entries(attrs)) {
1240
+ if (DATERANGE_RESERVED_ATTRS.has(key)) continue;
1241
+ clientAttributes[key] = substituteVars(value);
1242
+ }
1243
+ return __spreadProps(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({
1244
+ id,
1245
+ startDate
1246
+ }, attrs["CLASS"] && { classId: attrs["CLASS"] }), attrs["END-DATE"] && { endDate: attrs["END-DATE"] }), attrs["DURATION"] && { duration: Number(attrs["DURATION"]) }), attrs["PLANNED-DURATION"] && {
1247
+ plannedDuration: Number(attrs["PLANNED-DURATION"])
1248
+ }), endOnNext && { endOnNext: true }), {
1249
+ clientAttributes
1250
+ });
1251
+ }
1094
1252
  function parseByteRangeString(str) {
1095
1253
  const parts = str.split("@");
1096
1254
  return {
@@ -1104,8 +1262,8 @@
1104
1262
  var EXT_X_STREAM_INF = "#EXT-X-STREAM-INF:";
1105
1263
  var EXT_X_MEDIA = "#EXT-X-MEDIA:";
1106
1264
  var EXT_X_SESSION_DATA = "#EXT-X-SESSION-DATA:";
1107
- var EXT_X_DEFINE = "#EXT-X-DEFINE:";
1108
- function parseMainPlaylist(text) {
1265
+ var EXT_X_DEFINE2 = "#EXT-X-DEFINE:";
1266
+ function parseMainPlaylist(text, queryParams) {
1109
1267
  const reader = new StringReader(text);
1110
1268
  reader.white();
1111
1269
  if (!reader.stringIf(EXTM3U2)) {
@@ -1160,7 +1318,7 @@
1160
1318
  }
1161
1319
  alternativeRenditions.push(
1162
1320
  addIfPresent(
1163
- __spreadValues(__spreadValues({
1321
+ __spreadValues(__spreadValues(__spreadValues(__spreadValues({
1164
1322
  type,
1165
1323
  groupId: attrs["GROUP-ID"],
1166
1324
  name: attrs["NAME"]
@@ -1168,6 +1326,10 @@
1168
1326
  default: attrs["DEFAULT"] === "YES"
1169
1327
  }), attrs["AUTOSELECT"] && {
1170
1328
  autoSelect: attrs["AUTOSELECT"] === "YES"
1329
+ }), attrs["FORCED"] && {
1330
+ forced: attrs["FORCED"] === "YES"
1331
+ }), attrs["CHARACTERISTICS"] && {
1332
+ characteristics: attrs["CHARACTERISTICS"].split(",").map((c) => c.trim()).filter((c) => c.length > 0)
1171
1333
  }),
1172
1334
  attrs,
1173
1335
  {
@@ -1193,11 +1355,17 @@
1193
1355
  }
1194
1356
  )
1195
1357
  );
1196
- } else if (trimmed.startsWith(EXT_X_DEFINE)) {
1197
- const attrStr = trimmed.substring(EXT_X_DEFINE.length);
1358
+ } else if (trimmed.startsWith(EXT_X_DEFINE2)) {
1359
+ const attrStr = trimmed.substring(EXT_X_DEFINE2.length);
1198
1360
  const attrReader = new StringReader(attrStr);
1199
1361
  const attrs = parseAttributes(attrReader);
1200
- if (attrs["NAME"] && attrs["VALUE"]) {
1362
+ const queryParamName = attrs["QUERYPARAM"];
1363
+ if (queryParamName) {
1364
+ const queryValue = queryParams == null ? void 0 : queryParams[queryParamName];
1365
+ if (queryValue !== void 0) {
1366
+ defines[queryParamName] = queryValue;
1367
+ }
1368
+ } else if (attrs["NAME"] && attrs["VALUE"]) {
1201
1369
  defines[attrs["NAME"]] = attrs["VALUE"];
1202
1370
  }
1203
1371
  }
@@ -1225,85 +1393,6 @@
1225
1393
  return { width, height };
1226
1394
  }
1227
1395
 
1228
- // ../vinyl-util/test/browserTestUtil/mock/createSpyFactory.ts
1229
- var createSpy = jasmine.createSpy;
1230
- function createSpy2(key) {
1231
- return createSpy(String(key));
1232
- }
1233
-
1234
- // ../vinyl-util/test/browserTestUtil/mock/dom/lib.dom.ts
1235
- var MockAbortSignal = class {
1236
- constructor() {
1237
- __publicField(this, "aborted", false);
1238
- __publicField(this, "onabort", null);
1239
- __publicField(this, "reason");
1240
- __publicField(this, "throwIfAborted", createSpy2("throwIfAborted"));
1241
- __publicField(this, "addEventListener", createSpy2("addEventListener"));
1242
- __publicField(this, "removeEventListener", createSpy2(
1243
- "removeEventListener"
1244
- ));
1245
- __publicField(this, "dispatchEvent", createSpy2("dispatchEvent"));
1246
- }
1247
- };
1248
- var MockMediaSource = class {
1249
- constructor() {
1250
- __publicField(this, "activeSourceBuffers");
1251
- __publicField(this, "duration", 0);
1252
- __publicField(this, "onsourceclose", null);
1253
- __publicField(this, "onsourceended", null);
1254
- __publicField(this, "onsourceopen", null);
1255
- __publicField(this, "readyState", "closed");
1256
- __publicField(this, "sourceBuffers");
1257
- __publicField(this, "addSourceBuffer", createSpy2("addSourceBuffer"));
1258
- __publicField(this, "clearLiveSeekableRange", createSpy2(
1259
- "clearLiveSeekableRange"
1260
- ));
1261
- __publicField(this, "endOfStream", createSpy2("endOfStream"));
1262
- __publicField(this, "removeSourceBuffer", createSpy2("removeSourceBuffer"));
1263
- __publicField(this, "setLiveSeekableRange", createSpy2(
1264
- "setLiveSeekableRange"
1265
- ));
1266
- __publicField(this, "addEventListener", createSpy2("addEventListener"));
1267
- __publicField(this, "removeEventListener", createSpy2(
1268
- "removeEventListener"
1269
- ));
1270
- __publicField(this, "dispatchEvent", createSpy2("dispatchEvent"));
1271
- }
1272
- };
1273
-
1274
- // ../vinyl-util/test/browserTestUtil/mock/dom/globals.ts
1275
- var MockMediaSourceGlobal = class extends MockMediaSource {
1276
- };
1277
- __publicField(MockMediaSourceGlobal, "canConstructInDedicatedWorker", false);
1278
- __publicField(MockMediaSourceGlobal, "isTypeSupported", createSpy2(
1279
- "isTypeSupported"
1280
- ));
1281
- var MockAbortSignalGlobal = class extends MockAbortSignal {
1282
- };
1283
- __publicField(MockAbortSignalGlobal, "abort", createSpy2("abort"));
1284
- __publicField(MockAbortSignalGlobal, "any", createSpy2("any"));
1285
- __publicField(MockAbortSignalGlobal, "timeout", createSpy2("timeout"));
1286
-
1287
- // ../vinyl-util/test/browserTestUtil/expect/expectNothing.ts
1288
- function expectNothing() {
1289
- expect(true).toBeTruthy();
1290
- }
1291
-
1292
- // ../vinyl-util/test/browserTestUtil/env/jasmineEnv.ts
1293
- var nextTestTimeoutOverridden = false;
1294
- function setTestTimeout(timeout) {
1295
- let originalTimeout = null;
1296
- beforeEach(() => {
1297
- originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
1298
- if (!nextTestTimeoutOverridden)
1299
- jasmine.DEFAULT_TIMEOUT_INTERVAL = timeout * 1e3;
1300
- });
1301
- afterEach(() => {
1302
- if (originalTimeout) jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
1303
- if (nextTestTimeoutOverridden) nextTestTimeoutOverridden = false;
1304
- });
1305
- }
1306
-
1307
1396
  // ../vinyl-util/test/browserTestUtil/benchmark/Benchmark.ts
1308
1397
  var now;
1309
1398
  if (typeof window !== "undefined" && typeof window.performance !== "undefined" && typeof window.performance.now !== "undefined") {
@@ -1506,6 +1595,85 @@
1506
1595
  return sum / values.length;
1507
1596
  }
1508
1597
 
1598
+ // ../vinyl-util/test/browserTestUtil/env/jasmineEnv.ts
1599
+ var nextTestTimeoutOverridden = false;
1600
+ function setTestTimeout(timeout) {
1601
+ let originalTimeout = null;
1602
+ beforeEach(() => {
1603
+ originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
1604
+ if (!nextTestTimeoutOverridden)
1605
+ jasmine.DEFAULT_TIMEOUT_INTERVAL = timeout * 1e3;
1606
+ });
1607
+ afterEach(() => {
1608
+ if (originalTimeout) jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
1609
+ if (nextTestTimeoutOverridden) nextTestTimeoutOverridden = false;
1610
+ });
1611
+ }
1612
+
1613
+ // ../vinyl-util/test/browserTestUtil/expect/expectNothing.ts
1614
+ function expectNothing() {
1615
+ expect(true).toBeTruthy();
1616
+ }
1617
+
1618
+ // ../vinyl-util/test/browserTestUtil/mock/createSpyFactory.ts
1619
+ var createSpy = jasmine.createSpy;
1620
+ function createSpy2(key) {
1621
+ return createSpy(String(key));
1622
+ }
1623
+
1624
+ // ../vinyl-util/test/browserTestUtil/mock/dom/lib.dom.ts
1625
+ var MockAbortSignal = class {
1626
+ constructor() {
1627
+ __publicField(this, "aborted", false);
1628
+ __publicField(this, "onabort", null);
1629
+ __publicField(this, "reason");
1630
+ __publicField(this, "throwIfAborted", createSpy2("throwIfAborted"));
1631
+ __publicField(this, "addEventListener", createSpy2("addEventListener"));
1632
+ __publicField(this, "removeEventListener", createSpy2(
1633
+ "removeEventListener"
1634
+ ));
1635
+ __publicField(this, "dispatchEvent", createSpy2("dispatchEvent"));
1636
+ }
1637
+ };
1638
+ var MockMediaSource = class {
1639
+ constructor() {
1640
+ __publicField(this, "activeSourceBuffers");
1641
+ __publicField(this, "duration", 0);
1642
+ __publicField(this, "onsourceclose", null);
1643
+ __publicField(this, "onsourceended", null);
1644
+ __publicField(this, "onsourceopen", null);
1645
+ __publicField(this, "readyState", "closed");
1646
+ __publicField(this, "sourceBuffers");
1647
+ __publicField(this, "addSourceBuffer", createSpy2("addSourceBuffer"));
1648
+ __publicField(this, "clearLiveSeekableRange", createSpy2(
1649
+ "clearLiveSeekableRange"
1650
+ ));
1651
+ __publicField(this, "endOfStream", createSpy2("endOfStream"));
1652
+ __publicField(this, "removeSourceBuffer", createSpy2("removeSourceBuffer"));
1653
+ __publicField(this, "setLiveSeekableRange", createSpy2(
1654
+ "setLiveSeekableRange"
1655
+ ));
1656
+ __publicField(this, "addEventListener", createSpy2("addEventListener"));
1657
+ __publicField(this, "removeEventListener", createSpy2(
1658
+ "removeEventListener"
1659
+ ));
1660
+ __publicField(this, "dispatchEvent", createSpy2("dispatchEvent"));
1661
+ }
1662
+ };
1663
+
1664
+ // ../vinyl-util/test/browserTestUtil/mock/dom/globals.ts
1665
+ var MockMediaSourceGlobal = class extends MockMediaSource {
1666
+ };
1667
+ __publicField(MockMediaSourceGlobal, "canConstructInDedicatedWorker", false);
1668
+ __publicField(MockMediaSourceGlobal, "isTypeSupported", createSpy2(
1669
+ "isTypeSupported"
1670
+ ));
1671
+ var MockAbortSignalGlobal = class extends MockAbortSignal {
1672
+ };
1673
+ __publicField(MockAbortSignalGlobal, "abort", createSpy2("abort"));
1674
+ __publicField(MockAbortSignalGlobal, "any", createSpy2("any"));
1675
+ __publicField(MockAbortSignalGlobal, "timeout", createSpy2("timeout"));
1676
+
1509
1677
  // test/benchmark/setup.ts
1510
1678
  function setupBenchmark() {
1511
1679
  setTestTimeout(180);