Compare commits

..

10 Commits

Author SHA1 Message Date
github-actions[bot]
bcf8f4fe83 Version Packages 2021-06-21 16:25:40 +02:00
Thomas Allmer
5330740cb3 fix(cli): replace images to be responsive from the bottom up 2021-06-21 16:20:48 +02:00
Thomas Allmer
2edd61beaa chore: remove image hashes from tests 2021-06-21 15:56:41 +02:00
github-actions[bot]
2a5fc08f35 Version Packages 2021-06-21 14:37:07 +02:00
Thomas Allmer
43a7ca10c3 fix(cli): responsive images need to respect pathPrefix 2021-06-21 14:35:51 +02:00
github-actions[bot]
da39fa72f3 Version Packages 2021-06-16 09:08:08 +02:00
Thomas Allmer
a0e8edfbb9 fix(check-html-links): ignore not http schema urls 2021-06-16 09:04:05 +02:00
Thomas Allmer
50434293bb fix(check-html-links): ignore tel links 2021-06-16 09:04:05 +02:00
Thomas Allmer
f08f92615b fix(check-html-links): add missing slash dependency 2021-06-16 09:04:05 +02:00
Thomas Allmer
1949b1e1cb fix(check-html-links): ignore html encoded mailto links 2021-06-16 09:04:05 +02:00
18 changed files with 194 additions and 34 deletions

View File

@@ -1,5 +1,31 @@
# check-html-links
## 0.2.3
### Patch Changes
- 5043429: Ignore `<a href="tel:9999">` links
- f08f926: Add missing `slash` dependency
- a0e8edf: Ignore links containing not http schema urls like `sketch://`, `vscode://`, ...
```html
<a href="sketch://add-library?url=https%3A%2F%2Fmyexample.com%2Fdesign%2Fui-kit.xml"></a>
<a href="vscode://file/c:/myProject/package.json:5:10"></a>
```
- 1949b1e: Ignore plain and html encoded mailto links
```html
<!-- source -->
<a href="mailto:address@example.com">contact</a>
<!-- html encoded -->
<a
href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#97;&#100;&#100;&#114;&#101;&#115;&#115;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;"
>contact</a
>
```
## 0.2.2
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "check-html-links",
"version": "0.2.2",
"version": "0.2.3",
"publishConfig": {
"access": "public"
},
@@ -37,7 +37,8 @@
"command-line-args": "^5.1.1",
"glob": "^7.0.0",
"minimatch": "^3.0.4",
"sax-wasm": "^2.0.0"
"sax-wasm": "^2.0.0",
"slash": "^3.0.0"
},
"devDependencies": {
"@types/glob": "^7.0.0"

View File

@@ -182,6 +182,18 @@ function getValueAndAnchor(inValue) {
};
}
/**
* @param {string} url
* @returns {boolean}
*/
function isNonHttpSchema(url) {
const found = url.match(/([a-z]+):/);
if (found) {
return found.length > 0;
}
return false;
}
/**
*
* @param {Link[]} links
@@ -207,8 +219,13 @@ async function resolveLinks(links, { htmlFilePath, rootDir, ignoreUsage }) {
if (ignoreUsage(value)) {
// ignore
} else if (value.includes('mailto:')) {
} else if (
value.startsWith('mailto:') ||
value.startsWith('&#109;&#97;&#105;&#108;&#116;&#111;&#58;') // = "mailto:" but html encoded
) {
// ignore for now - could add a check to validate if the email address is valid
} else if (value.startsWith('tel:')) {
// ignore for now - could add a check to validate if the phone number is valid
} else if (valueFile === '' && anchor !== '') {
addLocalFile(htmlFilePath, anchor, usageObj);
} else if (value.startsWith('//') || value.startsWith('http')) {
@@ -219,6 +236,8 @@ async function resolveLinks(links, { htmlFilePath, rootDir, ignoreUsage }) {
addLocalFile(filePath, anchor, usageObj);
} else if (value === '' && anchor === '') {
// no need to check it
} else if (isNonHttpSchema(value)) {
// not a schema we handle
} else {
const filePath = path.join(path.dirname(htmlFilePath), valueFile);
addLocalFile(filePath, anchor, usageObj);

View File

@@ -1 +1,3 @@
<a href="mailto:foo@bar.com"></a>
<!-- encoded mailto links -->
<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#97;&#100;&#100;&#114;&#101;&#115;&#115;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;"></a>

View File

@@ -0,0 +1,2 @@
<a href="sketch://add-library?url=https%3A%2F%2Fmyexample.com%2Fdesign%2Fui-kit.xml"></a>
<a href="vscode://file/c:/myProject/package.json:5:10"></a>

View File

@@ -0,0 +1 @@
<a href="tel:99999"></a>

View File

@@ -183,6 +183,16 @@ describe('validateFolder', () => {
expect(cleanup(errors)).to.deep.equal([]);
});
it('ignores tel links', async () => {
const { errors, cleanup } = await execute('fixtures/tel');
expect(cleanup(errors)).to.deep.equal([]);
});
it('ignore not http schema urls', async () => {
const { errors, cleanup } = await execute('fixtures/not-http-schema');
expect(cleanup(errors)).to.deep.equal([]);
});
it('ignoring a folder', async () => {
const { errors, cleanup } = await execute('fixtures/internal-link-ignore', {
ignoreLinkPatterns: ['./relative/*', './relative/**/*'],

