Socket
Socket
Sign inDemoInstall

@bradymholt/ampify

Package Overview
Dependencies
81
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.0 to 0.2.0

2

index.d.ts

@@ -1,2 +0,2 @@

declare module "ampify" {
declare module "@bradymholt/ampify" {
export = ampify;

@@ -3,0 +3,0 @@ }

@@ -1,64 +0,116 @@

const fs = require('fs');
const url = require('url');
const axios = require('axios');
const cheerio = require('cheerio');
const sizeOf = require('image-size');
const CleanCss = require('clean-css');
const fs = require("fs");
const url = require("url");
const axios = require("axios");
const cheerio = require("cheerio");
const sizeOf = require("image-size");
const CleanCss = require("clean-css");
const pretty = require('pretty');
module.exports = async (html, options) => {
const tags = {
amp: ['img', 'video'],
};
let youtube = false;
const cheerioOptions = options || {
cwd: options.cwd || '',
cwd: options.cwd || "",
round: options.round || true,
normalizeWhitespace: options.normalizeWhitespace || false,
xmlMode: options.xmlMode || false,
decodeEntities: options.decodeEntities || false,
decodeEntities: options.decodeEntities || false
};
const round = cheerioOptions.round
? numb => Math.round(numb / 5) * 5
: numb => numb;
// Load html
const $ = cheerio.load(html, cheerioOptions);
const round = cheerioOptions.round ? numb => Math.round(numb / 5) * 5 : numb => numb;
const headElement = $("head");
/* AMP Boilerplate */
// add amp atrribute to <html/> element
$("html")
.first()
.attr("amp", "");
// set charset to utf-8
headElement.find("meta[charset]").remove();
headElement.prepend('<meta charset="utf-8">');
/* meta viewport */
headElement.find("meta[name='viewport']").remove();
headElement.append(
'<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">'
);
/* amp-boilerplate styles */
if (headElement.find("style[amp-boilerplate]").length === 0) {
headElement.append(
'<style amp-boilerplate="">body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>'
);
}
// AMP script
headElement.find("script[src*='cdn.ampproject.org']").remove();
headElement.append(
'<script async src="https://cdn.ampproject.org/v0.js"></script>'
);
/* remove non-AMP scripts */
$("script").each((index, element) => {
const el = $(element);
if (
el.attr("custom-element") == "amp-analytics" ||
el.attr("src") && el.attr("src").indexOf("cdn.ampproject.org") > -1
) {
return;
} else {
el.remove();
}
});
/* Fetch images and CSS */
const promises = [];
const responses = {};
const externalSrcContent = {};
$('img:not([width]):not([height])').each((index, element) => {
const src = $(element).attr('src');
// Fetch external images
$("img:not([width]):not([height])").each((index, element) => {
const src = $(element).attr("src");
// skip if already fetched
if (responses[src]) {
if (externalSrcContent[src]) {
return;
}
if (src && src.indexOf('//') !== -1) {
if (src && src.indexOf("//") !== -1) {
// set a flag
responses[src] = true;
externalSrcContent[src] = true;
const imageUrl = element.attribs.src;
promises.push(axios.get(imageUrl, { responseType: 'arraybuffer' })
.then((response) => {
responses[src] = response;
}));
promises.push(
axios.get(imageUrl, { responseType: "arraybuffer" }).then(response => {
externalSrcContent[src] = response;
})
);
}
});
$('link[rel=stylesheet]').each((index, element) => {
const src = $(element).attr('href');
if (responses[src]) {
// Fetch external CSS
$("link[rel=stylesheet]").each((index, element) => {
const src = $(element).attr("href");
if (isGoogleFontHostSrc(src)) {
// External links to fonts are allowed; we'll make a specific exception for Google Fonts
return;
}
if (externalSrcContent[src]) {
// We've already cached this one
return;
}
try {
if (src && src.indexOf('//') !== -1) {
if (src && src.indexOf("//") !== -1) {
let cssSrc = src;
if (src.indexOf('//') === 0) {
if (src.indexOf("//") === 0) {
cssSrc = `https:${src}`;
}
responses[src] = true;
promises.push(axios.get(cssSrc)
.then((response) => {
responses[src] = response;
}));
externalSrcContent[src] = true;
promises.push(
axios.get(cssSrc).then(response => {
externalSrcContent[src] = response;
})
);
}

@@ -72,69 +124,10 @@ } catch (err) {

/* html ⚡ */
$('html').each((index, element) => {
$(element).attr('amp', '');
});
/* head */
/* main amp library */
$('head script[src="https://cdn.ampproject.org/v0.js"]').remove();
$('head').prepend('<script async src="https://cdn.ampproject.org/v0.js"></script>');
/* meta charset */
$('head meta[charset="utf-8"]').remove();
$('head meta[charset="UTF-8"]').remove();
$('head').prepend('<meta charset="utf-8">');
/* google analytics */
$('script').each((index, element) => {
const src = $(element).attr('src');
if (src) {
const trackingId = src.match(/\bUA-\d{4,10}-\d{1,4}\b/);
if (trackingId) {
$(element).remove();
$('head').prepend('<script async custom-element="amp-analytics"src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"></script>');
$('body').append(`<amp-analytics type="googleanalytics">
<script type="application/json">
{ "vars": {
"account": "${trackingId}"
},
"triggers": {
"trackPageview": {
"on": "visible",
"request": "pageview"
}
}
}
</script>
</amp-analytics>`);
}
}
const scriptContent = $(element).html();
const htmlScriptContent = scriptContent.match(/function gtag\(\){dataLayer\.push\(arguments\);}/);
if (scriptContent && htmlScriptContent) {
$(element).remove();
}
});
/* meta viewport */
if ($('head meta[content="width=device-width,minimum-scale=1,initial-scale=1"]').length === 0) {
$('head').append('<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">');
}
/* style amp-boilerplate */
if ($('head style[amp-boilerplate]').length === 0) {
$('head').append('<style amp-boilerplate="">body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate="">body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>');
}
/* body */
/* img dimensions */
$('img:not([width]):not([height])').each((index, element) => {
const src = $(element).attr('src');
/* Set <img/> element height/width dimensions */
$("img:not([width]):not([height])").each((index, element) => {
const src = $(element).attr("src");
if (!src) {
return $(element).remove();
}
if (src.indexOf('//') === -1) {
const image = `${options.cwd}/${$(element).attr('src')}`;
if (src.indexOf("//") === -1) {
const image = `${options.cwd}/${$(element).attr("src")}`;
if (fs.existsSync(image)) {

@@ -144,14 +137,14 @@ const size = sizeOf(image);

width: round(size.width),
height: round(size.height),
height: round(size.height)
});
}
} else if (src.indexOf('//') !== -1) {
const response = responses[src];
} else if (src.indexOf("//") !== -1) {
const response = externalSrcContent[src];
if (response === true) {
throw new Error('No image for', src);
throw new Error("No image for", src);
}
const size = sizeOf(Buffer.from(response.data, 'binary'));
const size = sizeOf(Buffer.from(response.data, "binary"));
$(element).attr({
width: round(size.width),
height: round(size.height),
height: round(size.height)
});

@@ -161,24 +154,27 @@ }

/* inline styles */
$('link[rel=stylesheet]').each((index, element) => {
const src = $(element).attr('href');
/* Fetch external stylesheet content */
let styles = "";
$("link[rel=stylesheet]").each((index, element) => {
const src = $(element).attr("href");
let path = src;
let file = '';
const setFile = (data) => {
const minified = new CleanCss().minify(data).styles;
return `<style amp-custom>${minified}</style>`;
};
try {
if (src.indexOf('//') === -1) {
if (isGoogleFontHostSrc(src)) {
return;
}
const isRemoteSrcReference = src.indexOf("//") !== -1;
if (isRemoteSrcReference) {
const response = externalSrcContent[src];
if (response === true) {
throw new Error("No CSS for", src);
}
styles += response.data;
} else {
// Local file reference
path = `${options.cwd}/${src}`;
if (fs.existsSync(path)) {
file = setFile(String(fs.readFileSync(path)));
const fileContent = String(fs.readFileSync(path));
styles += fileContent;
}
} else if (src.indexOf('//') !== -1) {
const response = responses[src];
if (response === true) {
throw new Error('No CSS for', src);
}
file = setFile(response.data);
}

@@ -188,12 +184,28 @@ } catch (err) {

}
$(element).replaceWith(file);
$(element).remove();
});
/* Gather internal styles */
$("style:not([amp-boilerplate])").each((index, element) => {
styles += $(element).html();
$(element).remove();
});
// Add styles to <head/>
const minifiedStyles = new CleanCss().minify(styles).styles;
const finalizedStyles = scrubCss(minifiedStyles);
headElement.find("style[amp-custom]").remove();
headElement.append(`<style amp-custom>${finalizedStyles}</style>`);
/* youtube */
$('iframe[src*="http://www.youtube.com"],iframe[src*="https://www.youtube.com"],iframe[src*="http://youtu.be/"],iframe[src*="https://youtu.be/"]').each((index, element) => {
youtube = true;
const src = $(element).attr('src');
const width = $(element).attr('width');
const height = $(element).attr('height');
const path = url.parse(src).pathname.split('/');
let youTubeVideoEmbeded = false;
$(
'iframe[src*="http://www.youtube.com"],iframe[src*="https://www.youtube.com"],iframe[src*="http://youtu.be/"],iframe[src*="https://youtu.be/"]'
).each((index, element) => {
youTubeVideoEmbeded = true;
const src = $(element).attr("src");
const width = $(element).attr("width");
const height = $(element).attr("height");
const path = url.parse(src).pathname.split("/");
const ampYoutube = `

@@ -209,10 +221,15 @@ <amp-youtube

if (youtube) {
$('head').prepend('<script async custom-element="amp-youtube" src="https://cdn.ampproject.org/v0/amp-youtube-0.1.js">');
if (youTubeVideoEmbeded) {
headElement.prepend(
'<script async custom-element="amp-youtube" src="https://cdn.ampproject.org/v0/amp-youtube-0.1.js">'
);
}
/* amp tags */
$(tags.amp.join(',')).each((index, element) => {
/* Convert HTML tags to AMP tags */
const includeTags = {
amp: ["img", "video"]
};
$(includeTags.amp.join(",")).each((index, element) => {
const ampElement = Object.assign(element, {
name: `amp-${element.name}`,
name: `amp-${element.name}`
});

@@ -222,3 +239,13 @@ $(element).html($(ampElement).html());

return $.html();
const outerHtml = $.html();
const prettyOuterHtml = pretty(outerHtml);
return prettyOuterHtml;
};
function isGoogleFontHostSrc(src) {
return src.indexOf("fonts.googleapis.com") > -1;
}
function scrubCss(css) {
return css.replace(/\!important/g, "");
}
{
"name": "@bradymholt/ampify",
"version": "0.1.0",
"publishConfig":{
"version": "0.2.0",
"publishConfig": {
"access": "public"

@@ -42,3 +42,4 @@ },

"clean-css": "^4.2.1",
"image-size": "^0.7.3"
"image-size": "^0.7.3",
"pretty": "^2.0.0"
},

@@ -45,0 +46,0 @@ "devDependencies": {

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc