Docs: migrate to Astro Starlight

This commit is contained in:
Lovell Fuller 2025-01-16 12:55:45 +00:00
parent 14c83e1f4c
commit eeac8d4656
39 changed files with 279 additions and 505 deletions

2
.gitignore vendored
View File

@ -14,3 +14,5 @@ test/leak/libvips.supp
package-lock.json package-lock.json
.idea .idea
.firebase .firebase
.astro
docs/dist

79
docs/astro.config.mjs Normal file
View File

@ -0,0 +1,79 @@
// @ts-check
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
export default defineConfig({
site: 'https://sharp.pixelplumbing.com',
integrations: [
starlight({
title: 'sharp',
description:
'High performance Node.js image processing. The fastest module to resize JPEG, PNG, WebP and TIFF images.',
logo: {
src: './src/assets/sharp-logo.svg',
alt: '#'
},
customCss: ['./src/styles/custom.css'],
head: [{
tag: 'meta',
attrs: {
'http-equiv': 'Content-Security-Policy',
content: "default-src 'self'; connect-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://cdn.jsdelivr.net/gh/lovell/; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://static.cloudflareinsights.com/beacon.min.js/;"
}
}, {
tag: 'link',
attrs: {
rel: 'author',
href: '/humans.txt',
type: 'text/plain'
}
}, {
tag: 'script',
attrs: {
type: 'application/ld+json'
},
content: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'SoftwareSourceCode',
name: 'sharp',
description: 'High performance Node.js image processing',
url: 'https://sharp.pixelplumbing.com',
codeRepository: 'https://github.com/lovell/sharp',
programmingLanguage: ['JavaScript', 'C++'],
runtimePlatform: 'Node.js',
copyrightHolder: {
'@context': 'https://schema.org',
'@type': 'Person',
name: 'Lovell Fuller'
},
copyrightYear: 2013,
license: 'https://www.apache.org/licenses/LICENSE-2.0'
})
}],
sidebar: [
{ label: 'Home', link: '/' },
{ label: 'Installation', slug: 'install' },
{
label: 'API',
items: [
{ label: 'Constructor', slug: 'api-constructor' },
{ label: 'Input metadata', slug: 'api-input' },
{ label: 'Output options', slug: 'api-output' },
{ label: 'Resizing images', slug: 'api-resize' },
{ label: 'Compositing images', slug: 'api-composite' },
{ label: 'Image operations', slug: 'api-operation' },
{ label: 'Colour manipulation', slug: 'api-colour' },
{ label: 'Channel manipulation', slug: 'api-channel' },
{ label: 'Global properties', slug: 'api-utility' }
]
},
{ label: 'Performance', slug: 'performance' },
{ label: 'Changelog', slug: 'changelog' }
],
social: {
openCollective: 'https://opencollective.com/libvips',
github: 'https://github.com/lovell/sharp'
}
})
]
});

View File

