@altano/html-cdnify 6.0.0 → 6.0.2

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.
@@ -1,7 +1,6 @@
1
1
  import { HtmlAttributeStreamTransformer, TransformDefinition } from "./HtmlAttributeStreamTransformer.js";
2
- //#region src/CDNTransformer.d.ts
3
- type CDNTransformFunction = (cdnUrl: string, oldUrl: string, bufferPath: string) => string;
4
- interface CDNTransformerOptions {
2
+ export type CDNTransformFunction = (cdnUrl: string, oldUrl: string, bufferPath: string) => string;
3
+ export interface CDNTransformerOptions {
5
4
  cdnUrl: string;
6
5
  bufferPath?: string;
7
6
  transformDefinitions?: TransformDefinition[];
@@ -13,12 +12,10 @@ interface CDNTransformerOptions {
13
12
  * attributes that identify CDN-able resources converted to
14
13
  * use the given CDN URL.
15
14
  */
16
- declare class CDNTransformer extends HtmlAttributeStreamTransformer {
15
+ export declare class CDNTransformer extends HtmlAttributeStreamTransformer {
17
16
  #private;
18
17
  cdnOptions: Required<CDNTransformerOptions>;
19
18
  constructor(cdnOptions: CDNTransformerOptions);
20
19
  static defaultTransformFunction: CDNTransformFunction;
21
20
  }
22
- //#endregion
23
- export { CDNTransformFunction, CDNTransformer, CDNTransformerOptions };
24
21
  //# sourceMappingURL=CDNTransformer.d.ts.map
@@ -2,7 +2,7 @@ import urlConverter_default from "./urlConverter.js";
2
2
  import { HtmlAttributeStreamTransformer } from "./HtmlAttributeStreamTransformer.js";
3
3
  import { merge, mergeWith, unionBy } from "lodash-es";
4
4
 
5
- //#region src/CDNTransformer.ts
5
+ // src/CDNTransformer.ts
6
6
  /**
7
7
  * Handles merging objects that have TransformDefinition arrays
8
8
  */
@@ -95,6 +95,5 @@ var CDNTransformer = class CDNTransformer extends HtmlAttributeStreamTransformer
95
95
  };
96
96
  };
97
97
 
98
- //#endregion
99
98
  export { CDNTransformer };
100
99
  //# sourceMappingURL=CDNTransformer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CDNTransformer.js","names":["HtmlAttributeStreamTransformer.HtmlAttributeStreamTransformer","#defaultHtmlAttributeStreamTransformerOptions","#cdnifyAttribute","#defaultCdnOptions","urlConverter"],"sources":["../src/CDNTransformer.ts"],"sourcesContent":["import { unionBy, merge, mergeWith } from \"lodash-es\";\nimport urlConverter from \"./urlConverter.js\";\n\nimport * as HtmlAttributeStreamTransformer from \"./HtmlAttributeStreamTransformer.js\";\n\nexport type CDNTransformFunction = (\n cdnUrl: string,\n oldUrl: string,\n bufferPath: string,\n) => string;\n\nexport interface CDNTransformerOptions {\n cdnUrl: string;\n bufferPath?: string;\n\n transformDefinitions?: HtmlAttributeStreamTransformer.TransformDefinition[];\n transformFunction?: CDNTransformFunction;\n}\n\n/**\n * Handles merging objects that have TransformDefinition arrays\n */\nclass OptionsMerger {\n static isTransformDefinition(\n a: unknown,\n ): a is HtmlAttributeStreamTransformer.TransformDefinition {\n return (\n a != null &&\n typeof a === \"object\" &&\n \"selector\" in a &&\n \"attribute\" in a &&\n typeof a.selector === \"string\" &&\n typeof a.selector === \"string\" &&\n typeof a.attribute === \"string\"\n );\n }\n\n static isTransformDefinitions(\n a: unknown,\n ): a is HtmlAttributeStreamTransformer.TransformDefinition[] {\n return (\n Array.isArray(a) &&\n a.length > 0 &&\n OptionsMerger.isTransformDefinition(a[0])\n );\n }\n\n static mergeCustomizer = (objValue: unknown, srcValue: unknown): unknown => {\n if (\n OptionsMerger.isTransformDefinitions(objValue) &&\n OptionsMerger.isTransformDefinitions(srcValue)\n ) {\n const result = unionBy(\n srcValue,\n objValue, // reverse order to allow srcValue to take precedence\n (value: HtmlAttributeStreamTransformer.TransformDefinition) =>\n `${value.selector} / ${value.attribute}`,\n );\n\n return result;\n } else {\n return undefined;\n }\n };\n\n static merge<T, U, V, W>(\n target: T,\n source1: U,\n source2: V,\n source3: W,\n ): T & U & V & W {\n return mergeWith(\n target,\n source1,\n source2,\n source3,\n OptionsMerger.mergeCustomizer,\n );\n }\n}\n\n/**\n * Wraps an HtmlRewriteStream, w/ HTML as input and\n * HTML as output. The output will have all non-absolute-URL\n * attributes that identify CDN-able resources converted to\n * use the given CDN URL.\n */\nexport class CDNTransformer\n extends HtmlAttributeStreamTransformer.HtmlAttributeStreamTransformer\n{\n public cdnOptions: Required<CDNTransformerOptions>;\n\n constructor(cdnOptions: CDNTransformerOptions) {\n super(\n OptionsMerger.merge(\n {},\n CDNTransformer.#defaultHtmlAttributeStreamTransformerOptions,\n {\n transformDefinitions: [],\n transformFunction: (attribute: string) =>\n this.#cdnifyAttribute(attribute),\n },\n {\n transformDefinitions: cdnOptions.transformDefinitions,\n },\n ),\n );\n\n this.cdnOptions = merge(\n {\n transformDefinitions: [],\n },\n CDNTransformer.#defaultCdnOptions,\n cdnOptions,\n );\n\n if (typeof this.cdnOptions.cdnUrl !== \"string\") {\n throw new Error(`Invalid cdnUrl specified.`);\n }\n }\n\n #cdnifyAttribute(oldUrl: string): string {\n return this.cdnOptions.transformFunction(\n this.cdnOptions.cdnUrl,\n oldUrl,\n this.cdnOptions.bufferPath,\n );\n }\n\n static #defaultCdnOptions = {\n bufferPath: \".\",\n transformFunction: urlConverter,\n } as const;\n\n public static defaultTransformFunction: CDNTransformFunction =\n CDNTransformer.#defaultCdnOptions.transformFunction;\n\n static #defaultHtmlAttributeStreamTransformerOptions = {\n attributeToMarkElementToBeIgnored: \"data-cdn-ignore\",\n\n // inspired by https://github.com/callumlocke/grunt-cdnify/blob/master/tasks/cdnify.js#L31\n transformDefinitions: [\n {\n selector: `video[poster]:not([data-cdn-ignore])`,\n attribute: \"poster\",\n },\n {\n selector: `img[data-src]:not([data-cdn-ignore])`,\n attribute: \"data-src\",\n },\n {\n selector: `script[src]:not([data-cdn-ignore])`,\n attribute: \"src\",\n },\n {\n selector: `source[src]:not([data-cdn-ignore])`,\n attribute: \"src\",\n },\n {\n selector: `link[rel=\"apple-touch-icon\"]:not([data-cdn-ignore])`,\n attribute: \"href\",\n },\n {\n selector: `link[rel=\"icon\"]:not([data-cdn-ignore])`,\n attribute: \"href\",\n },\n {\n selector: `link[rel=\"shortcut icon\"]:not([data-cdn-ignore])`,\n attribute: \"href\",\n },\n {\n selector: `link[rel=\"stylesheet\"]:not([data-cdn-ignore])`,\n attribute: \"href\",\n },\n {\n selector: `img[src]:not([data-cdn-ignore])`,\n attribute: \"src\",\n },\n {\n selector: `img[srcset]:not([data-cdn-ignore])`,\n attribute: \"srcset\",\n attributeParser(\n attr: string,\n transformFunction: HtmlAttributeStreamTransformer.TransformFunction,\n ): string {\n return attr\n .split(\",\")\n .map((imgInfo) => imgInfo.replace(/([^ ]+)/, transformFunction))\n .join(\",\");\n },\n },\n ],\n } as const;\n}\n"],"mappings":";;;;;;;;AAsBA,IAAM,gBAAN,MAAM,cAAc;CAClB,OAAO,sBACL,GACyD;EACzD,OACE,KAAK,QACL,OAAO,MAAM,YACb,cAAc,KACd,eAAe,KACf,OAAO,EAAE,aAAa,YACtB,OAAO,EAAE,aAAa,YACtB,OAAO,EAAE,cAAc;CAE3B;CAEA,OAAO,uBACL,GAC2D;EAC3D,OACE,MAAM,QAAQ,CAAC,KACf,EAAE,SAAS,KACX,cAAc,sBAAsB,EAAE,EAAE;CAE5C;CAEA,OAAO,mBAAmB,UAAmB,aAA+B;EAC1E,IACE,cAAc,uBAAuB,QAAQ,KAC7C,cAAc,uBAAuB,QAAQ,GAS7C,OAPe,QACb,UACA,WACC,UACC,GAAG,MAAM,SAAS,KAAK,MAAM,WAGrB;OAEZ;CAEJ;CAEA,OAAO,MACL,QACA,SACA,SACA,SACe;EACf,OAAO,UACL,QACA,SACA,SACA,SACA,cAAc,eAChB;CACF;AACF;;;;;;;AAQA,IAAa,iBAAb,MAAa,uBACHA,+BACV;CACE,AAAO;CAEP,YAAY,YAAmC;EAC7C,MACE,cAAc,MACZ,CAAC,GACD,eAAeC,+CACf;GACE,sBAAsB,CAAC;GACvB,oBAAoB,cAClB,KAAKC,iBAAiB,SAAS;EACnC,GACA,EACE,sBAAsB,WAAW,qBACnC,CACF,CACF;EAEA,KAAK,aAAa,MAChB,EACE,sBAAsB,CAAC,EACzB,GACA,eAAeC,oBACf,UACF;EAEA,IAAI,OAAO,KAAK,WAAW,WAAW,UACpC,MAAM,IAAI,MAAM,2BAA2B;CAE/C;CAEA,iBAAiB,QAAwB;EACvC,OAAO,KAAK,WAAW,kBACrB,KAAK,WAAW,QAChB,QACA,KAAK,WAAW,UAClB;CACF;CAEA,OAAOA,qBAAqB;EAC1B,YAAY;EACZ,mBAAmBC;CACrB;CAEA,OAAc,2BACZ,eAAeD,mBAAmB;CAEpC,OAAOF,gDAAgD;EACrD,mCAAmC;EAGnC,sBAAsB;GACpB;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;IACX,gBACE,MACA,mBACQ;KACR,OAAO,KACJ,MAAM,GAAG,CAAC,CACV,KAAK,YAAY,QAAQ,QAAQ,WAAW,iBAAiB,CAAC,CAAC,CAC/D,KAAK,GAAG;IACb;GACF;EACF;CACF;AACF"}
1
+ {"version":3,"file":"CDNTransformer.js","names":["HtmlAttributeStreamTransformer.HtmlAttributeStreamTransformer","urlConverter"],"sources":["../src/CDNTransformer.ts"],"sourcesContent":["import { unionBy, merge, mergeWith } from \"lodash-es\";\nimport urlConverter from \"./urlConverter.js\";\n\nimport * as HtmlAttributeStreamTransformer from \"./HtmlAttributeStreamTransformer.js\";\n\nexport type CDNTransformFunction = (\n cdnUrl: string,\n oldUrl: string,\n bufferPath: string,\n) => string;\n\nexport interface CDNTransformerOptions {\n cdnUrl: string;\n bufferPath?: string;\n\n transformDefinitions?: HtmlAttributeStreamTransformer.TransformDefinition[];\n transformFunction?: CDNTransformFunction;\n}\n\n/**\n * Handles merging objects that have TransformDefinition arrays\n */\nclass OptionsMerger {\n static isTransformDefinition(\n a: unknown,\n ): a is HtmlAttributeStreamTransformer.TransformDefinition {\n return (\n a != null &&\n typeof a === \"object\" &&\n \"selector\" in a &&\n \"attribute\" in a &&\n typeof a.selector === \"string\" &&\n typeof a.selector === \"string\" &&\n typeof a.attribute === \"string\"\n );\n }\n\n static isTransformDefinitions(\n a: unknown,\n ): a is HtmlAttributeStreamTransformer.TransformDefinition[] {\n return (\n Array.isArray(a) &&\n a.length > 0 &&\n OptionsMerger.isTransformDefinition(a[0])\n );\n }\n\n static mergeCustomizer = (objValue: unknown, srcValue: unknown): unknown => {\n if (\n OptionsMerger.isTransformDefinitions(objValue) &&\n OptionsMerger.isTransformDefinitions(srcValue)\n ) {\n const result = unionBy(\n srcValue,\n objValue, // reverse order to allow srcValue to take precedence\n (value: HtmlAttributeStreamTransformer.TransformDefinition) =>\n `${value.selector} / ${value.attribute}`,\n );\n\n return result;\n } else {\n return undefined;\n }\n };\n\n static merge<T, U, V, W>(\n target: T,\n source1: U,\n source2: V,\n source3: W,\n ): T & U & V & W {\n return mergeWith(\n target,\n source1,\n source2,\n source3,\n OptionsMerger.mergeCustomizer,\n );\n }\n}\n\n/**\n * Wraps an HtmlRewriteStream, w/ HTML as input and\n * HTML as output. The output will have all non-absolute-URL\n * attributes that identify CDN-able resources converted to\n * use the given CDN URL.\n */\nexport class CDNTransformer\n extends HtmlAttributeStreamTransformer.HtmlAttributeStreamTransformer\n{\n public cdnOptions: Required<CDNTransformerOptions>;\n\n constructor(cdnOptions: CDNTransformerOptions) {\n super(\n OptionsMerger.merge(\n {},\n CDNTransformer.#defaultHtmlAttributeStreamTransformerOptions,\n {\n transformDefinitions: [],\n transformFunction: (attribute: string) =>\n this.#cdnifyAttribute(attribute),\n },\n {\n transformDefinitions: cdnOptions.transformDefinitions,\n },\n ),\n );\n\n this.cdnOptions = merge(\n {\n transformDefinitions: [],\n },\n CDNTransformer.#defaultCdnOptions,\n cdnOptions,\n );\n\n if (typeof this.cdnOptions.cdnUrl !== \"string\") {\n throw new Error(`Invalid cdnUrl specified.`);\n }\n }\n\n #cdnifyAttribute(oldUrl: string): string {\n return this.cdnOptions.transformFunction(\n this.cdnOptions.cdnUrl,\n oldUrl,\n this.cdnOptions.bufferPath,\n );\n }\n\n static #defaultCdnOptions = {\n bufferPath: \".\",\n transformFunction: urlConverter,\n } as const;\n\n public static defaultTransformFunction: CDNTransformFunction =\n CDNTransformer.#defaultCdnOptions.transformFunction;\n\n static #defaultHtmlAttributeStreamTransformerOptions = {\n attributeToMarkElementToBeIgnored: \"data-cdn-ignore\",\n\n // inspired by https://github.com/callumlocke/grunt-cdnify/blob/master/tasks/cdnify.js#L31\n transformDefinitions: [\n {\n selector: `video[poster]:not([data-cdn-ignore])`,\n attribute: \"poster\",\n },\n {\n selector: `img[data-src]:not([data-cdn-ignore])`,\n attribute: \"data-src\",\n },\n {\n selector: `script[src]:not([data-cdn-ignore])`,\n attribute: \"src\",\n },\n {\n selector: `source[src]:not([data-cdn-ignore])`,\n attribute: \"src\",\n },\n {\n selector: `link[rel=\"apple-touch-icon\"]:not([data-cdn-ignore])`,\n attribute: \"href\",\n },\n {\n selector: `link[rel=\"icon\"]:not([data-cdn-ignore])`,\n attribute: \"href\",\n },\n {\n selector: `link[rel=\"shortcut icon\"]:not([data-cdn-ignore])`,\n attribute: \"href\",\n },\n {\n selector: `link[rel=\"stylesheet\"]:not([data-cdn-ignore])`,\n attribute: \"href\",\n },\n {\n selector: `img[src]:not([data-cdn-ignore])`,\n attribute: \"src\",\n },\n {\n selector: `img[srcset]:not([data-cdn-ignore])`,\n attribute: \"srcset\",\n attributeParser(\n attr: string,\n transformFunction: HtmlAttributeStreamTransformer.TransformFunction,\n ): string {\n return attr\n .split(\",\")\n .map((imgInfo) => imgInfo.replace(/([^ ]+)/, transformFunction))\n .join(\",\");\n },\n },\n ],\n } as const;\n}\n"],"mappings":";;;;;;;;AAsBA,IAAM,gBAAN,MAAM,cAAc;CAClB,OAAO,sBACL,GACyD;EACzD,OACE,KAAK,QACL,OAAO,MAAM,YACb,cAAc,KACd,eAAe,KACf,OAAO,EAAE,aAAa,YACtB,OAAO,EAAE,aAAa,YACtB,OAAO,EAAE,cAAc;CAE3B;CAEA,OAAO,uBACL,GAC2D;EAC3D,OACE,MAAM,QAAQ,CAAC,KACf,EAAE,SAAS,KACX,cAAc,sBAAsB,EAAE,EAAE;CAE5C;CAEA,OAAO,mBAAmB,UAAmB,aAA+B;EAC1E,IACE,cAAc,uBAAuB,QAAQ,KAC7C,cAAc,uBAAuB,QAAQ,GAS7C,OAPe,QACb,UACA,WACC,UACC,GAAG,MAAM,SAAS,KAAK,MAAM,WAGrB;OAEZ;CAEJ;CAEA,OAAO,MACL,QACA,SACA,SACA,SACe;EACf,OAAO,UACL,QACA,SACA,SACA,SACA,cAAc,eAChB;CACF;AACF;;;;;;;AAQA,IAAa,iBAAb,MAAa,uBACHA,+BACV;CACE,AAAO;CAEP,YAAY,YAAmC;EAC7C,MACE,cAAc,MACZ,CAAC,GACD,eAAe,+CACf;GACE,sBAAsB,CAAC;GACvB,oBAAoB,cAClB,KAAK,iBAAiB,SAAS;EACnC,GACA,EACE,sBAAsB,WAAW,qBACnC,CACF,CACF;EAEA,KAAK,aAAa,MAChB,EACE,sBAAsB,CAAC,EACzB,GACA,eAAe,oBACf,UACF;EAEA,IAAI,OAAO,KAAK,WAAW,WAAW,UACpC,MAAM,IAAI,MAAM,2BAA2B;CAE/C;CAEA,iBAAiB,QAAwB;EACvC,OAAO,KAAK,WAAW,kBACrB,KAAK,WAAW,QAChB,QACA,KAAK,WAAW,UAClB;CACF;CAEA,OAAO,qBAAqB;EAC1B,YAAY;EACZ,mBAAmBC;CACrB;CAEA,OAAc,2BACZ,eAAe,mBAAmB;CAEpC,OAAO,gDAAgD;EACrD,mCAAmC;EAGnC,sBAAsB;GACpB;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;GACb;GACA;IACE,UAAU;IACV,WAAW;IACX,gBACE,MACA,mBACQ;KACR,OAAO,KACJ,MAAM,GAAG,CAAC,CACV,KAAK,YAAY,QAAQ,QAAQ,WAAW,iBAAiB,CAAC,CAAC,CAC/D,KAAK,GAAG;IACb;GACF;EACF;CACF;AACF"}
@@ -1,20 +1,19 @@
1
1
  import HtmlTransformer from "./HtmlTransformer.js";
2
- //#region src/HtmlAttributeStreamTransformer.d.ts
3
- interface HtmlAttributeStreamTransformerOptions {
2
+ export interface HtmlAttributeStreamTransformerOptions {
4
3
  transformDefinitions: TransformDefinition[];
5
4
  transformFunction: TransformFunction;
6
5
  attributeToMarkElementToBeIgnored?: string;
7
6
  }
8
- interface TransformDefinition {
7
+ export interface TransformDefinition {
9
8
  selector: string;
10
9
  attribute: string;
11
10
  attributeParser?: undefined | ((oldAttribute: string, transformFunction: TransformFunction) => string);
12
11
  }
13
- type TransformFunction = (oldAttribute: string) => string;
14
- interface AttributeParser {
12
+ export type TransformFunction = (oldAttribute: string) => string;
13
+ export interface AttributeParser {
15
14
  (oldAttribute: string, transformFunction: TransformFunction): string;
16
15
  }
17
- interface AttributeParsers {
16
+ export interface AttributeParsers {
18
17
  [index: string]: AttributeParser;
19
18
  }
20
19
  /**
@@ -23,7 +22,7 @@ interface AttributeParsers {
23
22
  * attributes that identify CDN-able resources converted to
24
23
  * use the given CDN URL.
25
24
  */
26
- declare class HtmlAttributeStreamTransformer extends HtmlTransformer {
25
+ export declare class HtmlAttributeStreamTransformer extends HtmlTransformer {
27
26
  condensedTransformOptions: TransformDefinition[];
28
27
  options: HtmlAttributeStreamTransformerOptions;
29
28
  constructor(options: HtmlAttributeStreamTransformerOptions);
@@ -31,6 +30,4 @@ declare class HtmlAttributeStreamTransformer extends HtmlTransformer {
31
30
  protected applyTransforms(): void;
32
31
  private processTransforms;
33
32
  }
34
- //#endregion
35
- export { AttributeParser, AttributeParsers, HtmlAttributeStreamTransformer, HtmlAttributeStreamTransformerOptions, TransformDefinition, TransformFunction };
36
33
  //# sourceMappingURL=HtmlAttributeStreamTransformer.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import HtmlTransformer from "./HtmlTransformer.js";
2
2
  import { groupBy } from "lodash-es";
3
3
 
4
- //#region src/HtmlAttributeStreamTransformer.ts
4
+ // src/HtmlAttributeStreamTransformer.ts
5
5
  /**
6
6
  * Wraps an HtmlRewriteStream, w/ HTML as input and
7
7
  * HTML as output. The output will have all non-absolute-URL
@@ -61,6 +61,5 @@ var HtmlAttributeStreamTransformer = class HtmlAttributeStreamTransformer extend
61
61
  }
62
62
  };
63
63
 
64
- //#endregion
65
64
  export { HtmlAttributeStreamTransformer };
66
65
  //# sourceMappingURL=HtmlAttributeStreamTransformer.js.map
@@ -1,5 +1,4 @@
1
1
  import { RewritingStream } from "parse5-html-rewriting-stream";
2
- //#region src/HtmlRewriteStream.d.ts
3
2
  /**
4
3
  * The subset of a DOM element that transforms are allowed to touch.
5
4
  *
@@ -7,12 +6,12 @@ import { RewritingStream } from "parse5-html-rewriting-stream";
7
6
  * `true` rather than `""`, so callers can tell it apart from an attribute
8
7
  * holding a real value.
9
8
  */
10
- interface SelectedElement {
9
+ export interface SelectedElement {
11
10
  getAttribute(name: string): string | true | undefined;
12
11
  setAttribute(name: string, value: string): void;
13
12
  removeAttribute(name: string): void;
14
13
  }
15
- type SelectionHandler = (element: SelectedElement) => void;
14
+ export type SelectionHandler = (element: SelectedElement) => void;
16
15
  /**
17
16
  * An HTML-in, HTML-out transform stream that rewrites attributes on elements
18
17
  * matching a CSS selector.
@@ -27,7 +26,7 @@ type SelectionHandler = (element: SelectedElement) => void;
27
26
  * ships, and every selector its tests exercise, is element-local: a tag name
28
27
  * plus attribute predicates, optionally negated with `:not()`.
29
28
  */
30
- declare class HtmlRewriteStream extends RewritingStream {
29
+ export declare class HtmlRewriteStream extends RewritingStream {
31
30
  #private;
32
31
  constructor();
33
32
  /**
@@ -43,6 +42,4 @@ declare class HtmlRewriteStream extends RewritingStream {
43
42
  override _transform(chunk: string | Buffer, encoding: string, callback: (error?: Error | null, data?: string) => void): void;
44
43
  override _final(callback: (error?: Error | null, data?: string) => void): void;
45
44
  }
46
- //#endregion
47
- export { HtmlRewriteStream, SelectedElement, SelectionHandler };
48
45
  //# sourceMappingURL=HtmlRewriteStream.d.ts.map
@@ -3,7 +3,7 @@ import { Element } from "domhandler";
3
3
  import { compile } from "css-select";
4
4
  import { StringDecoder } from "node:string_decoder";
5
5
 
6
- //#region src/HtmlRewriteStream.ts
6
+ // src/HtmlRewriteStream.ts
7
7
  /**
8
8
  * An HTML-in, HTML-out transform stream that rewrites attributes on elements
9
9
  * matching a CSS selector.
@@ -80,6 +80,5 @@ var HtmlRewriteStream = class extends RewritingStream {
80
80
  }
81
81
  };
82
82
 
83
- //#endregion
84
83
  export { HtmlRewriteStream };
85
84
  //# sourceMappingURL=HtmlRewriteStream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HtmlRewriteStream.js","names":["#selections","#decoder"],"sources":["../src/HtmlRewriteStream.ts"],"sourcesContent":["import { RewritingStream } from \"parse5-html-rewriting-stream\";\nimport { Element } from \"domhandler\";\nimport { compile } from \"css-select\";\nimport { StringDecoder } from \"node:string_decoder\";\nimport type { Element as DomElement } from \"domhandler\";\n\n/**\n * css-select's own `CompiledQuery` isn't re-exported from its entry point, but\n * it is structurally just a predicate over a node.\n */\ntype CompiledSelector = (node: DomElement) => boolean;\n\n/**\n * The subset of a DOM element that transforms are allowed to touch.\n *\n * `getAttribute` reports a valueless attribute (`<img data-cdn-ignore>`) as\n * `true` rather than `\"\"`, so callers can tell it apart from an attribute\n * holding a real value.\n */\nexport interface SelectedElement {\n getAttribute(name: string): string | true | undefined;\n setAttribute(name: string, value: string): void;\n removeAttribute(name: string): void;\n}\n\nexport type SelectionHandler = (element: SelectedElement) => void;\n\ninterface Selection {\n match: CompiledSelector;\n handler: SelectionHandler;\n}\n\n/**\n * An HTML-in, HTML-out transform stream that rewrites attributes on elements\n * matching a CSS selector.\n *\n * Anything the selectors don't match passes through byte-for-byte; a matched\n * start tag is re-serialized, so its internal whitespace collapses and a\n * self-closing `/` is dropped. That asymmetry is deliberate — it reproduces the\n * observable behavior of `@gofunky/trumpet`, which this replaced.\n *\n * Selectors are evaluated against each start tag on its own, so combinators\n * (descendant, child, sibling) will not match. Every selector this package\n * ships, and every selector its tests exercise, is element-local: a tag name\n * plus attribute predicates, optionally negated with `:not()`.\n */\nexport class HtmlRewriteStream extends RewritingStream {\n readonly #selections: Selection[] = [];\n readonly #decoder = new StringDecoder(\"utf8\");\n\n constructor() {\n super();\n\n this.on(\"startTag\", (token, raw) => {\n let dirty = false;\n\n const element: SelectedElement = {\n getAttribute(name) {\n const attr = token.attrs.find((a) => a.name === name);\n if (attr == null) {\n return undefined;\n }\n return attr.value === \"\" ? true : attr.value;\n },\n setAttribute(name, value) {\n const attr = token.attrs.find((a) => a.name === name);\n if (attr) {\n attr.value = value;\n } else {\n token.attrs.push({ name, value });\n }\n dirty = true;\n },\n removeAttribute(name) {\n const before = token.attrs.length;\n token.attrs = token.attrs.filter((a) => a.name !== name);\n if (token.attrs.length !== before) {\n dirty = true;\n }\n },\n };\n\n // css-select needs a domhandler node. Building a throwaway one per start\n // tag keeps this independent of any parse tree.\n const node = new Element(\n token.tagName,\n Object.fromEntries(token.attrs.map((a) => [a.name, a.value])),\n );\n\n for (const { match, handler } of this.#selections) {\n if (match(node)) handler(element);\n }\n\n if (dirty) {\n // trumpet emitted `<img>` for `<img />`; parse5 would keep the marker.\n token.selfClosing = false;\n this.emitStartTag(token);\n } else {\n // Untouched tags go out exactly as they came in, quirks and all.\n this.emitRaw(raw);\n }\n });\n }\n\n /**\n * Register a handler to run against every element matching `selector`.\n * Must be called before any data is written to the stream.\n */\n selectAll(selector: string, handler: SelectionHandler): void {\n this.#selections.push({ match: compile(selector), handler });\n }\n\n /**\n * parse5's parser accepts only strings, but callers pipe Buffers in. Decode\n * through a StringDecoder rather than `chunk.toString()`, so a multi-byte\n * character split across two chunks survives the boundary.\n */\n override _transform(\n chunk: string | Buffer,\n encoding: string,\n callback: (error?: Error | null, data?: string) => void,\n ): void {\n const text = typeof chunk === \"string\" ? chunk : this.#decoder.write(chunk);\n super._transform(text, encoding, callback);\n }\n\n override _final(\n callback: (error?: Error | null, data?: string) => void,\n ): void {\n // Anything the decoder is still holding is an incomplete sequence at end\n // of input; `end()` turns it into replacement characters. Push it through\n // the parser before finishing rather than dropping it.\n const rest = this.#decoder.end();\n if (rest !== \"\") this.push(this._transformChunk(rest));\n super._final(callback);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA8CA,IAAa,oBAAb,cAAuC,gBAAgB;CACrD,AAASA,cAA2B,CAAC;CACrC,AAASC,WAAW,IAAI,cAAc,MAAM;CAE5C,cAAc;EACZ,MAAM;EAEN,KAAK,GAAG,aAAa,OAAO,QAAQ;GAClC,IAAI,QAAQ;GAEZ,MAAM,UAA2B;IAC/B,aAAa,MAAM;KACjB,MAAM,OAAO,MAAM,MAAM,MAAM,MAAM,EAAE,SAAS,IAAI;KACpD,IAAI,QAAQ,MACV;KAEF,OAAO,KAAK,UAAU,KAAK,OAAO,KAAK;IACzC;IACA,aAAa,MAAM,OAAO;KACxB,MAAM,OAAO,MAAM,MAAM,MAAM,MAAM,EAAE,SAAS,IAAI;KACpD,IAAI,MACF,KAAK,QAAQ;UAEb,MAAM,MAAM,KAAK;MAAE;MAAM;KAAM,CAAC;KAElC,QAAQ;IACV;IACA,gBAAgB,MAAM;KACpB,MAAM,SAAS,MAAM,MAAM;KAC3B,MAAM,QAAQ,MAAM,MAAM,QAAQ,MAAM,EAAE,SAAS,IAAI;KACvD,IAAI,MAAM,MAAM,WAAW,QACzB,QAAQ;IAEZ;GACF;GAIA,MAAM,OAAO,IAAI,QACf,MAAM,SACN,OAAO,YAAY,MAAM,MAAM,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAC9D;GAEA,KAAK,MAAM,EAAE,OAAO,aAAa,KAAKD,aACpC,IAAI,MAAM,IAAI,GAAG,QAAQ,OAAO;GAGlC,IAAI,OAAO;IAET,MAAM,cAAc;IACpB,KAAK,aAAa,KAAK;GACzB,OAEE,KAAK,QAAQ,GAAG;EAEpB,CAAC;CACH;;;;;CAMA,UAAU,UAAkB,SAAiC;EAC3D,KAAKA,YAAY,KAAK;GAAE,OAAO,QAAQ,QAAQ;GAAG;EAAQ,CAAC;CAC7D;;;;;;CAOA,AAAS,WACP,OACA,UACA,UACM;EACN,MAAM,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAKC,SAAS,MAAM,KAAK;EAC1E,MAAM,WAAW,MAAM,UAAU,QAAQ;CAC3C;CAEA,AAAS,OACP,UACM;EAIN,MAAM,OAAO,KAAKA,SAAS,IAAI;EAC/B,IAAI,SAAS,IAAI,KAAK,KAAK,KAAK,gBAAgB,IAAI,CAAC;EACrD,MAAM,OAAO,QAAQ;CACvB;AACF"}
1
+ {"version":3,"file":"HtmlRewriteStream.js","names":[],"sources":["../src/HtmlRewriteStream.ts"],"sourcesContent":["import { RewritingStream } from \"parse5-html-rewriting-stream\";\nimport { Element } from \"domhandler\";\nimport { compile } from \"css-select\";\nimport { StringDecoder } from \"node:string_decoder\";\nimport type { Element as DomElement } from \"domhandler\";\n\n/**\n * css-select's own `CompiledQuery` isn't re-exported from its entry point, but\n * it is structurally just a predicate over a node.\n */\ntype CompiledSelector = (node: DomElement) => boolean;\n\n/**\n * The subset of a DOM element that transforms are allowed to touch.\n *\n * `getAttribute` reports a valueless attribute (`<img data-cdn-ignore>`) as\n * `true` rather than `\"\"`, so callers can tell it apart from an attribute\n * holding a real value.\n */\nexport interface SelectedElement {\n getAttribute(name: string): string | true | undefined;\n setAttribute(name: string, value: string): void;\n removeAttribute(name: string): void;\n}\n\nexport type SelectionHandler = (element: SelectedElement) => void;\n\ninterface Selection {\n match: CompiledSelector;\n handler: SelectionHandler;\n}\n\n/**\n * An HTML-in, HTML-out transform stream that rewrites attributes on elements\n * matching a CSS selector.\n *\n * Anything the selectors don't match passes through byte-for-byte; a matched\n * start tag is re-serialized, so its internal whitespace collapses and a\n * self-closing `/` is dropped. That asymmetry is deliberate — it reproduces the\n * observable behavior of `@gofunky/trumpet`, which this replaced.\n *\n * Selectors are evaluated against each start tag on its own, so combinators\n * (descendant, child, sibling) will not match. Every selector this package\n * ships, and every selector its tests exercise, is element-local: a tag name\n * plus attribute predicates, optionally negated with `:not()`.\n */\nexport class HtmlRewriteStream extends RewritingStream {\n readonly #selections: Selection[] = [];\n readonly #decoder = new StringDecoder(\"utf8\");\n\n constructor() {\n super();\n\n this.on(\"startTag\", (token, raw) => {\n let dirty = false;\n\n const element: SelectedElement = {\n getAttribute(name) {\n const attr = token.attrs.find((a) => a.name === name);\n if (attr == null) {\n return undefined;\n }\n return attr.value === \"\" ? true : attr.value;\n },\n setAttribute(name, value) {\n const attr = token.attrs.find((a) => a.name === name);\n if (attr) {\n attr.value = value;\n } else {\n token.attrs.push({ name, value });\n }\n dirty = true;\n },\n removeAttribute(name) {\n const before = token.attrs.length;\n token.attrs = token.attrs.filter((a) => a.name !== name);\n if (token.attrs.length !== before) {\n dirty = true;\n }\n },\n };\n\n // css-select needs a domhandler node. Building a throwaway one per start\n // tag keeps this independent of any parse tree.\n const node = new Element(\n token.tagName,\n Object.fromEntries(token.attrs.map((a) => [a.name, a.value])),\n );\n\n for (const { match, handler } of this.#selections) {\n if (match(node)) handler(element);\n }\n\n if (dirty) {\n // trumpet emitted `<img>` for `<img />`; parse5 would keep the marker.\n token.selfClosing = false;\n this.emitStartTag(token);\n } else {\n // Untouched tags go out exactly as they came in, quirks and all.\n this.emitRaw(raw);\n }\n });\n }\n\n /**\n * Register a handler to run against every element matching `selector`.\n * Must be called before any data is written to the stream.\n */\n selectAll(selector: string, handler: SelectionHandler): void {\n this.#selections.push({ match: compile(selector), handler });\n }\n\n /**\n * parse5's parser accepts only strings, but callers pipe Buffers in. Decode\n * through a StringDecoder rather than `chunk.toString()`, so a multi-byte\n * character split across two chunks survives the boundary.\n */\n override _transform(\n chunk: string | Buffer,\n encoding: string,\n callback: (error?: Error | null, data?: string) => void,\n ): void {\n const text = typeof chunk === \"string\" ? chunk : this.#decoder.write(chunk);\n super._transform(text, encoding, callback);\n }\n\n override _final(\n callback: (error?: Error | null, data?: string) => void,\n ): void {\n // Anything the decoder is still holding is an incomplete sequence at end\n // of input; `end()` turns it into replacement characters. Push it through\n // the parser before finishing rather than dropping it.\n const rest = this.#decoder.end();\n if (rest !== \"\") this.push(this._transformChunk(rest));\n super._final(callback);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA8CA,IAAa,oBAAb,cAAuC,gBAAgB;CACrD,AAAS,cAA2B,CAAC;CACrC,AAAS,WAAW,IAAI,cAAc,MAAM;CAE5C,cAAc;EACZ,MAAM;EAEN,KAAK,GAAG,aAAa,OAAO,QAAQ;GAClC,IAAI,QAAQ;GAEZ,MAAM,UAA2B;IAC/B,aAAa,MAAM;KACjB,MAAM,OAAO,MAAM,MAAM,MAAM,MAAM,EAAE,SAAS,IAAI;KACpD,IAAI,QAAQ,MACV;KAEF,OAAO,KAAK,UAAU,KAAK,OAAO,KAAK;IACzC;IACA,aAAa,MAAM,OAAO;KACxB,MAAM,OAAO,MAAM,MAAM,MAAM,MAAM,EAAE,SAAS,IAAI;KACpD,IAAI,MACF,KAAK,QAAQ;UAEb,MAAM,MAAM,KAAK;MAAE;MAAM;KAAM,CAAC;KAElC,QAAQ;IACV;IACA,gBAAgB,MAAM;KACpB,MAAM,SAAS,MAAM,MAAM;KAC3B,MAAM,QAAQ,MAAM,MAAM,QAAQ,MAAM,EAAE,SAAS,IAAI;KACvD,IAAI,MAAM,MAAM,WAAW,QACzB,QAAQ;IAEZ;GACF;GAIA,MAAM,OAAO,IAAI,QACf,MAAM,SACN,OAAO,YAAY,MAAM,MAAM,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAC9D;GAEA,KAAK,MAAM,EAAE,OAAO,aAAa,KAAK,aACpC,IAAI,MAAM,IAAI,GAAG,QAAQ,OAAO;GAGlC,IAAI,OAAO;IAET,MAAM,cAAc;IACpB,KAAK,aAAa,KAAK;GACzB,OAEE,KAAK,QAAQ,GAAG;EAEpB,CAAC;CACH;;;;;CAMA,UAAU,UAAkB,SAAiC;EAC3D,KAAK,YAAY,KAAK;GAAE,OAAO,QAAQ,QAAQ;GAAG;EAAQ,CAAC;CAC7D;;;;;;CAOA,AAAS,WACP,OACA,UACA,UACM;EACN,MAAM,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAK,SAAS,MAAM,KAAK;EAC1E,MAAM,WAAW,MAAM,UAAU,QAAQ;CAC3C;CAEA,AAAS,OACP,UACM;EAIN,MAAM,OAAO,KAAK,SAAS,IAAI;EAC/B,IAAI,SAAS,IAAI,KAAK,KAAK,KAAK,gBAAgB,IAAI,CAAC;EACrD,MAAM,OAAO,QAAQ;CACvB;AACF"}
@@ -1,6 +1,5 @@
1
1
  import { HtmlRewriteStream, SelectedElement, SelectionHandler } from "./HtmlRewriteStream.js";
2
- //#region src/HtmlTransformer.d.ts
3
- declare class HtmlTransformer {
2
+ export default class HtmlTransformer {
4
3
  private transformStream;
5
4
  /**
6
5
  * Get the underlying transform stream
@@ -11,6 +10,5 @@ declare class HtmlTransformer {
11
10
  */
12
11
  get outputBufferPromise(): Promise<Buffer>;
13
12
  }
14
- //#endregion
15
- export { HtmlRewriteStream, type SelectedElement, type SelectionHandler, HtmlTransformer as default };
13
+ export { HtmlRewriteStream, type SelectedElement, type SelectionHandler };
16
14
  //# sourceMappingURL=HtmlTransformer.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import { HtmlRewriteStream } from "./HtmlRewriteStream.js";
2
2
  import { buffer } from "node:stream/consumers";
3
3
 
4
- //#region src/HtmlTransformer.ts
4
+ // src/HtmlTransformer.ts
5
5
  var HtmlTransformer = class {
6
6
  transformStream = new HtmlRewriteStream();
7
7
  /**
@@ -18,6 +18,5 @@ var HtmlTransformer = class {
18
18
  }
19
19
  };
20
20
 
21
- //#endregion
22
21
  export { HtmlRewriteStream, HtmlTransformer as default };
23
22
  //# sourceMappingURL=HtmlTransformer.js.map
package/dist/cdnify.d.ts CHANGED
@@ -1,12 +1,10 @@
1
1
  import { CDNTransformerOptions } from "./CDNTransformer.js";
2
- //#region src/cdnify.d.ts
3
- interface CdnifyOptions extends CDNTransformerOptions {
2
+ export interface CdnifyOptions extends CDNTransformerOptions {
4
3
  buffer: string | Buffer;
5
4
  }
6
5
  /**
7
6
  * Alternative wrapper for simple Promise-based use of library (as opposed to transform stream)
8
7
  */
9
- declare function cdnify(options: CdnifyOptions): Promise<Buffer>;
10
- //#endregion
11
- export { CdnifyOptions, cdnify, cdnify as default };
8
+ export declare function cdnify(options: CdnifyOptions): Promise<Buffer>;
9
+ export { cdnify as default };
12
10
  //# sourceMappingURL=cdnify.d.ts.map
package/dist/cdnify.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { CDNTransformer } from "./CDNTransformer.js";
2
2
  import streamifier from "streamifier";
3
3
 
4
- //#region src/cdnify.ts
4
+ // src/cdnify.ts
5
5
  /**
6
6
  * Alternative wrapper for simple Promise-based use of library (as opposed to transform stream)
7
7
  */
@@ -12,6 +12,5 @@ function cdnify(options) {
12
12
  return cdnTransformer.outputBufferPromise;
13
13
  }
14
14
 
15
- //#endregion
16
15
  export { cdnify, cdnify as default };
17
16
  //# sourceMappingURL=cdnify.js.map
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { CDNTransformFunction, CDNTransformer, CDNTransformerOptions } from "./CDNTransformer.js";
2
1
  import { CdnifyOptions, cdnify } from "./cdnify.js";
2
+ import { CDNTransformFunction, CDNTransformer, CDNTransformerOptions } from "./CDNTransformer.js";
3
3
  export { CDNTransformFunction, CDNTransformer, CDNTransformerOptions, CdnifyOptions, cdnify };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { CDNTransformer } from "./CDNTransformer.js";
2
1
  import { cdnify } from "./cdnify.js";
2
+ import { CDNTransformer } from "./CDNTransformer.js";
3
3
 
4
4
  export { CDNTransformer, cdnify };
@@ -1,8 +1,6 @@
1
- //#region src/urlConverter.d.ts
2
1
  /**
3
2
  * Resolve oldUrl against pathOldUrlIsRelativeTo, and then prepend newUrlBase
4
3
  */
5
4
  declare const _default: (newUrlBase: string, oldUrl: string, pathOldUrlIsRelativeTo?: string) => string;
6
- //#endregion
7
5
  export { _default as default };
8
6
  //# sourceMappingURL=urlConverter.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import path from "node:path";
2
2
 
3
- //#region src/urlConverter.ts
3
+ // src/urlConverter.ts
4
4
  /** Origin used to resolve path-only bases, which `new URL()` can't parse. */
5
5
  const PLACEHOLDER_ORIGIN = "http://html-cdnify.invalid";
6
6
  const SCHEME_PATTERN = /^[a-z][a-z0-9+\-.]*:/i;
@@ -34,7 +34,7 @@ var urlConverter_default = (newUrlBase, oldUrl, pathOldUrlIsRelativeTo) => {
34
34
  if (!isLocalPath(oldUrl)) return oldUrl;
35
35
  else {
36
36
  oldUrl = oldUrl.trim();
37
- let relativePath = ".";
37
+ let relativePath;
38
38
  if (pathOldUrlIsRelativeTo) relativePath = resolveUrl(pathOldUrlIsRelativeTo.endsWith("/") ? pathOldUrlIsRelativeTo : path.dirname(pathOldUrlIsRelativeTo) + "/", oldUrl);
39
39
  else relativePath = oldUrl;
40
40
  if (relativePath.startsWith("/")) relativePath = relativePath.slice(1);
@@ -43,6 +43,5 @@ var urlConverter_default = (newUrlBase, oldUrl, pathOldUrlIsRelativeTo) => {
43
43
  }
44
44
  };
45
45
 
46
- //#endregion
47
46
  export { urlConverter_default as default };
48
47
  //# sourceMappingURL=urlConverter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"urlConverter.js","names":[],"sources":["../src/urlConverter.ts"],"sourcesContent":["import path from \"node:path\";\n\n/** Origin used to resolve path-only bases, which `new URL()` can't parse. */\nconst PLACEHOLDER_ORIGIN = \"http://html-cdnify.invalid\";\n\nconst SCHEME_PATTERN = /^[a-z][a-z0-9+\\-.]*:/i;\n\nfunction isLocalPath(filePath: string): boolean {\n return (\n typeof filePath === \"string\" &&\n filePath.length > 0 &&\n filePath.indexOf(\"//\") === -1 &&\n filePath.indexOf(\"data:\") !== 0\n );\n}\n\n/**\n * Resolve `relativeUrl` against `base`, the way the (deprecated) legacy\n * `url.resolve` did, but using the WHATWG URL API.\n *\n * `new URL()` only accepts a fully absolute base, so the two other base shapes\n * this package supports are resolved against a stand-in that is stripped back\n * off afterwards:\n *\n * - protocol-relative (`//cdn.com/cdn/`) borrows a protocol\n * - path-only (`someDir/`) borrows a whole origin\n */\nfunction resolveUrl(base: string, relativeUrl: string): string {\n if (base.startsWith(\"//\")) {\n return new URL(relativeUrl, `http:${base}`).href.slice(\"http:\".length);\n } else if (SCHEME_PATTERN.test(base)) {\n return new URL(relativeUrl, base).href;\n } else {\n const absoluteBase = new URL(base, PLACEHOLDER_ORIGIN);\n const resolved = new URL(relativeUrl, absoluteBase).href.slice(\n PLACEHOLDER_ORIGIN.length,\n );\n // The placeholder origin makes everything look rooted at `/`. Only keep\n // that slash if it was already there before resolving.\n const isRooted = base.startsWith(\"/\") || relativeUrl.startsWith(\"/\");\n return isRooted ? resolved : resolved.slice(1);\n }\n}\n\n/**\n * Resolve oldUrl against pathOldUrlIsRelativeTo, and then prepend newUrlBase\n */\nexport default (\n newUrlBase: string,\n oldUrl: string,\n pathOldUrlIsRelativeTo?: string,\n): string => {\n if (!isLocalPath(oldUrl)) {\n return oldUrl;\n } else {\n oldUrl = oldUrl.trim();\n let relativePath = \".\";\n\n if (pathOldUrlIsRelativeTo) {\n const isDirAlready = pathOldUrlIsRelativeTo.endsWith(\"/\");\n const fileDirName = isDirAlready\n ? pathOldUrlIsRelativeTo\n : path.dirname(pathOldUrlIsRelativeTo) + \"/\";\n relativePath = resolveUrl(fileDirName, oldUrl);\n } else {\n relativePath = oldUrl;\n }\n\n // When resolving against the CDN URL, we should always use a relative URL.\n //\n // e.g. http://somecdn.com/cdn/ + /article/some.css => http://somecdn.com/cdn/article/some.css\n // and *NOT*\n // http://somecdn.com/cdn/ + /article/some.css => http://somecdn.com/article/some.css\n //\n if (relativePath.startsWith(\"/\")) {\n relativePath = relativePath.slice(1);\n }\n\n if (!newUrlBase.endsWith(\"/\")) {\n newUrlBase += \"/\";\n }\n\n return resolveUrl(newUrlBase, relativePath);\n }\n};\n"],"mappings":";;;;AAGA,MAAM,qBAAqB;AAE3B,MAAM,iBAAiB;AAEvB,SAAS,YAAY,UAA2B;CAC9C,OACE,OAAO,aAAa,YACpB,SAAS,SAAS,KAClB,SAAS,QAAQ,IAAI,MAAM,MAC3B,SAAS,QAAQ,OAAO,MAAM;AAElC;;;;;;;;;;;;AAaA,SAAS,WAAW,MAAc,aAA6B;CAC7D,IAAI,KAAK,WAAW,IAAI,GACtB,OAAO,IAAI,IAAI,aAAa,QAAQ,MAAM,CAAC,CAAC,KAAK,MAAM,CAAc;MAChE,IAAI,eAAe,KAAK,IAAI,GACjC,OAAO,IAAI,IAAI,aAAa,IAAI,CAAC,CAAC;MAC7B;EACL,MAAM,eAAe,IAAI,IAAI,MAAM,kBAAkB;EACrD,MAAM,WAAW,IAAI,IAAI,aAAa,YAAY,CAAC,CAAC,KAAK,MACvD,EACF;EAIA,OADiB,KAAK,WAAW,GAAG,KAAK,YAAY,WAAW,GAAG,IACjD,WAAW,SAAS,MAAM,CAAC;CAC/C;AACF;;;;AAKA,4BACE,YACA,QACA,2BACW;CACX,IAAI,CAAC,YAAY,MAAM,GACrB,OAAO;MACF;EACL,SAAS,OAAO,KAAK;EACrB,IAAI,eAAe;EAEnB,IAAI,wBAKF,eAAe,WAJM,uBAAuB,SAAS,GACtB,IAC3B,yBACA,KAAK,QAAQ,sBAAsB,IAAI,KACJ,MAAM;OAE7C,eAAe;EASjB,IAAI,aAAa,WAAW,GAAG,GAC7B,eAAe,aAAa,MAAM,CAAC;EAGrC,IAAI,CAAC,WAAW,SAAS,GAAG,GAC1B,cAAc;EAGhB,OAAO,WAAW,YAAY,YAAY;CAC5C;AACF"}
1
+ {"version":3,"file":"urlConverter.js","names":[],"sources":["../src/urlConverter.ts"],"sourcesContent":["import path from \"node:path\";\n\n/** Origin used to resolve path-only bases, which `new URL()` can't parse. */\nconst PLACEHOLDER_ORIGIN = \"http://html-cdnify.invalid\";\n\nconst SCHEME_PATTERN = /^[a-z][a-z0-9+\\-.]*:/i;\n\nfunction isLocalPath(filePath: string): boolean {\n return (\n typeof filePath === \"string\" &&\n filePath.length > 0 &&\n filePath.indexOf(\"//\") === -1 &&\n filePath.indexOf(\"data:\") !== 0\n );\n}\n\n/**\n * Resolve `relativeUrl` against `base`, the way the (deprecated) legacy\n * `url.resolve` did, but using the WHATWG URL API.\n *\n * `new URL()` only accepts a fully absolute base, so the two other base shapes\n * this package supports are resolved against a stand-in that is stripped back\n * off afterwards:\n *\n * - protocol-relative (`//cdn.com/cdn/`) borrows a protocol\n * - path-only (`someDir/`) borrows a whole origin\n */\nfunction resolveUrl(base: string, relativeUrl: string): string {\n if (base.startsWith(\"//\")) {\n return new URL(relativeUrl, `http:${base}`).href.slice(\"http:\".length);\n } else if (SCHEME_PATTERN.test(base)) {\n return new URL(relativeUrl, base).href;\n } else {\n const absoluteBase = new URL(base, PLACEHOLDER_ORIGIN);\n const resolved = new URL(relativeUrl, absoluteBase).href.slice(\n PLACEHOLDER_ORIGIN.length,\n );\n // The placeholder origin makes everything look rooted at `/`. Only keep\n // that slash if it was already there before resolving.\n const isRooted = base.startsWith(\"/\") || relativeUrl.startsWith(\"/\");\n return isRooted ? resolved : resolved.slice(1);\n }\n}\n\n/**\n * Resolve oldUrl against pathOldUrlIsRelativeTo, and then prepend newUrlBase\n */\nexport default (\n newUrlBase: string,\n oldUrl: string,\n pathOldUrlIsRelativeTo?: string,\n): string => {\n if (!isLocalPath(oldUrl)) {\n return oldUrl;\n } else {\n oldUrl = oldUrl.trim();\n let relativePath: string;\n\n if (pathOldUrlIsRelativeTo) {\n const isDirAlready = pathOldUrlIsRelativeTo.endsWith(\"/\");\n const fileDirName = isDirAlready\n ? pathOldUrlIsRelativeTo\n : path.dirname(pathOldUrlIsRelativeTo) + \"/\";\n relativePath = resolveUrl(fileDirName, oldUrl);\n } else {\n relativePath = oldUrl;\n }\n\n // When resolving against the CDN URL, we should always use a relative URL.\n //\n // e.g. http://somecdn.com/cdn/ + /article/some.css => http://somecdn.com/cdn/article/some.css\n // and *NOT*\n // http://somecdn.com/cdn/ + /article/some.css => http://somecdn.com/article/some.css\n //\n if (relativePath.startsWith(\"/\")) {\n relativePath = relativePath.slice(1);\n }\n\n if (!newUrlBase.endsWith(\"/\")) {\n newUrlBase += \"/\";\n }\n\n return resolveUrl(newUrlBase, relativePath);\n }\n};\n"],"mappings":";;;;AAGA,MAAM,qBAAqB;AAE3B,MAAM,iBAAiB;AAEvB,SAAS,YAAY,UAA2B;CAC9C,OACE,OAAO,aAAa,YACpB,SAAS,SAAS,KAClB,SAAS,QAAQ,IAAI,MAAM,MAC3B,SAAS,QAAQ,OAAO,MAAM;AAElC;;;;;;;;;;;;AAaA,SAAS,WAAW,MAAc,aAA6B;CAC7D,IAAI,KAAK,WAAW,IAAI,GACtB,OAAO,IAAI,IAAI,aAAa,QAAQ,MAAM,CAAC,CAAC,KAAK,MAAM,CAAc;MAChE,IAAI,eAAe,KAAK,IAAI,GACjC,OAAO,IAAI,IAAI,aAAa,IAAI,CAAC,CAAC;MAC7B;EACL,MAAM,eAAe,IAAI,IAAI,MAAM,kBAAkB;EACrD,MAAM,WAAW,IAAI,IAAI,aAAa,YAAY,CAAC,CAAC,KAAK,MACvD,EACF;EAIA,OADiB,KAAK,WAAW,GAAG,KAAK,YAAY,WAAW,GAAG,IACjD,WAAW,SAAS,MAAM,CAAC;CAC/C;AACF;;;;AAKA,4BACE,YACA,QACA,2BACW;CACX,IAAI,CAAC,YAAY,MAAM,GACrB,OAAO;MACF;EACL,SAAS,OAAO,KAAK;EACrB,IAAI;EAEJ,IAAI,wBAKF,eAAe,WAJM,uBAAuB,SAAS,GACtB,IAC3B,yBACA,KAAK,QAAQ,sBAAsB,IAAI,KACJ,MAAM;OAE7C,eAAe;EASjB,IAAI,aAAa,WAAW,GAAG,GAC7B,eAAe,aAAa,MAAM,CAAC;EAGrC,IAAI,CAAC,WAAW,SAAS,GAAG,GAC1B,cAAc;EAGhB,OAAO,WAAW,YAAY,YAAY;CAC5C;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@altano/html-cdnify",
3
- "version": "6.0.0",
3
+ "version": "6.0.2",
4
4
  "description": "Transform the relative URLs in your HTML markup (e.g. scripts, stylesheets, images) to use your CDN URL.",
5
5
  "keywords": [
6
6
  "cdn",
@@ -34,22 +34,22 @@
34
34
  "css-select": "^7.0.0",
35
35
  "domhandler": "^6.0.1",
36
36
  "lodash-es": "^4.18.1",
37
- "parse5-html-rewriting-stream": "^8.0.1",
37
+ "parse5-html-rewriting-stream": "^8.1.0",
38
38
  "streamifier": "^0.1.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@arethetypeswrong/cli": "^0.18.5",
42
42
  "@types/lodash-es": "^4.17.12",
43
- "@types/node": "^26.1.1",
43
+ "@types/node": "^26.6.6",
44
44
  "@types/streamifier": "^0.1.2",
45
- "@vitest/coverage-v8": "^4.1.10",
45
+ "@vitest/coverage-v8": "^5.1.0",
46
46
  "depcheck": "^1.4.7",
47
- "eslint": "^9.39.5",
48
- "prettier": "3.9.6",
49
- "tsdown": "^0.22.14",
47
+ "eslint": "^10.14.0",
48
+ "prettier": "3.9.10",
49
+ "tsdown": "^0.23.5",
50
50
  "typescript": "^6.0.3",
51
- "vite": "^8.1.5",
52
- "vitest": "^4.1.10",
51
+ "vite": "^8.3.5",
52
+ "vitest": "^5.1.0",
53
53
  "@altano/build-config": "0.0.1",
54
54
  "@altano/testing": "0.0.1",
55
55
  "@altano/tsconfig": "0.0.1"