@altano/html-cdnify 4.0.2 → 5.0.0
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.
- package/dist/CDNTransformer.d.ts +5 -6
- package/dist/CDNTransformer.js.map +1 -1
- package/dist/HtmlAttributeStreamTransformer.d.ts +6 -7
- package/dist/HtmlAttributeStreamTransformer.js +1 -0
- package/dist/HtmlAttributeStreamTransformer.js.map +1 -1
- package/dist/HtmlTransformer.d.ts +4 -5
- package/dist/HtmlTransformer.js.map +1 -1
- package/dist/cdnify.d.ts +2 -3
- package/dist/cdnify.js.map +1 -1
- package/dist/urlConverter.d.ts +2 -2
- package/dist/urlConverter.js +26 -6
- package/dist/urlConverter.js.map +1 -1
- package/package.json +16 -16
package/dist/CDNTransformer.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { HtmlAttributeStreamTransformer, TransformDefinition } from "./HtmlAttributeStreamTransformer.js";
|
|
2
|
-
|
|
3
2
|
//#region src/CDNTransformer.d.ts
|
|
4
3
|
type CDNTransformFunction = (cdnUrl: string, oldUrl: string, bufferPath: string) => string;
|
|
5
4
|
interface CDNTransformerOptions {
|
|
@@ -9,11 +8,11 @@ interface CDNTransformerOptions {
|
|
|
9
8
|
transformFunction?: CDNTransformFunction;
|
|
10
9
|
}
|
|
11
10
|
/**
|
|
12
|
-
* Wraps a node-trumpet Transform stream, w/ HTML as input and
|
|
13
|
-
* HTML as output. The output will have all non-absolute-URL
|
|
14
|
-
* attributes that identify CDN-able resources converted to
|
|
15
|
-
* use the given CDN URL.
|
|
16
|
-
*/
|
|
11
|
+
* Wraps a node-trumpet Transform stream, w/ HTML as input and
|
|
12
|
+
* HTML as output. The output will have all non-absolute-URL
|
|
13
|
+
* attributes that identify CDN-able resources converted to
|
|
14
|
+
* use the given CDN URL.
|
|
15
|
+
*/
|
|
17
16
|
declare class CDNTransformer extends HtmlAttributeStreamTransformer {
|
|
18
17
|
#private;
|
|
19
18
|
cdnOptions: Required<CDNTransformerOptions>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CDNTransformer.js","names":["HtmlAttributeStreamTransformer.HtmlAttributeStreamTransformer","#defaultHtmlAttributeStreamTransformerOptions","#cdnifyAttribute","#defaultCdnOptions","urlConverter"],"sources":["../src/CDNTransformer.ts"],"sourcesContent":["import { unionBy, merge, mergeWith, type MergeWithCustomizer } from \"lodash\";\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: MergeWithCustomizer = (objValue, srcValue) => {\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 a node-trumpet Transform stream, 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;
|
|
1
|
+
{"version":3,"file":"CDNTransformer.js","names":["HtmlAttributeStreamTransformer.HtmlAttributeStreamTransformer","#defaultHtmlAttributeStreamTransformerOptions","#cdnifyAttribute","#defaultCdnOptions","urlConverter"],"sources":["../src/CDNTransformer.ts"],"sourcesContent":["import { unionBy, merge, mergeWith, type MergeWithCustomizer } from \"lodash\";\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: MergeWithCustomizer = (objValue, srcValue) => {\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 a node-trumpet Transform stream, 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,mBAAwC,UAAU,aAAa;EACpE,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,5 +1,4 @@
|
|
|
1
1
|
import HtmlTransformer from "./HtmlTransformer.js";
|
|
2
|
-
|
|
3
2
|
//#region src/HtmlAttributeStreamTransformer.d.ts
|
|
4
3
|
interface HtmlAttributeStreamTransformerOptions {
|
|
5
4
|
transformDefinitions: TransformDefinition[];
|
|
@@ -19,14 +18,14 @@ interface AttributeParsers {
|
|
|
19
18
|
[index: string]: AttributeParser;
|
|
20
19
|
}
|
|
21
20
|
/**
|
|
22
|
-
* Wraps a node-trumpet Transform stream, w/ HTML as input and
|
|
23
|
-
* HTML as output. The output will have all non-absolute-URL
|
|
24
|
-
* attributes that identify CDN-able resources converted to
|
|
25
|
-
* use the given CDN URL.
|
|
26
|
-
*/
|
|
21
|
+
* Wraps a node-trumpet Transform stream, w/ HTML as input and
|
|
22
|
+
* HTML as output. The output will have all non-absolute-URL
|
|
23
|
+
* attributes that identify CDN-able resources converted to
|
|
24
|
+
* use the given CDN URL.
|
|
25
|
+
*/
|
|
27
26
|
declare class HtmlAttributeStreamTransformer extends HtmlTransformer {
|
|
28
|
-
options: HtmlAttributeStreamTransformerOptions;
|
|
29
27
|
condensedTransformOptions: TransformDefinition[];
|
|
28
|
+
options: HtmlAttributeStreamTransformerOptions;
|
|
30
29
|
constructor(options: HtmlAttributeStreamTransformerOptions);
|
|
31
30
|
static attributeParsers: AttributeParsers;
|
|
32
31
|
protected applyTransforms(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HtmlAttributeStreamTransformer.js","names":[],"sources":["../src/HtmlAttributeStreamTransformer.ts"],"sourcesContent":["import { groupBy } from \"lodash\";\nimport HtmlTransformer from \"./HtmlTransformer.js\";\n\nexport interface HtmlAttributeStreamTransformerOptions {\n transformDefinitions: TransformDefinition[];\n transformFunction: TransformFunction;\n attributeToMarkElementToBeIgnored?: string;\n}\n\nexport interface TransformDefinition {\n selector: string;\n attribute: string;\n attributeParser?:\n | undefined\n | ((oldAttribute: string, transformFunction: TransformFunction) => string);\n}\n\nexport type TransformFunction = (oldAttribute: string) => string;\n\nexport interface AttributeParser {\n (oldAttribute: string, transformFunction: TransformFunction): string;\n}\n\nexport interface AttributeParsers {\n [index: string]: AttributeParser;\n}\n\n/**\n * Wraps a node-trumpet Transform stream, 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 HtmlAttributeStreamTransformer extends HtmlTransformer {\n public condensedTransformOptions: TransformDefinition[] = [];\n\n constructor(
|
|
1
|
+
{"version":3,"file":"HtmlAttributeStreamTransformer.js","names":[],"sources":["../src/HtmlAttributeStreamTransformer.ts"],"sourcesContent":["import { groupBy } from \"lodash\";\nimport HtmlTransformer from \"./HtmlTransformer.js\";\n\nexport interface HtmlAttributeStreamTransformerOptions {\n transformDefinitions: TransformDefinition[];\n transformFunction: TransformFunction;\n attributeToMarkElementToBeIgnored?: string;\n}\n\nexport interface TransformDefinition {\n selector: string;\n attribute: string;\n attributeParser?:\n | undefined\n | ((oldAttribute: string, transformFunction: TransformFunction) => string);\n}\n\nexport type TransformFunction = (oldAttribute: string) => string;\n\nexport interface AttributeParser {\n (oldAttribute: string, transformFunction: TransformFunction): string;\n}\n\nexport interface AttributeParsers {\n [index: string]: AttributeParser;\n}\n\n/**\n * Wraps a node-trumpet Transform stream, 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 HtmlAttributeStreamTransformer extends HtmlTransformer {\n public condensedTransformOptions: TransformDefinition[] = [];\n public options: HtmlAttributeStreamTransformerOptions;\n\n constructor(options: HtmlAttributeStreamTransformerOptions) {\n super();\n\n this.options = options;\n\n this.processTransforms();\n\n this.applyTransforms();\n }\n\n static attributeParsers: AttributeParsers = {\n default: (attr, transformFunction) => transformFunction(attr),\n };\n\n protected applyTransforms(): void {\n this.condensedTransformOptions.forEach((settings) => {\n const selector = settings.selector;\n const attribute = settings.attribute;\n const parser = settings.attributeParser;\n\n this.stream.selectAll(selector, (elem) => {\n const oldAttributeValue = elem.getAttribute(attribute);\n\n // Check that the attribute is set (which should always be the case) and the\n // typeof=string, which will be false in the case of empty attributes (which\n // cause getAttribute() to return the boolean true)\n if (typeof oldAttributeValue === \"string\") {\n const newAttributeValue =\n parser && parser(oldAttributeValue, this.options.transformFunction);\n if (newAttributeValue && newAttributeValue !== oldAttributeValue) {\n elem.setAttribute(attribute, newAttributeValue);\n }\n }\n });\n });\n\n // Run cleanup transform last\n const { attributeToMarkElementToBeIgnored } = this.options;\n if (attributeToMarkElementToBeIgnored) {\n this.stream.selectAll(\n `[${attributeToMarkElementToBeIgnored}]`,\n (elem) => {\n elem.removeAttribute(attributeToMarkElementToBeIgnored);\n },\n );\n }\n }\n\n private processTransforms(): void {\n this.options.transformDefinitions.forEach((option) => {\n if (!option.attributeParser) {\n option.attributeParser =\n HtmlAttributeStreamTransformer.attributeParsers[\"default\"];\n }\n\n if (typeof option.selector !== \"string\") {\n throw new Error(`Invalid selector specified.`);\n }\n\n if (typeof option.attribute !== \"string\") {\n throw new Error(`Invalid attribute specified.`);\n }\n\n if (!(option.attributeParser instanceof Function)) {\n throw new Error(\"Invalid attributeParser specified.\");\n }\n });\n\n /**\n * As a performance enhancement, we can condense the list of transformDefinitions such that\n * selectors with the same attribute and attributeParser can be combined into a single,\n * comma-delimited CSS selector.\n */\n const groupedTransformOptions = groupBy(\n this.options.transformDefinitions,\n (obj) => {\n return [obj.attribute, obj.attributeParser];\n },\n );\n\n this.condensedTransformOptions = Object.values(groupedTransformOptions).map(\n (likeTransformOptions) => {\n const attribute = likeTransformOptions[0]!.attribute;\n const attributeParser = likeTransformOptions[0]!.attributeParser;\n\n return {\n attribute,\n attributeParser,\n selector: likeTransformOptions\n .map((likeTransformOption) => likeTransformOption.selector)\n .join(\", \"),\n };\n },\n );\n }\n}\n"],"mappings":";;;;;;;;;;AAiCA,IAAa,iCAAb,MAAa,uCAAuC,gBAAgB;CAClE,AAAO,4BAAmD,CAAC;CAC3D,AAAO;CAEP,YAAY,SAAgD;EAC1D,MAAM;EAEN,KAAK,UAAU;EAEf,KAAK,kBAAkB;EAEvB,KAAK,gBAAgB;CACvB;CAEA,OAAO,mBAAqC,EAC1C,UAAU,MAAM,sBAAsB,kBAAkB,IAAI,EAC9D;CAEA,AAAU,kBAAwB;EAChC,KAAK,0BAA0B,SAAS,aAAa;GACnD,MAAM,WAAW,SAAS;GAC1B,MAAM,YAAY,SAAS;GAC3B,MAAM,SAAS,SAAS;GAExB,KAAK,OAAO,UAAU,WAAW,SAAS;IACxC,MAAM,oBAAoB,KAAK,aAAa,SAAS;IAKrD,IAAI,OAAO,sBAAsB,UAAU;KACzC,MAAM,oBACJ,UAAU,OAAO,mBAAmB,KAAK,QAAQ,iBAAiB;KACpE,IAAI,qBAAqB,sBAAsB,mBAC7C,KAAK,aAAa,WAAW,iBAAiB;IAElD;GACF,CAAC;EACH,CAAC;EAGD,MAAM,EAAE,sCAAsC,KAAK;EACnD,IAAI,mCACF,KAAK,OAAO,UACV,IAAI,kCAAkC,KACrC,SAAS;GACR,KAAK,gBAAgB,iCAAiC;EACxD,CACF;CAEJ;CAEA,AAAQ,oBAA0B;EAChC,KAAK,QAAQ,qBAAqB,SAAS,WAAW;GACpD,IAAI,CAAC,OAAO,iBACV,OAAO,kBACL,+BAA+B,iBAAiB;GAGpD,IAAI,OAAO,OAAO,aAAa,UAC7B,MAAM,IAAI,MAAM,6BAA6B;GAG/C,IAAI,OAAO,OAAO,cAAc,UAC9B,MAAM,IAAI,MAAM,8BAA8B;GAGhD,IAAI,EAAE,OAAO,2BAA2B,WACtC,MAAM,IAAI,MAAM,oCAAoC;EAExD,CAAC;;;;;;EAOD,MAAM,0BAA0B,QAC9B,KAAK,QAAQ,uBACZ,QAAQ;GACP,OAAO,CAAC,IAAI,WAAW,IAAI,eAAe;EAC5C,CACF;EAEA,KAAK,4BAA4B,OAAO,OAAO,uBAAuB,CAAC,CAAC,KACrE,yBAAyB;GAIxB,OAAO;IACL,WAJgB,qBAAqB,EAAE,CAAE;IAKzC,iBAJsB,qBAAqB,EAAE,CAAE;IAK/C,UAAU,qBACP,KAAK,wBAAwB,oBAAoB,QAAQ,CAAC,CAC1D,KAAK,IAAI;GACd;EACF,CACF;CACF;AACF"}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { Trumpet } from "@gofunky/trumpet";
|
|
2
|
-
|
|
3
2
|
//#region src/HtmlTransformer.d.ts
|
|
4
3
|
type TrumpetTransformStream = Trumpet;
|
|
5
4
|
declare class HtmlTransformer {
|
|
6
5
|
private transformStream;
|
|
7
6
|
constructor();
|
|
8
7
|
/**
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
* Get the underlying transform stream
|
|
9
|
+
*/
|
|
11
10
|
get stream(): Trumpet;
|
|
12
11
|
/**
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
* Get a promise to the complete output Buffer (alternative API to dealing with stream)
|
|
13
|
+
*/
|
|
15
14
|
get outputBufferPromise(): Promise<Buffer>;
|
|
16
15
|
}
|
|
17
16
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HtmlTransformer.js","names":[],"sources":["../src/HtmlTransformer.ts"],"sourcesContent":["import trumpet, { type Trumpet } from \"@gofunky/trumpet\";\nimport streamToPromise from \"stream-to-promise\";\n\nexport type TrumpetTransformStream = Trumpet;\n\nexport default class HtmlTransformer {\n private transformStream: TrumpetTransformStream;\n\n constructor(/*public inputPath: string*/) {\n this.transformStream = trumpet();\n }\n\n /**\n * Get the underlying transform stream\n */\n get stream(): Trumpet {\n return this.transformStream;\n }\n\n /**\n * Get a promise to the complete output Buffer (alternative API to dealing with stream)\n */\n get outputBufferPromise(): Promise<Buffer> {\n return streamToPromise(this.stream);\n }\n}\n"],"mappings":";;;;AAKA,IAAqB,kBAArB,MAAqC;CACnC,AAAQ;CAER,cAA0C;
|
|
1
|
+
{"version":3,"file":"HtmlTransformer.js","names":[],"sources":["../src/HtmlTransformer.ts"],"sourcesContent":["import trumpet, { type Trumpet } from \"@gofunky/trumpet\";\nimport streamToPromise from \"stream-to-promise\";\n\nexport type TrumpetTransformStream = Trumpet;\n\nexport default class HtmlTransformer {\n private transformStream: TrumpetTransformStream;\n\n constructor(/*public inputPath: string*/) {\n this.transformStream = trumpet();\n }\n\n /**\n * Get the underlying transform stream\n */\n get stream(): Trumpet {\n return this.transformStream;\n }\n\n /**\n * Get a promise to the complete output Buffer (alternative API to dealing with stream)\n */\n get outputBufferPromise(): Promise<Buffer> {\n return streamToPromise(this.stream);\n }\n}\n"],"mappings":";;;;AAKA,IAAqB,kBAArB,MAAqC;CACnC,AAAQ;CAER,cAA0C;EACxC,KAAK,kBAAkB,QAAQ;CACjC;;;;CAKA,IAAI,SAAkB;EACpB,OAAO,KAAK;CACd;;;;CAKA,IAAI,sBAAuC;EACzC,OAAO,gBAAgB,KAAK,MAAM;CACpC;AACF"}
|
package/dist/cdnify.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { CDNTransformerOptions } from "./CDNTransformer.js";
|
|
2
|
-
|
|
3
2
|
//#region src/cdnify.d.ts
|
|
4
3
|
interface CdnifyOptions extends CDNTransformerOptions {
|
|
5
4
|
buffer: string | Buffer;
|
|
6
5
|
}
|
|
7
6
|
/**
|
|
8
|
-
* Alternative wrapper for simple Promise-based use of library (as opposed to transform stream)
|
|
9
|
-
*/
|
|
7
|
+
* Alternative wrapper for simple Promise-based use of library (as opposed to transform stream)
|
|
8
|
+
*/
|
|
10
9
|
declare function cdnify(options: CdnifyOptions): Promise<Buffer>;
|
|
11
10
|
//#endregion
|
|
12
11
|
export { CdnifyOptions, cdnify, cdnify as default };
|
package/dist/cdnify.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cdnify.js","names":[],"sources":["../src/cdnify.ts"],"sourcesContent":["import {\n CDNTransformer,\n type CDNTransformerOptions,\n} from \"./CDNTransformer.js\";\n\nimport streamifier from \"streamifier\";\n\nexport interface CdnifyOptions extends CDNTransformerOptions {\n buffer: string | Buffer;\n}\n\n/**\n * Alternative wrapper for simple Promise-based use of library (as opposed to transform stream)\n */\nexport function cdnify(options: CdnifyOptions): Promise<Buffer> {\n if (typeof options.buffer !== \"string\") {\n options.buffer = options.buffer.toString();\n }\n\n const cdnTransformer = new CDNTransformer(options);\n\n streamifier.createReadStream(options.buffer).pipe(cdnTransformer.stream);\n\n return cdnTransformer.outputBufferPromise;\n}\n\nexport default cdnify;\n"],"mappings":";;;;;;;AAcA,SAAgB,OAAO,SAAyC;
|
|
1
|
+
{"version":3,"file":"cdnify.js","names":[],"sources":["../src/cdnify.ts"],"sourcesContent":["import {\n CDNTransformer,\n type CDNTransformerOptions,\n} from \"./CDNTransformer.js\";\n\nimport streamifier from \"streamifier\";\n\nexport interface CdnifyOptions extends CDNTransformerOptions {\n buffer: string | Buffer;\n}\n\n/**\n * Alternative wrapper for simple Promise-based use of library (as opposed to transform stream)\n */\nexport function cdnify(options: CdnifyOptions): Promise<Buffer> {\n if (typeof options.buffer !== \"string\") {\n options.buffer = options.buffer.toString();\n }\n\n const cdnTransformer = new CDNTransformer(options);\n\n streamifier.createReadStream(options.buffer).pipe(cdnTransformer.stream);\n\n return cdnTransformer.outputBufferPromise;\n}\n\nexport default cdnify;\n"],"mappings":";;;;;;;AAcA,SAAgB,OAAO,SAAyC;CAC9D,IAAI,OAAO,QAAQ,WAAW,UAC5B,QAAQ,SAAS,QAAQ,OAAO,SAAS;CAG3C,MAAM,iBAAiB,IAAI,eAAe,OAAO;CAEjD,YAAY,iBAAiB,QAAQ,MAAM,CAAC,CAAC,KAAK,eAAe,MAAM;CAEvE,OAAO,eAAe;AACxB"}
|
package/dist/urlConverter.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/urlConverter.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* Resolve oldUrl against pathOldUrlIsRelativeTo, and then prepend newUrlBase
|
|
4
|
-
*/
|
|
3
|
+
* Resolve oldUrl against pathOldUrlIsRelativeTo, and then prepend newUrlBase
|
|
4
|
+
*/
|
|
5
5
|
declare const _default: (newUrlBase: string, oldUrl: string, pathOldUrlIsRelativeTo?: string) => string;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { _default as default };
|
package/dist/urlConverter.js
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
|
-
import url from "node:url";
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
|
|
4
3
|
//#region src/urlConverter.ts
|
|
4
|
+
/** Origin used to resolve path-only bases, which `new URL()` can't parse. */
|
|
5
|
+
const PLACEHOLDER_ORIGIN = "http://html-cdnify.invalid";
|
|
6
|
+
const SCHEME_PATTERN = /^[a-z][a-z0-9+\-.]*:/i;
|
|
5
7
|
function isLocalPath(filePath) {
|
|
6
8
|
return typeof filePath === "string" && filePath.length > 0 && filePath.indexOf("//") === -1 && filePath.indexOf("data:") !== 0;
|
|
7
9
|
}
|
|
8
10
|
/**
|
|
11
|
+
* Resolve `relativeUrl` against `base`, the way the (deprecated) legacy
|
|
12
|
+
* `url.resolve` did, but using the WHATWG URL API.
|
|
13
|
+
*
|
|
14
|
+
* `new URL()` only accepts a fully absolute base, so the two other base shapes
|
|
15
|
+
* this package supports are resolved against a stand-in that is stripped back
|
|
16
|
+
* off afterwards:
|
|
17
|
+
*
|
|
18
|
+
* - protocol-relative (`//cdn.com/cdn/`) borrows a protocol
|
|
19
|
+
* - path-only (`someDir/`) borrows a whole origin
|
|
20
|
+
*/
|
|
21
|
+
function resolveUrl(base, relativeUrl) {
|
|
22
|
+
if (base.startsWith("//")) return new URL(relativeUrl, `http:${base}`).href.slice(5);
|
|
23
|
+
else if (SCHEME_PATTERN.test(base)) return new URL(relativeUrl, base).href;
|
|
24
|
+
else {
|
|
25
|
+
const absoluteBase = new URL(base, PLACEHOLDER_ORIGIN);
|
|
26
|
+
const resolved = new URL(relativeUrl, absoluteBase).href.slice(26);
|
|
27
|
+
return base.startsWith("/") || relativeUrl.startsWith("/") ? resolved : resolved.slice(1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
9
31
|
* Resolve oldUrl against pathOldUrlIsRelativeTo, and then prepend newUrlBase
|
|
10
32
|
*/
|
|
11
33
|
var urlConverter_default = (newUrlBase, oldUrl, pathOldUrlIsRelativeTo) => {
|
|
@@ -13,13 +35,11 @@ var urlConverter_default = (newUrlBase, oldUrl, pathOldUrlIsRelativeTo) => {
|
|
|
13
35
|
else {
|
|
14
36
|
oldUrl = oldUrl.trim();
|
|
15
37
|
let relativePath = ".";
|
|
16
|
-
if (pathOldUrlIsRelativeTo)
|
|
17
|
-
|
|
18
|
-
relativePath = url.resolve(fileDirName, oldUrl);
|
|
19
|
-
} else relativePath = oldUrl;
|
|
38
|
+
if (pathOldUrlIsRelativeTo) relativePath = resolveUrl(pathOldUrlIsRelativeTo.endsWith("/") ? pathOldUrlIsRelativeTo : path.dirname(pathOldUrlIsRelativeTo) + "/", oldUrl);
|
|
39
|
+
else relativePath = oldUrl;
|
|
20
40
|
if (relativePath.startsWith("/")) relativePath = relativePath.slice(1);
|
|
21
41
|
if (!newUrlBase.endsWith("/")) newUrlBase += "/";
|
|
22
|
-
return
|
|
42
|
+
return resolveUrl(newUrlBase, relativePath);
|
|
23
43
|
}
|
|
24
44
|
};
|
|
25
45
|
|
package/dist/urlConverter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"urlConverter.js","names":[],"sources":["../src/urlConverter.ts"],"sourcesContent":["import
|
|
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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@altano/html-cdnify",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
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",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"license": "ISC",
|
|
18
18
|
"author": {
|
|
19
19
|
"name": "Alan Norbauer",
|
|
20
|
-
"email": "
|
|
20
|
+
"email": "alan@norbauer.com",
|
|
21
21
|
"url": "https://alan.norbauer.com"
|
|
22
22
|
},
|
|
23
23
|
"sideEffects": false,
|
|
@@ -32,24 +32,24 @@
|
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@gofunky/trumpet": "^3.0.3",
|
|
35
|
-
"lodash": "^4.
|
|
35
|
+
"lodash": "^4.18.1",
|
|
36
36
|
"stream-to-promise": "^3.0.0",
|
|
37
37
|
"streamifier": "^0.1.1"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@arethetypeswrong/cli": "^0.18.
|
|
41
|
-
"@types/lodash": "^4.17.
|
|
42
|
-
"@types/node": "^
|
|
40
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
41
|
+
"@types/lodash": "^4.17.24",
|
|
42
|
+
"@types/node": "^26.1.1",
|
|
43
43
|
"@types/stream-to-promise": "^2.2.5",
|
|
44
44
|
"@types/streamifier": "^0.1.2",
|
|
45
|
-
"@vitest/coverage-v8": "^4.1.
|
|
45
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
46
46
|
"depcheck": "^1.4.7",
|
|
47
|
-
"eslint": "^9.39.
|
|
48
|
-
"prettier": "
|
|
49
|
-
"tsdown": "^0.
|
|
50
|
-
"typescript": "^
|
|
51
|
-
"vite": "^
|
|
52
|
-
"vitest": "^4.1.
|
|
47
|
+
"eslint": "^9.39.5",
|
|
48
|
+
"prettier": "3.9.6",
|
|
49
|
+
"tsdown": "^0.22.13",
|
|
50
|
+
"typescript": "^6.0.3",
|
|
51
|
+
"vite": "^8.1.5",
|
|
52
|
+
"vitest": "^4.1.10",
|
|
53
53
|
"@altano/build-config": "0.0.1",
|
|
54
54
|
"@altano/testing": "0.0.1",
|
|
55
55
|
"@altano/tsconfig": "0.0.1"
|
|
@@ -61,15 +61,15 @@
|
|
|
61
61
|
"access": "public"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|
|
64
|
-
"build": "tsdown
|
|
64
|
+
"build": "tsdown",
|
|
65
65
|
"check:exports": "attw --pack . --profile esm-only --quiet",
|
|
66
66
|
"check:types:src": "tsc --noEmit",
|
|
67
67
|
"check:types:test": "tsc --noEmit --project ./tests/tsconfig.json",
|
|
68
68
|
"check:unused-dependencies": "depcheck",
|
|
69
69
|
"clean": "rm -rf .turbo && rm -rf .tsbuildinfo && rm -rf node_modules && rm -rf dist",
|
|
70
70
|
"dev": "pnpm run build --watch",
|
|
71
|
-
"format": "prettier --check
|
|
72
|
-
"format:fix": "prettier --write
|
|
71
|
+
"format": "prettier --check .",
|
|
72
|
+
"format:fix": "prettier --write .",
|
|
73
73
|
"lint": "eslint",
|
|
74
74
|
"lint:fix": "TIMING=1 pnpm lint --fix",
|
|
75
75
|
"lint:timing": "TIMING=1 pnpm lint",
|