@ -1,38 +0,0 @@
// Copyright 2013 Lovell Fuller and others.
// SPDX-License-Identifier: Apache-2.0
'use strict';
const fs = require('fs').promises;
const path = require('path');
const jsdoc2md = require('jsdoc-to-markdown');
[
'constructor',
'input',
'resize',
'composite',
'operation',
'colour',
'channel',
'output',
'utility'
].forEach(async (m) => {
const input = path.join('lib', `${m}.js`);
const output = path.join('docs', `api-${m}.md`);
const ast = await jsdoc2md.getTemplateData({ files: input });
const markdown = await jsdoc2md.render({
data: ast,
'global-index-format': 'none',
'module-index-format': 'none'
});
const cleanMarkdown = markdown
.replace(/(## )([A-Za-z0-9]+)([^\n]*)/g, '$1$2\n> $2$3\n') // simplify headings to match those of documentationjs, ensures existing URLs work
.replace(/<a name="[A-Za-z0-9+]+"><\/a>/g, '') // remove anchors, let docute add these (at markdown to HTML render time)
.replace(/\*\*Kind\*\*: global[^\n]+/g, '') // remove all "global" Kind labels (requires JSDoc refactoring)
.trim();
await fs.writeFile(output, cleanMarkdown);
});

42
docs/build.mjs Normal file
View File

@ -0,0 +1,42 @@
// Copyright 2013 Lovell Fuller and others.
// SPDX-License-Identifier: Apache-2.0
'use strict';
import fs from 'node:fs/promises';
import path from 'node:path';
import jsdoc2md from 'jsdoc-to-markdown';
const pages = {
constructor: 'Constructor',
input: 'Input metadata',
resize: 'Resizing images',
composite: 'Compositing images',
operation: 'Image operations',
colour: 'Colour manipulation',
channel: 'Channel manipulation',
output: 'Output options',
utility: 'Global properties'
};
Object.keys(pages).forEach(async (m) => {
const input = path.join('lib', `${m}.js`);
const output = path.join('docs', 'src', 'content', 'docs', `api-${m}.md`);
const ast = await jsdoc2md.getTemplateData({ files: input });
const markdown = await jsdoc2md.render({
data: ast,
'global-index-format': 'none',
'module-index-format': 'none'
});
const cleanMarkdown =
`---\ntitle: ${pages[m]}\n---\n\n` +
markdown
.replace(/(## )([A-Za-z0-9]+)([^\n]*)/g, '$1$2\n> $2$3\n') // simplify headings
.replace(/<a name="[A-Za-z0-9+]+"><\/a>/g, '') // remove anchors
.replace(/\*\*Kind\*\*: global[^\n]+/g, '') // remove all "global" Kind labels (requires JSDoc refactoring)
.trim();
await fs.writeFile(output, cleanMarkdown);
});

1
docs/docute.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,14 +1,7 @@
{ {
"hosting": { "hosting": {
"site": "pixelplumbing-sharp", "site": "pixelplumbing-sharp",
"public": ".", "public": "dist",
"ignore": [
".*",
"build.js",
"firebase.json",
"image/**",
"search-index/**"
],
"headers": [ "headers": [
{ {
"source": "**", "source": "**",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 652 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

File diff suppressed because one or more lines are too long

17
docs/package.json Normal file
View File

@ -0,0 +1,17 @@
{
"name": "sharp-docs",
"type": "module",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/starlight": "^0.31.0",
"astro": "^5.1.7"
}
}

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 508 B

After

Width:  |  Height:  |  Size: 508 B

4
docs/public/robots.txt Normal file
View File

@ -0,0 +1,4 @@
User-agent: *
Disallow:
Sitemap: https://sharp.pixelplumbing.com/sitemap-index.xml

View File

Before

Width:  |  Height:  |  Size: 929 B

After

Width:  |  Height:  |  Size: 929 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="86 86 550 550">
<!-- Creative Commons CC0 1.0 Universal Public Domain Dedication -->
<path fill="none" stroke="#9c0" stroke-width="80" d="M258.411 285.777l200.176-26.8M244.113 466.413L451.44 438.66M451.441 438.66V238.484M451.441 88.363v171.572l178.725-23.917M270.323 255.602V477.22M272.71 634.17V462.591L93.984 486.515"/>
<path fill="none" stroke="#090" stroke-width="80" d="M451.441 610.246V438.66l178.725-23.91M269.688 112.59v171.58L90.964 308.093"/>
</svg>

After

Width:  |  Height:  |  Size: 508 B

View File

@ -1,2 +0,0 @@
User-agent: *
Disallow:

File diff suppressed because one or more lines are too long

View File

@ -1,64 +0,0 @@
// Copyright 2013 Lovell Fuller and others.
// SPDX-License-Identifier: Apache-2.0
'use strict';
const fs = require('fs');
const path = require('path');
const { extractDescription, extractKeywords, extractParameters } = require('./extract');
const searchIndex = [];
// Install
const contents = fs.readFileSync(path.join(__dirname, '..', 'install.md'), 'utf8');
const matches = contents.matchAll(
/## (?<title>[A-Za-z0-9 ]+)\n\n(?<body>[^#]+)/gs
);
for (const match of matches) {
const { title, body } = match.groups;
const description = extractDescription(body);
searchIndex.push({
t: title,
d: description,
k: extractKeywords(`${title} ${description}`),
l: `/install#${title.toLowerCase().replace(/ /g, '-')}`
});
}
// API
[
'constructor',
'input',
'output',
'resize',
'composite',
'operation',
'channel',
'colour',
'utility'
].forEach((section) => {
const contents = fs.readFileSync(path.join(__dirname, '..', `api-${section}.md`), 'utf8');
const matches = contents.matchAll(
/## (?<title>[A-Za-z]+)\n[^\n]+\n(?<firstparagraph>.+?)\n\n.+?(?<parameters>\| Param .+?\n\n)?\*\*Example/gs
);
for (const match of matches) {
const { title, firstparagraph, parameters } = match.groups;
const description = firstparagraph.startsWith('###')
? 'Constructor'
: extractDescription(firstparagraph);
const parameterNames = parameters ? extractParameters(parameters) : '';
searchIndex.push({
t: title,
d: description,
k: extractKeywords(`${title} ${description} ${parameterNames}`),
l: `/api-${section}#${title.toLowerCase()}`
});
}
});
fs.writeFileSync(
path.join(__dirname, '..', 'search-index.json'),
JSON.stringify(searchIndex)
);

View File

@ -1,34 +0,0 @@
// Copyright 2013 Lovell Fuller and others.
// SPDX-License-Identifier: Apache-2.0
'use strict';
const stopWords = require('./stop-words');
const extractDescription = (str) =>
str
.replace(/### Examples.*/sg, '')
.replace(/\(http[^)]+/g, '')
.replace(/\s+/g, ' ')
.replace(/[^A-Za-z0-9_/\-,. ]/g, '')
.replace(/\s+/g, ' ')
.substring(0, 200)
.trim();
const extractParameters = (str) =>
[...str.matchAll(/options\.(?<name>[^.`\] ]+)/gs)]
.map((match) => match.groups.name)
.map((name) => name.replace(/([A-Z])/g, ' $1').toLowerCase())
.join(' ');
const extractKeywords = (str) =>
[
...new Set(
str
.split(/[ -/]/)
.map((word) => word.toLowerCase().replace(/[^a-z]/g, ''))
.filter((word) => word.length > 2 && word.length < 15 && !stopWords.includes(word))
)
].join(' ');
module.exports = { extractDescription, extractKeywords, extractParameters };

View File

@ -1,140 +0,0 @@
// Copyright 2013 Lovell Fuller and others.
// SPDX-License-Identifier: Apache-2.0
'use strict';
module.exports = [
'about',
'after',
'all',
'allows',
'already',
'also',
'alternative',
'always',
'and',
'any',
'are',
'available',
'based',
'been',
'before',
'best',
'both',
'call',
'callback',
'can',
'containing',
'contains',
'created',
'current',
'date',
'default',
'deprecated',
'does',
'each',
'either',
'ensure',
'entirely',
'etc',
'every',
'except',
'following',
'for',
'from',
'get',
'gets',
'given',
'has',
'have',
'helps',
'how',
'image',
'implies',
'include',
'including',
'involve',
'its',
'last',
'least',
'lots',
'make',
'may',
'meaning',
'more',
'most',
'much',
'must',
'non',
'not',
'now',
'occur',
'occurs',
'one',
'options',
'other',
'out',
'over',
'part',
'perform',
'performs',
'please',
'pre',
'previously',
'produce',
'proper',
'provide',
'provided',
'ready',
'requires',
'requiresharp',
'returned',
'run',
'same',
'see',
'set',
'sets',
'sharp',
'should',
'since',
'site',
'some',
'specified',
'spelling',
'such',
'support',
'supported',
'sure',
'take',
'task',
'than',
'that',
'the',
'their',
'then',
'there',
'therefore',
'these',
'this',
'under',
'unless',
'unmaintained',
'unsuitable',
'unsupported',
'until',
'use',
'used',
'using',
'value',
'values',
'via',
'were',
'when',
'which',
'while',
'will',
'with',
'without',
'you',
'your'
];

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="86 86 550 550">
<!-- Creative Commons CC0 1.0 Universal Public Domain Dedication -->
<path fill="none" stroke="#9c0" stroke-width="80" d="M258.411 285.777l200.176-26.8M244.113 466.413L451.44 438.66M451.441 438.66V238.484M451.441 88.363v171.572l178.725-23.917M270.323 255.602V477.22M272.71 634.17V462.591L93.984 486.515"/>
<path fill="none" stroke="#090" stroke-width="80" d="M451.441 610.246V438.66l178.725-23.91M269.688 112.59v171.58L90.964 308.093"/>
</svg>

After

Width:  |  Height:  |  Size: 508 B

View File

@ -0,0 +1,7 @@
import { defineCollection } from 'astro:content';
import { docsLoader } from '@astrojs/starlight/loaders';
import { docsSchema } from '@astrojs/starlight/schema';
export const collections = {
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
};

View File

@ -1,3 +1,7 @@
---
title: Channel manipulation
---
## removeAlpha ## removeAlpha
> removeAlpha() ⇒ <code>Sharp</code> > removeAlpha() ⇒ <code>Sharp</code>

View File

@ -1,3 +1,7 @@
---
title: Colour manipulation
---
## tint ## tint
> tint(tint) ⇒ <code>Sharp</code> > tint(tint) ⇒ <code>Sharp</code>

View File

@ -1,3 +1,7 @@
---
title: Compositing images
---
## composite ## composite
> composite(images) ⇒ <code>Sharp</code> > composite(images) ⇒ <code>Sharp</code>

View File

@ -1,3 +1,7 @@
---
title: Constructor
---
## Sharp ## Sharp
> Sharp > Sharp

View File

@ -1,3 +1,7 @@
---
title: Input metadata
---
## metadata ## metadata
> metadata([callback]) ⇒ <code>Promise.&lt;Object&gt;</code> \| <code>Sharp</code> > metadata([callback]) ⇒ <code>Promise.&lt;Object&gt;</code> \| <code>Sharp</code>

View File

@ -1,3 +1,7 @@
---
title: Image operations
---
## rotate ## rotate
> rotate([angle], [options]) ⇒ <code>Sharp</code> > rotate([angle], [options]) ⇒ <code>Sharp</code>

View File

@ -1,3 +1,7 @@
---
title: Output options
---
## toFile ## toFile
> toFile(fileOut, [callback]) ⇒ <code>Promise.&lt;Object&gt;</code> > toFile(fileOut, [callback]) ⇒ <code>Promise.&lt;Object&gt;</code>

View File

@ -1,3 +1,7 @@
---
title: Resizing images
---
## resize ## resize
> resize([width], [height], [options]) ⇒ <code>Sharp</code> > resize([width], [height], [options]) ⇒ <code>Sharp</code>

View File

@ -1,3 +1,7 @@
---
title: Global properties
---
## versions ## versions
> versions > versions

View File

@ -1,5 +1,7 @@
# Changelog ---
title: Changelog
---
## v0.34 - *hat* ## v0.34 - *hat*
Requires libvips v8.16.0 Requires libvips v8.16.0

View File

@ -1,4 +1,6 @@
# sharp ---
title: "High performance Node.js image processing"
---
<img src="https://cdn.jsdelivr.net/gh/lovell/sharp@main/docs/image/sharp-logo.svg" width="160" height="160" alt="sharp logo" align="right"> <img src="https://cdn.jsdelivr.net/gh/lovell/sharp@main/docs/image/sharp-logo.svg" width="160" height="160" alt="sharp logo" align="right">
@ -23,7 +25,11 @@ rotation, extraction, compositing and gamma correction are available.
Most modern macOS, Windows and Linux systems Most modern macOS, Windows and Linux systems
do not require any additional install or runtime dependencies. do not require any additional install or runtime dependencies.
### Formats ```sh
npm install sharp
```
## Formats
This module supports reading JPEG, PNG, WebP, GIF, AVIF, TIFF and SVG images. This module supports reading JPEG, PNG, WebP, GIF, AVIF, TIFF and SVG images.
@ -37,7 +43,7 @@ Deep Zoom image pyramids can be generated,
suitable for use with "slippy map" tile viewers like suitable for use with "slippy map" tile viewers like
[OpenSeadragon](https://github.com/openseadragon/openseadragon). [OpenSeadragon](https://github.com/openseadragon/openseadragon).
### Fast ## Fast
This module is powered by the blazingly fast This module is powered by the blazingly fast
[libvips](https://github.com/libvips/libvips) image processing library, [libvips](https://github.com/libvips/libvips) image processing library,
@ -52,7 +58,7 @@ taking full advantage of multiple CPU cores and L1/L2/L3 cache.
Everything remains non-blocking thanks to _libuv_, Everything remains non-blocking thanks to _libuv_,
no child processes are spawned and Promises/async/await are supported. no child processes are spawned and Promises/async/await are supported.
### Optimal ## Optimal
The features of `mozjpeg` and `pngquant` can be used The features of `mozjpeg` and `pngquant` can be used
to optimise the file size of JPEG and PNG images respectively, to optimise the file size of JPEG and PNG images respectively,
@ -71,12 +77,12 @@ The file size of animated GIF output is optimised
without having to use separate command line tools such as without having to use separate command line tools such as
[gifsicle](https://www.lcdf.org/gifsicle/). [gifsicle](https://www.lcdf.org/gifsicle/).
### Contributing ## Contributing
A [guide for contributors](https://github.com/lovell/sharp/blob/main/.github/CONTRIBUTING.md) A [guide for contributors](https://github.com/lovell/sharp/blob/main/.github/CONTRIBUTING.md)
covers reporting bugs, requesting features and submitting code changes. covers reporting bugs, requesting features and submitting code changes.
### Licensing ## Licensing
Copyright 2013 Lovell Fuller and others. Copyright 2013 Lovell Fuller and others.

View File

@ -1,8 +1,12 @@
# Installation ---
title: Installation
---
Works with your choice of JavaScript package manager. Works with your choice of JavaScript package manager.
> ⚠️ **Please ensure your package manager is configured to install optional dependencies** :::caution
Please ensure your package manager is configured to install optional dependencies
:::
If a package manager lockfile must support multiple platforms, If a package manager lockfile must support multiple platforms,
please see the [cross-platform](#cross-platform) section please see the [cross-platform](#cross-platform) section
@ -59,7 +63,9 @@ within the same installation tree and/or using the same lockfile.
### npm v10+ ### npm v10+
> ⚠️ **npm `package-lock.json` files can cause installation problems due to [npm bug #4828](https://github.com/npm/cli/issues/4828)** :::caution
npm `package-lock.json` files shared by multiple platforms can cause installation problems due to [npm bug #4828](https://github.com/npm/cli/issues/4828)
:::
Provides limited support via `--os`, `--cpu` and `--libc` flags. Provides limited support via `--os`, `--cpu` and `--libc` flags.

View File

@ -1,4 +1,6 @@
# Performance ---
title: Performance
---
A test to benchmark the performance of this module relative to alternatives. A test to benchmark the performance of this module relative to alternatives.

View File

@ -0,0 +1,45 @@
@view-transition {
navigation: auto;
}
:root {
--sl-content-width: 60rem;
--sl-color-accent-low: #072d00;
--sl-color-accent: #247f00;
--sl-color-accent-high: #aad7a0;
--sl-color-white: #ffffff;
--sl-color-gray-1: #eaf0e8;
--sl-color-gray-2: #c5cdc3;
--sl-color-gray-3: #99a796;
--sl-color-gray-4: #4f5c4d;
--sl-color-gray-5: #303c2d;
--sl-color-gray-6: #1f2a1c;
--sl-color-black: #151a13;
}
:root[data-theme="light"] {
--sl-color-accent-low: #c0e2b8;
--sl-color-accent: #165800;
--sl-color-accent-high: #0d3e00;
--sl-color-white: #151a13;
--sl-color-gray-1: #1f2a1c;
--sl-color-gray-2: #303c2d;
--sl-color-gray-3: #4f5c4d;
--sl-color-gray-4: #82907f;
--sl-color-gray-5: #bdc4bb;
--sl-color-gray-6: #eaf0e8;
--sl-color-gray-7: #f4f7f3;
--sl-color-black: #ffffff;
}
blockquote {
background-color: var(--sl-color-gray-6);
padding: 1rem;
}
.site-title::after {
content: "High performance Node.js image processing";
color: var(--sl-color-text);
font-size: var(--sl-text-sm);
padding-top: 0.3rem;
}

5
docs/tsconfig.json Normal file
View File

@ -0,0 +1,5 @@
{
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}

View File

@ -102,9 +102,9 @@
"test-types": "tsd", "test-types": "tsd",
"package-from-local-build": "node npm/from-local-build", "package-from-local-build": "node npm/from-local-build",
"package-from-github-release": "node npm/from-github-release", "package-from-github-release": "node npm/from-github-release",
"docs-build": "node docs/build && node docs/search-index/build", "docs-build": "node docs/build.mjs",
"docs-serve": "cd docs && npx serve", "docs-serve": "cd docs && npm start",
"docs-publish": "cd docs && npx firebase-tools deploy --project pixelplumbing --only hosting:pixelplumbing-sharp" "docs-publish": "cd docs && npm run build && npx firebase-tools deploy --project pixelplumbing --only hosting:pixelplumbing-sharp"
}, },
"type": "commonjs", "type": "commonjs",
"main": "lib/index.js", "main": "lib/index.js",