View File

@@ -1,5 +1,17 @@
# @rocket/cli
## 0.9.2
### Patch Changes
- 5330740: When replacing images with responsive picture tags do this from the bottom up so the initial dom parsing locations still hold true.
## 0.9.1
### Patch Changes
- 43a7ca1: Responsive images need to respect a set pathPrefix
## 0.9.0
### Minor Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@rocket/cli",
"version": "0.9.0",
"version": "0.9.2",
"publishConfig": {
"access": "public"
},
@@ -67,7 +67,7 @@
"@web/dev-server": "^0.1.4",
"@web/dev-server-rollup": "^0.3.2",
"@web/rollup-plugin-copy": "^0.2.0",
"check-html-links": "^0.2.2",
"check-html-links": "^0.2.3",
"command-line-args": "^5.1.1",
"command-line-usage": "^6.1.1",
"fs-extra": "^9.0.1",

View File

@@ -2,6 +2,7 @@
const fs = require('fs');
const path = require('path');
const EleventyImage = require('@11ty/eleventy-img');
const urlFilter = require('@11ty/eleventy/src/Filters/Url.js');
const { SaxEventType, SAXParser } = require('sax-wasm');
const { getComputedConfig } = require('../public/computedConfig.cjs');
@@ -140,7 +141,7 @@ async function responsiveImages(images, { inputPath, outputDir, imagePresets = {
const metadata = await EleventyImage(filePath, {
outputDir: path.join(outputDir, 'images'),
urlPath: '/images/',
urlPath: urlFilter('/images/'),
...presetSettings,
});
const lowsrc = metadata.jpeg[0];
@@ -194,7 +195,7 @@ async function responsiveImages(images, { inputPath, outputDir, imagePresets = {
function updateHtml(html, changes) {
let newHtml = html;
for (const change of changes) {
for (const change of changes.reverse()) {
newHtml = replaceBetween({
html: newHtml,
start: change.openStart,

View File

@@ -19,6 +19,7 @@ export function setFixtureDir(importMetaUrl) {
* @property {boolean} stripStartEndWhitespace
* @property {boolean} stripScripts
* @property {boolean} formatHtml
* @property {boolean} replaceImageHashes
* @property {start|build} type
*/
@@ -51,6 +52,7 @@ export async function readOutput(
stripScripts = false,
formatHtml = false,
type = 'build',
replaceImageHashes = false,
} = {},
) {
if (!cli || !cli.config) {
@@ -70,6 +72,9 @@ export async function readOutput(
const scriptCloseTagStart = text.indexOf('</script>', scriptOpenTagEnd) + 9;
text = text.substring(0, scriptOpenTagEnd) + text.substring(scriptCloseTagStart);
}
if (replaceImageHashes) {
text = text.replace(/\/images\/([a-z0-9]+)-/g, '/images/__HASH__-');
}
if (formatHtml) {
text = prettier.format(text, { parser: 'html', printWidth: 100 });
}

View File

@@ -102,6 +102,30 @@ describe('RocketCli e2e', () => {
);
const assetHtml = await readStartOutput(cli, 'use-assets/index.html');
expect(assetHtml).to.equal('<link rel="stylesheet" href="/_merged_assets/some.css">');
const imageHtml = await readStartOutput(cli, 'image/index.html', { replaceImageHashes: true });
expect(imageHtml).to.equal(
[
'<p>',
' <figure>',
' <picture>',
'<source type="image/avif" srcset="/images/__HASH__-600.avif 600w, /images/__HASH__-900.avif 900w" sizes="100vw">',
'<source type="image/jpeg" srcset="/images/__HASH__-600.jpeg 600w, /images/__HASH__-900.jpeg 900w" sizes="100vw">',
' <img',
' alt="My Image Alternative Text" rocket-image="responsive"',
' src="/images/__HASH__-600.jpeg"',
' ',
' ',
' width="600"',
' height="316"',
' loading="lazy"',
' decoding="async"',
' />',
' </picture>',
' <figcaption>My Image Description</figcaption>',
'</figure>',
' </p>',
].join('\n'),
);
});
it('can add a pathPrefix that will be used in the build command', async () => {
@@ -119,6 +143,26 @@ describe('RocketCli e2e', () => {
expect(assetHtml).to.equal(
'<html><head><link rel="stylesheet" href="../41297ffa.css">\n\n</head><body>\n\n</body></html>',
);
let imageHtml = await readBuildOutput(cli, 'image/index.html');
imageHtml = imageHtml.replace(/\.\.\/([a-z0-9]+)\./g, '../__HASH__.');
expect(imageHtml).to.equal(
[
'<html><head>',
'</head><body><p>',
' </p><figure>',
' <picture>',
'<source type="image/avif" srcset="../__HASH__.avif 600w, ../__HASH__.avif 900w" sizes="100vw">',
'<source type="image/jpeg" srcset="../__HASH__.jpeg 600w, ../__HASH__.jpeg 900w" sizes="100vw">',
' <img alt="My Image Alternative Text" rocket-image="responsive" src="../__HASH__.jpeg" width="600" height="316" loading="lazy" decoding="async">',
' </picture>',
' <figcaption>My Image Description</figcaption>',
'</figure>',
' <p></p>',
'',
'',
'</body></html>',
].join('\n'),
);
});
it('smoke test for link checking', async () => {

View File

@@ -22,7 +22,10 @@ describe('RocketCli images', () => {
describe('Images', () => {
it('does render content images responsive', async () => {
cli = await executeStart('e2e-fixtures/images/rocket.config.js');
const indexHtml = await readStartOutput(cli, 'index.html', { formatHtml: true });
const indexHtml = await readStartOutput(cli, 'index.html', {
formatHtml: true,
replaceImageHashes: true,
});
expect(indexHtml).to.equal(
[
'<p>',
@@ -30,18 +33,18 @@ describe('RocketCli images', () => {
' <picture>',
' <source',
' type="image/avif"',
' srcset="/images/d67643ad-600.avif 600w, /images/d67643ad-900.avif 900w"',
' srcset="/images/__HASH__-600.avif 600w, /images/__HASH__-900.avif 900w"',
' sizes="100vw"',
' />',
' <source',
' type="image/jpeg"',
' srcset="/images/d67643ad-600.jpeg 600w, /images/d67643ad-900.jpeg 900w"',
' srcset="/images/__HASH__-600.jpeg 600w, /images/__HASH__-900.jpeg 900w"',
' sizes="100vw"',
' />',
' <img',
' alt="My Image Alternative Text"',
' rocket-image="responsive"',
' src="/images/d67643ad-600.jpeg"',
' src="/images/__HASH__-600.jpeg"',
' width="600"',
' height="316"',
' loading="lazy"',
@@ -57,47 +60,57 @@ describe('RocketCli images', () => {
it('renders multiple images in the correct order', async () => {
cli = await executeStart('e2e-fixtures/images/rocket.config.js');
const indexHtml = await readStartOutput(cli, 'two-images/index.html', { formatHtml: true });
const indexHtml = await readStartOutput(cli, 'two-images/index.html', {
formatHtml: true,
replaceImageHashes: true,
});
expect(indexHtml).to.equal(
[
'<h2 id="one">',
' <a aria-hidden="true" tabindex="-1" href="#one"><span class="icon icon-link"></span></a>one',
'</h2>',
'<p>',
' <picture>',
' <source',
' type="image/avif"',
' srcset="/images/d67643ad-600.avif 600w, /images/d67643ad-900.avif 900w"',
' srcset="/images/__HASH__-600.avif 600w, /images/__HASH__-900.avif 900w"',
' sizes="100vw"',
' />',
' <source',
' type="image/jpeg"',
' srcset="/images/d67643ad-600.jpeg 600w, /images/d67643ad-900.jpeg 900w"',
' srcset="/images/__HASH__-600.jpeg 600w, /images/__HASH__-900.jpeg 900w"',
' sizes="100vw"',
' />',
' <img',
' alt="one"',
' rocket-image="responsive"',
' src="/images/d67643ad-600.jpeg"',
' src="/images/__HASH__-600.jpeg"',
' width="600"',
' height="316"',
' loading="lazy"',
' decoding="async"',
' />',
' </picture>',
'',
'</p>',
'<h2 id="two">',
' <a aria-hidden="true" tabindex="-1" href="#two"><span class="icon icon-link"></span></a>two',
'</h2>',
'<p>',
' <picture>',
' <source',
' type="image/avif"',
' srcset="/images/d67643ad-600.avif 600w, /images/d67643ad-900.avif 900w"',
' srcset="/images/__HASH__-600.avif 600w, /images/__HASH__-900.avif 900w"',
' sizes="100vw"',
' />',
' <source',
' type="image/jpeg"',
' srcset="/images/d67643ad-600.jpeg 600w, /images/d67643ad-900.jpeg 900w"',
' srcset="/images/__HASH__-600.jpeg 600w, /images/__HASH__-900.jpeg 900w"',
' sizes="100vw"',
' />',
' <img',
' alt="two"',
' rocket-image="responsive"',
' src="/images/d67643ad-600.jpeg"',
' src="/images/__HASH__-600.jpeg"',
' width="600"',
' height="316"',
' loading="lazy"',
@@ -111,7 +124,10 @@ describe('RocketCli images', () => {
it('can configure those responsive images', async () => {
cli = await executeStart('e2e-fixtures/images/small.rocket.config.js');
const indexHtml = await readStartOutput(cli, 'index.html', { formatHtml: true });
const indexHtml = await readStartOutput(cli, 'index.html', {
formatHtml: true,
replaceImageHashes: true,
});
expect(indexHtml).to.equal(
[
'<p>',
@@ -119,18 +135,18 @@ describe('RocketCli images', () => {
' <picture>',
' <source',
' type="image/avif"',
' srcset="/images/d67643ad-30.avif 30w, /images/d67643ad-60.avif 60w"',
' srcset="/images/__HASH__-30.avif 30w, /images/__HASH__-60.avif 60w"',
' sizes="(min-width: 1024px) 30px, 60px"',
' />',
' <source',
' type="image/jpeg"',
' srcset="/images/d67643ad-30.jpeg 30w, /images/d67643ad-60.jpeg 60w"',
' srcset="/images/__HASH__-30.jpeg 30w, /images/__HASH__-60.jpeg 60w"',
' sizes="(min-width: 1024px) 30px, 60px"',
' />',
' <img',
' alt="My Image Alternative Text"',
' rocket-image="responsive"',
' src="/images/d67643ad-30.jpeg"',
' src="/images/__HASH__-30.jpeg"',
' width="30"',
' height="15"',
' loading="lazy"',
@@ -146,25 +162,28 @@ describe('RocketCli images', () => {
it('will only render a figure & figcaption if there is a caption/title', async () => {
cli = await executeStart('e2e-fixtures/images/small.rocket.config.js');
const indexHtml = await readStartOutput(cli, 'no-title/index.html', { formatHtml: true });
const indexHtml = await readStartOutput(cli, 'no-title/index.html', {
formatHtml: true,
replaceImageHashes: true,
});
expect(indexHtml).to.equal(
[
'<p>',
' <picture>',
' <source',
' type="image/avif"',
' srcset="/images/d67643ad-30.avif 30w, /images/d67643ad-60.avif 60w"',
' srcset="/images/__HASH__-30.avif 30w, /images/__HASH__-60.avif 60w"',
' sizes="(min-width: 1024px) 30px, 60px"',
' />',
' <source',
' type="image/jpeg"',
' srcset="/images/d67643ad-30.jpeg 30w, /images/d67643ad-60.jpeg 60w"',
' srcset="/images/__HASH__-30.jpeg 30w, /images/__HASH__-60.jpeg 60w"',
' sizes="(min-width: 1024px) 30px, 60px"',
' />',
' <img',
' alt="My Image Alternative Text"',
' rocket-image="responsive"',
' src="/images/d67643ad-30.jpeg"',
' src="/images/__HASH__-30.jpeg"',
' width="30"',
' height="15"',
' loading="lazy"',
@@ -178,15 +197,18 @@ describe('RocketCli images', () => {
it('will render an img with srcset and sizes if there is only one image format', async () => {
cli = await executeStart('e2e-fixtures/images/single-format.rocket.config.js');
const indexHtml = await readStartOutput(cli, 'no-title/index.html', { formatHtml: true });
const indexHtml = await readStartOutput(cli, 'no-title/index.html', {
formatHtml: true,
replaceImageHashes: true,
});
expect(indexHtml).to.equal(
[
'<p>',
' <img',
' alt="My Image Alternative Text"',
' rocket-image="responsive"',
' src="/images/d67643ad-30.jpeg"',
' srcset="/images/d67643ad-30.jpeg 30w, /images/d67643ad-60.jpeg 60w"',
' src="/images/__HASH__-30.jpeg"',
' srcset="/images/__HASH__-30.jpeg 30w, /images/__HASH__-60.jpeg 60w"',
' sizes="(min-width: 1024px) 30px, 60px"',
' width="30"',
' height="15"',

View File

@@ -108,15 +108,18 @@ describe('RocketCli preset', () => {
it('a preset can provide an adjustImagePresets() function', async () => {
cli = await executeStart('preset-fixtures/use-preset/rocket.config.js');
const indexHtml = await readStartOutput(cli, 'index.html', { formatHtml: true });
const indexHtml = await readStartOutput(cli, 'index.html', {
formatHtml: true,
replaceImageHashes: true,
});
expect(indexHtml).to.equal(
[
'<p>',
' <img',
' alt="My Image Alternative Text"',
' rocket-image="responsive"',
' src="/images/1f847765-30.jpeg"',
' srcset="/images/1f847765-30.jpeg 30w, /images/1f847765-60.jpeg 60w"',
' src="/images/__HASH__-30.jpeg"',
' srcset="/images/__HASH__-30.jpeg 30w, /images/__HASH__-60.jpeg 60w"',
' sizes="30px"',
' width="30"',
' height="15"',

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

@@ -0,0 +1,5 @@
---
layout: layout-raw
---
![My Image Alternative Text](./_assets/my-image.jpg 'My Image Description')

View File

@@ -2,4 +2,10 @@
layout: layout-raw
---
![one](./_assets/my-image.jpg)![two](./_assets/my-image.jpg)
## one
![one](./_assets/my-image.jpg)
## two
![two](./_assets/my-image.jpg)

View File

@@ -25,6 +25,7 @@ const config = {
}),
],
// serviceWorkerName: 'sw.js',
// pathPrefix: '/_site/',
// emptyOutputDir: false,
};