Merge branch 'main' into spike/upgrade
This commit is contained in:
commit
cbb244421b
344 changed files with 2148 additions and 2319 deletions
|
@ -2,9 +2,6 @@
|
|||
"extends": "../../../tsconfig.base.json",
|
||||
"include": ["src"],
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"module": "ES2022",
|
||||
"outDir": "./dist",
|
||||
"target": "ES2022"
|
||||
"outDir": "./dist"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^3.0.13"
|
||||
"astro": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^1.0.3",
|
||||
"@astrojs/mdx": "^1.1.0",
|
||||
"@astrojs/rss": "^3.0.0",
|
||||
"@astrojs/sitemap": "^3.0.0",
|
||||
"astro": "^3.0.13"
|
||||
"astro": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
],
|
||||
"scripts": {},
|
||||
"devDependencies": {
|
||||
"astro": "^3.0.13"
|
||||
"astro": "^3.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"astro": "^2.0.0-beta.0"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^3.0.13"
|
||||
"astro": "^3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/deno": "^5.0.0"
|
||||
|
|
|
@ -14,6 +14,6 @@
|
|||
"@astrojs/alpinejs": "^0.3.0",
|
||||
"@types/alpinejs": "^3.7.2",
|
||||
"alpinejs": "^3.12.3",
|
||||
"astro": "^3.0.13"
|
||||
"astro": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"dependencies": {
|
||||
"@astrojs/lit": "^3.0.0",
|
||||
"@webcomponents/template-shadowroot": "^0.2.1",
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"lit": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"@astrojs/solid-js": "^3.0.1",
|
||||
"@astrojs/svelte": "^4.0.2",
|
||||
"@astrojs/vue": "^3.0.0",
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"preact": "^10.17.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"dependencies": {
|
||||
"@astrojs/preact": "^3.0.0",
|
||||
"@preact/signals": "^1.2.1",
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"preact": "^10.17.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"@astrojs/react": "^3.0.2",
|
||||
"@types/react": "^18.2.21",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/solid-js": "^3.0.1",
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"solid-js": "^1.7.11"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/svelte": "^4.0.2",
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"svelte": "^4.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/vue": "^3.0.0",
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"vue": "^3.3.4"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/node": "^6.0.0",
|
||||
"astro": "^3.0.13"
|
||||
"astro": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
],
|
||||
"scripts": {},
|
||||
"devDependencies": {
|
||||
"astro": "^3.0.13"
|
||||
"astro": "^3.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"astro": "^2.0.0-beta.0"
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/node": "^6.0.0",
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"html-minifier": "^4.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^3.0.13"
|
||||
"astro": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^3.0.13"
|
||||
"astro": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^3.0.13"
|
||||
"astro": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"dependencies": {
|
||||
"@astrojs/node": "^6.0.0",
|
||||
"@astrojs/svelte": "^4.0.2",
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"svelte": "^4.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/markdoc": "^0.5.0",
|
||||
"astro": "^3.0.13"
|
||||
"astro": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/markdown-remark": "^3.1.0",
|
||||
"astro": "^3.0.13",
|
||||
"@astrojs/markdown-remark": "^3.2.0",
|
||||
"astro": "^3.1.0",
|
||||
"hast-util-select": "^5.0.5",
|
||||
"rehype-autolink-headings": "^6.1.1",
|
||||
"rehype-slug": "^5.1.0",
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^3.0.13"
|
||||
"astro": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^1.0.3",
|
||||
"@astrojs/mdx": "^1.1.0",
|
||||
"@astrojs/preact": "^3.0.0",
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"preact": "^10.17.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"dependencies": {
|
||||
"@astrojs/preact": "^3.0.0",
|
||||
"@nanostores/preact": "^0.5.0",
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"nanostores": "^0.9.3",
|
||||
"preact": "^10.17.1"
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^1.0.3",
|
||||
"@astrojs/mdx": "^1.1.0",
|
||||
"@astrojs/tailwind": "^5.0.0",
|
||||
"@types/canvas-confetti": "^1.6.0",
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"canvas-confetti": "^1.6.0",
|
||||
"postcss": "^8.4.28",
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"vite-plugin-pwa": "0.16.4",
|
||||
"workbox-window": "^7.0.0"
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"test": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^3.0.13",
|
||||
"astro": "^3.1.0",
|
||||
"vitest": "^0.34.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["src"],
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"outDir": "./dist"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { z } from 'astro/zod';
|
||||
import type { RSSOptions } from './index';
|
||||
import type { RSSOptions } from './index.js';
|
||||
|
||||
/** Normalize URL to its canonical form */
|
||||
export function createCanonicalURL(
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["src"],
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"module": "ES2022",
|
||||
"outDir": "./dist",
|
||||
"target": "ES2022",
|
||||
"strictNullChecks": true
|
||||
"outDir": "./dist"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,28 @@
|
|||
# astro
|
||||
|
||||
## 3.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#8467](https://github.com/withastro/astro/pull/8467) [`ecc65abbf`](https://github.com/withastro/astro/commit/ecc65abbf9e086c5bbd1973cd4a820082b4e0dc5) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Add a new `image.endpoint` setting to allow using a custom endpoint in dev and SSR
|
||||
|
||||
- [#8518](https://github.com/withastro/astro/pull/8518) [`2c4fc878b`](https://github.com/withastro/astro/commit/2c4fc878bece36b7fcf1470419c7ce6f1e1e95d0) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Adds support for using AVIF (`.avif`) files with the Image component. Importing an AVIF file will now correctly return the same object shape as other image file types. See the [Image docs](https://docs.astro.build/en/guides/images/#update-existing-img-tags) for more information on the different properties available on the returned object.
|
||||
|
||||
- [#8464](https://github.com/withastro/astro/pull/8464) [`c92e0acd7`](https://github.com/withastro/astro/commit/c92e0acd715171b3f4c3294099780e21576648c8) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Add types for the object syntax for `style` (ex: `style={{color: 'red'}}`)
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#8532](https://github.com/withastro/astro/pull/8532) [`7522bb491`](https://github.com/withastro/astro/commit/7522bb4914f2f9e8b8f3c743bc9c941fd3aca644) Thanks [@bluwy](https://github.com/bluwy)! - Improve markdown rendering performance by sharing processor instance
|
||||
|
||||
- [#8537](https://github.com/withastro/astro/pull/8537) [`f95febf96`](https://github.com/withastro/astro/commit/f95febf96bb97babb28d78994332f5e47f5f637d) Thanks [@martrapp](https://github.com/martrapp)! - bugfix checking media-type in client-side router
|
||||
|
||||
- [#8536](https://github.com/withastro/astro/pull/8536) [`b85c8a78a`](https://github.com/withastro/astro/commit/b85c8a78a116dbbddc901438bc0b7a1917dc0238) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Improved error messages around `astro:assets`
|
||||
|
||||
- [#7607](https://github.com/withastro/astro/pull/7607) [`45364c345`](https://github.com/withastro/astro/commit/45364c345267429e400baecd1fbc290503f8b13a) Thanks [@FineWolf](https://github.com/FineWolf)! - Add `CollectionKey`, `ContentCollectionKey`, and `DataCollectionKey` exports to `astro:content`
|
||||
|
||||
- Updated dependencies [[`d93987824`](https://github.com/withastro/astro/commit/d93987824d3d6b4f58267be21ab8466ee8d5d5f8), [`7522bb491`](https://github.com/withastro/astro/commit/7522bb4914f2f9e8b8f3c743bc9c941fd3aca644)]:
|
||||
- @astrojs/markdown-remark@3.2.0
|
||||
|
||||
## 3.0.13
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -34,10 +34,10 @@ Having trouble? Get help in the official [Astro Discord](https://astro.build/cha
|
|||
|
||||
**New contributors welcome!** Check out our [Contributors Guide](/CONTRIBUTING.md) for help getting started.
|
||||
|
||||
Join us on [Discord](https://astro.build/chat) to meet other maintainers. We'll help you get your first contribution in no time!
|
||||
Join us on [Discord](https://astro.build/chat) to meet other contributors. We'll help you get your first contribution in no time!
|
||||
|
||||
## Sponsors
|
||||
|
||||
Astro is generously supported by [Netlify](https://www.netlify.com/), [Vercel](https://vercel.com/), and several other amazing organizations [listed here.](https://astro.build/)
|
||||
Astro is generously supported by [Vercel](https://vercel.com/), [storyblok](https://storyblok.com/), and several other amazing organizations [listed here.](https://opencollective.com/astrodotbuild)
|
||||
|
||||
[❤️ Sponsor Astro! ❤️](https://github.com/withastro/.github/blob/main/FUNDING.md)
|
||||
|
|
29
packages/astro/astro-jsx.d.ts
vendored
29
packages/astro/astro-jsx.d.ts
vendored
|
@ -471,6 +471,33 @@ declare namespace astroHTML.JSX {
|
|||
| 'treegrid'
|
||||
| 'treeitem';
|
||||
|
||||
type CssProperty = keyof Omit<
|
||||
CSSStyleDeclaration,
|
||||
| 'item'
|
||||
| 'setProperty'
|
||||
| 'removeProperty'
|
||||
| 'getPropertyValue'
|
||||
| 'getPropertyPriority'
|
||||
| 'parentRule'
|
||||
| 'length'
|
||||
| 'cssFloat'
|
||||
| 'cssText'
|
||||
| typeof Symbol.iterator
|
||||
| number
|
||||
>;
|
||||
|
||||
type KebabCSSDOMProperties = import('./dist/type-utils.js').KebabKeys<DOMCSSProperties>;
|
||||
|
||||
type DOMCSSProperties = {
|
||||
[key in CssProperty]?: string | number | null | undefined;
|
||||
};
|
||||
type AllCSSProperties = {
|
||||
[key: string]: string | number | null | undefined;
|
||||
};
|
||||
type StyleObject = import('./dist/type-utils.js').Simplify<
|
||||
KebabCSSDOMProperties & DOMCSSProperties & AllCSSProperties
|
||||
>;
|
||||
|
||||
interface HTMLAttributes extends AriaAttributes, DOMAttributes, AstroBuiltinAttributes {
|
||||
// Standard HTML Attributes
|
||||
accesskey?: string | undefined | null;
|
||||
|
@ -513,7 +540,7 @@ declare namespace astroHTML.JSX {
|
|||
lang?: string | undefined | null;
|
||||
slot?: string | undefined | null;
|
||||
spellcheck?: 'true' | 'false' | boolean | undefined | null;
|
||||
style?: string | Record<string, any> | undefined | null;
|
||||
style?: string | StyleObject | undefined | null;
|
||||
tabindex?: number | string | undefined | null;
|
||||
title?: string | undefined | null;
|
||||
translate?: 'yes' | 'no' | undefined | null;
|
||||
|
|
12
packages/astro/client.d.ts
vendored
12
packages/astro/client.d.ts
vendored
|
@ -52,7 +52,7 @@ declare module 'astro:assets' {
|
|||
| import('./dist/assets/types.js').ImageTransform
|
||||
| import('./dist/assets/types.js').UnresolvedImageTransform
|
||||
) => Promise<import('./dist/assets/types.js').GetImageResult>;
|
||||
imageConfig: import('./dist/@types/astro').AstroConfig['image'];
|
||||
imageConfig: import('./dist/@types/astro.js').AstroConfig['image'];
|
||||
getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService;
|
||||
Image: typeof import('./components/Image.astro').default;
|
||||
};
|
||||
|
@ -108,6 +108,10 @@ declare module '*.svg' {
|
|||
const metadata: ImageMetadata;
|
||||
export default metadata;
|
||||
}
|
||||
declare module '*.avif' {
|
||||
const metadata: ImageMetadata;
|
||||
export default metadata;
|
||||
}
|
||||
|
||||
declare module 'astro:transitions' {
|
||||
type TransitionModule = typeof import('./dist/transitions/index.js');
|
||||
|
@ -126,7 +130,7 @@ declare module 'astro:components' {
|
|||
export * from 'astro/components';
|
||||
}
|
||||
|
||||
type MD = import('./dist/@types/astro').MarkdownInstance<Record<string, any>>;
|
||||
type MD = import('./dist/@types/astro.js').MarkdownInstance<Record<string, any>>;
|
||||
interface ExportedMarkdownModuleEntities {
|
||||
frontmatter: MD['frontmatter'];
|
||||
file: MD['file'];
|
||||
|
@ -231,7 +235,7 @@ declare module '*.mdown' {
|
|||
}
|
||||
|
||||
declare module '*.mdx' {
|
||||
type MDX = import('./dist/@types/astro').MDXInstance<Record<string, any>>;
|
||||
type MDX = import('./dist/@types/astro.js').MDXInstance<Record<string, any>>;
|
||||
|
||||
export const frontmatter: MDX['frontmatter'];
|
||||
export const file: MDX['file'];
|
||||
|
@ -244,7 +248,7 @@ declare module '*.mdx' {
|
|||
}
|
||||
|
||||
declare module 'astro:ssr-manifest' {
|
||||
export const manifest: import('./dist/@types/astro').SSRManifest;
|
||||
export const manifest: import('./dist/@types/astro.js').SSRManifest;
|
||||
}
|
||||
|
||||
// Everything below are Vite's types (apart from image types, which are in `client.d.ts`)
|
||||
|
|
|
@ -65,19 +65,19 @@ const { fallback = 'animate' } = Astro.props as Props;
|
|||
};
|
||||
|
||||
async function getHTML(href: string) {
|
||||
let res;
|
||||
try {
|
||||
res = await fetch(href);
|
||||
const res = await fetch(href);
|
||||
const html = await res.text();
|
||||
return {
|
||||
ok: res.ok,
|
||||
html,
|
||||
redirected: res.redirected ? res.url : undefined,
|
||||
// drop potential charset (+ other name/value pairs) as parser needs the mediaType
|
||||
mediaType: res.headers.get('content-type')?.replace(/;.*$/, ''),
|
||||
};
|
||||
} catch (err) {
|
||||
return { ok: false };
|
||||
}
|
||||
const html = await res.text();
|
||||
return {
|
||||
ok: res.ok,
|
||||
html,
|
||||
redirected: res.redirected ? res.url : undefined,
|
||||
contentType: res.headers.get('content-type'),
|
||||
};
|
||||
}
|
||||
|
||||
function getFallback(): Fallback {
|
||||
|
@ -126,13 +126,13 @@ const { fallback = 'animate' } = Astro.props as Props;
|
|||
|
||||
// A noop element used to prevent styles from being removed
|
||||
if (import.meta.env.DEV) {
|
||||
var noopEl: string | undefined = document.createElement('div');
|
||||
var noopEl = document.createElement('div');
|
||||
}
|
||||
|
||||
async function updateDOM(doc: Document, loc: URL, state?: State, fallback?: Fallback) {
|
||||
// Check for a head element that should persist, either because it has the data
|
||||
// attribute or is a link el.
|
||||
const persistedHeadElement = (el: Element): Element | null => {
|
||||
const persistedHeadElement = (el: HTMLElement): Element | null => {
|
||||
const id = el.getAttribute(PERSIST_ATTR);
|
||||
const newEl = id && doc.head.querySelector(`[${PERSIST_ATTR}="${id}"]`);
|
||||
if (newEl) {
|
||||
|
@ -189,7 +189,7 @@ const { fallback = 'animate' } = Astro.props as Props;
|
|||
|
||||
// Swap head
|
||||
for (const el of Array.from(document.head.children)) {
|
||||
const newEl = persistedHeadElement(el);
|
||||
const newEl = persistedHeadElement(el as HTMLElement);
|
||||
// If the element exists in the document already, remove it
|
||||
// from the new document and leave the current node alone
|
||||
if (newEl) {
|
||||
|
@ -290,16 +290,16 @@ const { fallback = 'animate' } = Astro.props as Props;
|
|||
async function navigate(dir: Direction, loc: URL, state?: State) {
|
||||
let finished: Promise<void>;
|
||||
const href = loc.href;
|
||||
const { html, ok, contentType, redirected } = await getHTML(href);
|
||||
const { html, ok, mediaType, redirected } = await getHTML(href);
|
||||
// if there was a redirection, show the final URL in the browser's address bar
|
||||
redirected && (loc = new URL(redirected));
|
||||
// If there is a problem fetching the new page, just do an MPA navigation to it.
|
||||
if (!ok || contentType !== 'text/html') {
|
||||
if (!ok || !(mediaType === 'text/html' || mediaType === 'application/xhtml+xml')) {
|
||||
location.href = href;
|
||||
return;
|
||||
}
|
||||
|
||||
const doc = parser.parseFromString(html, contentType);
|
||||
const doc = parser.parseFromString(html, mediaType);
|
||||
if (!doc.querySelector('[name="astro-view-transitions-enabled"]')) {
|
||||
location.href = href;
|
||||
return;
|
||||
|
|
7
packages/astro/content-types.template.d.ts
vendored
7
packages/astro/content-types.template.d.ts
vendored
|
@ -12,7 +12,12 @@ declare module 'astro:content' {
|
|||
export { z } from 'astro/zod';
|
||||
|
||||
type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
|
||||
export type CollectionEntry<C extends keyof AnyEntryMap> = Flatten<AnyEntryMap[C]>;
|
||||
|
||||
export type CollectionKey = keyof AnyEntryMap;
|
||||
export type CollectionEntry<C extends CollectionKey> = Flatten<AnyEntryMap[C]>;
|
||||
|
||||
export type ContentCollectionKey = keyof ContentEntryMap;
|
||||
export type DataCollectionKey = keyof DataEntryMap;
|
||||
|
||||
// This needs to be in sync with ImageMetadata
|
||||
export type ImageFunction = () => import('astro/zod').ZodObject<{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "astro",
|
||||
"version": "3.0.13",
|
||||
"version": "3.1.0",
|
||||
"description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
|
||||
"type": "module",
|
||||
"author": "withastro",
|
||||
|
@ -157,6 +157,7 @@
|
|||
"p-limit": "^4.0.0",
|
||||
"path-to-regexp": "^6.2.1",
|
||||
"preferred-pm": "^3.1.2",
|
||||
"probe-image-size": "^7.2.3",
|
||||
"prompts": "^2.4.2",
|
||||
"rehype": "^12.0.1",
|
||||
"resolve": "^1.22.4",
|
||||
|
@ -197,6 +198,7 @@
|
|||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/mime": "^3.0.1",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@types/probe-image-size": "^7.2.0",
|
||||
"@types/prompts": "^2.4.4",
|
||||
"@types/resolve": "^1.20.2",
|
||||
"@types/send": "^0.17.1",
|
||||
|
|
|
@ -13,16 +13,16 @@ import type { AddressInfo } from 'node:net';
|
|||
import type * as rollup from 'rollup';
|
||||
import type { TsConfigJson } from 'tsconfig-resolver';
|
||||
import type * as vite from 'vite';
|
||||
import type { RemotePattern } from '../assets/utils/remotePattern';
|
||||
import type { SerializedSSRManifest } from '../core/app/types';
|
||||
import type { PageBuildData } from '../core/build/types';
|
||||
import type { AstroConfigType } from '../core/config';
|
||||
import type { AstroTimer } from '../core/config/timer';
|
||||
import type { AstroCookies } from '../core/cookies';
|
||||
import type { RemotePattern } from '../assets/utils/remotePattern.js';
|
||||
import type { SerializedSSRManifest } from '../core/app/types.js';
|
||||
import type { PageBuildData } from '../core/build/types.js';
|
||||
import type { AstroConfigType } from '../core/config/index.js';
|
||||
import type { AstroTimer } from '../core/config/timer.js';
|
||||
import type { AstroCookies } from '../core/cookies/index.js';
|
||||
import type { ResponseWithEncoding } from '../core/endpoint/index.js';
|
||||
import type { AstroIntegrationLogger, Logger, LoggerLevel } from '../core/logger/core';
|
||||
import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server';
|
||||
import type { OmitIndexSignature, Simplify } from '../type-utils';
|
||||
import type { AstroIntegrationLogger, Logger, LoggerLevel } from '../core/logger/core.js';
|
||||
import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server/index.js';
|
||||
import type { OmitIndexSignature, Simplify } from '../type-utils.js';
|
||||
import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js';
|
||||
|
||||
export { type AstroIntegrationLogger };
|
||||
|
@ -39,7 +39,7 @@ export type {
|
|||
ExternalImageService,
|
||||
ImageService,
|
||||
LocalImageService,
|
||||
} from '../assets/services/service';
|
||||
} from '../assets/services/service.js';
|
||||
export type {
|
||||
GetImageResult,
|
||||
ImageInputFormat,
|
||||
|
@ -48,10 +48,10 @@ export type {
|
|||
ImageQuality,
|
||||
ImageQualityPreset,
|
||||
ImageTransform,
|
||||
} from '../assets/types';
|
||||
export type { RemotePattern } from '../assets/utils/remotePattern';
|
||||
export type { SSRManifest } from '../core/app/types';
|
||||
export type { AstroCookies } from '../core/cookies';
|
||||
} from '../assets/types.js';
|
||||
export type { RemotePattern } from '../assets/utils/remotePattern.js';
|
||||
export type { SSRManifest } from '../core/app/types.js';
|
||||
export type { AstroCookies } from '../core/cookies/index.js';
|
||||
|
||||
export interface AstroBuiltinProps {
|
||||
'client:load'?: boolean;
|
||||
|
@ -974,6 +974,28 @@ export interface AstroUserConfig {
|
|||
* @name Image Options
|
||||
*/
|
||||
image?: {
|
||||
/**
|
||||
* @docs
|
||||
* @name image.endpoint
|
||||
* @type {string}
|
||||
* @default `undefined`
|
||||
* @version 3.1.0
|
||||
* @description
|
||||
* Set the endpoint to use for image optimization in dev and SSR. Set to `undefined` to use the default endpoint.
|
||||
*
|
||||
* The endpoint will always be injected at `/_image`.
|
||||
*
|
||||
* ```js
|
||||
* {
|
||||
* image: {
|
||||
* // Example: Use a custom image endpoint
|
||||
* endpoint: './src/image-endpoint.ts',
|
||||
* },
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
endpoint?: string;
|
||||
|
||||
/**
|
||||
* @docs
|
||||
* @name image.service
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import fs, { readFileSync } from 'node:fs';
|
||||
import { basename, join } from 'node:path/posix';
|
||||
import type { BuildPipeline } from '../../core/build/buildPipeline';
|
||||
import type { BuildPipeline } from '../../core/build/buildPipeline.js';
|
||||
import { prependForwardSlash } from '../../core/path.js';
|
||||
import { isServerLikeOutput } from '../../prerender/utils.js';
|
||||
import { getConfiguredImageService, isESMImportedImage } from '../internal.js';
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
export const VIRTUAL_MODULE_ID = 'astro:assets';
|
||||
export const VIRTUAL_SERVICE_ID = 'virtual:image-service';
|
||||
export const VALID_INPUT_FORMATS = [
|
||||
// TODO: `image-size` does not support the following formats, so users can't import them.
|
||||
// However, it would be immensely useful to add, for three reasons:
|
||||
// - `heic` and `heif` are common formats, especially among Apple users.
|
||||
// - AVIF is a common format on the web that's bound to become more and more common.
|
||||
// - It's totally reasonable for an user's provided image service to want to support more image types.
|
||||
//'heic',
|
||||
//'heif',
|
||||
//'avif',
|
||||
'jpeg',
|
||||
'jpg',
|
||||
'png',
|
||||
|
@ -16,6 +8,7 @@ export const VALID_INPUT_FORMATS = [
|
|||
'webp',
|
||||
'gif',
|
||||
'svg',
|
||||
'avif',
|
||||
] as const;
|
||||
/**
|
||||
* Valid formats that our base services support.
|
||||
|
@ -29,5 +22,6 @@ export const VALID_SUPPORTED_FORMATS = [
|
|||
'webp',
|
||||
'gif',
|
||||
'svg',
|
||||
'avif',
|
||||
] as const;
|
||||
export const VALID_OUTPUT_FORMATS = ['avif', 'png', 'webp', 'jpeg', 'jpg', 'svg'] as const;
|
||||
|
|
|
@ -11,10 +11,12 @@ import type {
|
|||
import { matchHostname, matchPattern } from './utils/remotePattern.js';
|
||||
|
||||
export function injectImageEndpoint(settings: AstroSettings) {
|
||||
const endpointEntrypoint = settings.config.image.endpoint ?? 'astro/assets/image-endpoint';
|
||||
|
||||
// TODO: Add a setting to disable the image endpoint
|
||||
settings.injectedRoutes.push({
|
||||
pattern: '/_image',
|
||||
entryPoint: 'astro/assets/image-endpoint',
|
||||
entryPoint: endpointEntrypoint,
|
||||
prerender: false,
|
||||
});
|
||||
|
||||
|
@ -77,12 +79,12 @@ export async function getImage(
|
|||
|
||||
const service = await getConfiguredImageService();
|
||||
|
||||
// If the user inlined an import, something fairly common especially in MDX, await it for them
|
||||
// If the user inlined an import, something fairly common especially in MDX, or passed a function that returns an Image, await it for them
|
||||
const resolvedOptions: ImageTransform = {
|
||||
...options,
|
||||
src:
|
||||
typeof options.src === 'object' && 'then' in options.src
|
||||
? (await options.src).default
|
||||
? (await options.src).default ?? (await options.src)
|
||||
: options.src,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { AstroConfig } from '../../@types/astro.js';
|
||||
import { AstroError, AstroErrorData } from '../../core/errors/index.js';
|
||||
import { joinPaths } from '../../core/path.js';
|
||||
import { isRemotePath, joinPaths } from '../../core/path.js';
|
||||
import { VALID_SUPPORTED_FORMATS } from '../consts.js';
|
||||
import { isESMImportedImage, isRemoteAllowed } from '../internal.js';
|
||||
import type { ImageOutputFormat, ImageTransform } from '../types.js';
|
||||
|
@ -126,13 +126,20 @@ export const baseService: Omit<LocalImageService, 'transform'> = {
|
|||
if (!options.src || (typeof options.src !== 'string' && typeof options.src !== 'object')) {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.ExpectedImage,
|
||||
message: AstroErrorData.ExpectedImage.message(JSON.stringify(options.src)),
|
||||
message: AstroErrorData.ExpectedImage.message(
|
||||
JSON.stringify(options.src),
|
||||
typeof options.src,
|
||||
JSON.stringify(options, (_, v) => (v === undefined ? null : v))
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (!isESMImportedImage(options.src)) {
|
||||
// User passed an `/@fs/` path instead of the full image.
|
||||
if (options.src.startsWith('/@fs/')) {
|
||||
// User passed an `/@fs/` path or a filesystem path instead of the full image.
|
||||
if (
|
||||
options.src.startsWith('/@fs/') ||
|
||||
(!isRemotePath(options.src) && !options.src.startsWith('/'))
|
||||
) {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.LocalImageUsedWrongly,
|
||||
message: AstroErrorData.LocalImageUsedWrongly.message(options.src),
|
||||
|
|
|
@ -33,7 +33,7 @@ export interface RotateOptions {
|
|||
}
|
||||
|
||||
// MozJPEG
|
||||
import type { MozJPEGModule as MozJPEGEncodeModule } from './mozjpeg/mozjpeg_enc'
|
||||
import type { MozJPEGModule as MozJPEGEncodeModule } from './mozjpeg/mozjpeg_enc.js'
|
||||
import mozDec from './mozjpeg/mozjpeg_node_dec.js'
|
||||
import mozDecWasm from './mozjpeg/mozjpeg_node_dec.wasm.js'
|
||||
|
||||
|
@ -41,7 +41,7 @@ import mozEnc from './mozjpeg/mozjpeg_node_enc.js'
|
|||
import mozEncWasm from './mozjpeg/mozjpeg_node_enc.wasm.js'
|
||||
|
||||
// WebP
|
||||
import type { WebPModule as WebPEncodeModule } from './webp/webp_enc'
|
||||
import type { WebPModule as WebPEncodeModule } from './webp/webp_enc.js'
|
||||
import webpDec from './webp/webp_node_dec.js'
|
||||
import webpDecWasm from './webp/webp_node_dec.wasm.js'
|
||||
|
||||
|
@ -49,7 +49,7 @@ import webpEnc from './webp/webp_node_enc.js'
|
|||
import webpEncWasm from './webp/webp_node_enc.wasm.js'
|
||||
|
||||
// AVIF
|
||||
import type { AVIFModule as AVIFEncodeModule } from './avif/avif_enc'
|
||||
import type { AVIFModule as AVIFEncodeModule } from './avif/avif_enc.js'
|
||||
import avifDec from './avif/avif_node_dec.js'
|
||||
import avifDecWasm from './avif/avif_node_dec.wasm.js'
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import probe from 'probe-image-size';
|
||||
import type { ImageInputFormat, ImageMetadata } from '../types.js';
|
||||
import imageSize from '../vendor/image-size/index.js';
|
||||
|
||||
export async function imageMetadata(data: Buffer): Promise<Omit<ImageMetadata, 'src'> | undefined> {
|
||||
const { width, height, type, orientation } = imageSize(data);
|
||||
const result = probe.sync(data);
|
||||
if (result === null) {
|
||||
throw new Error('Failed to probe image size.');
|
||||
}
|
||||
|
||||
const { width, height, type, orientation } = result;
|
||||
const isPortrait = (orientation || 0) >= 5;
|
||||
|
||||
if (!width || !height || !type) {
|
||||
|
|
3
packages/astro/src/assets/vendor/README.md
vendored
3
packages/astro/src/assets/vendor/README.md
vendored
|
@ -1,3 +0,0 @@
|
|||
Vendored version of `image-size` and `queue` because we had issues with the CJS nature of those packages.
|
||||
|
||||
Should hopefully be fixed by https://github.com/image-size/image-size/pull/370
|
|
@ -1,9 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2017 Aditya Yadav, http://netroy.in
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,30 +0,0 @@
|
|||
import { typeHandlers, type imageType } from './types.js'
|
||||
|
||||
const keys = Object.keys(typeHandlers) as imageType[]
|
||||
|
||||
// This map helps avoid validating for every single image type
|
||||
const firstBytes: { [byte: number]: imageType } = {
|
||||
0x38: 'psd',
|
||||
0x42: 'bmp',
|
||||
0x44: 'dds',
|
||||
0x47: 'gif',
|
||||
0x49: 'tiff',
|
||||
0x4d: 'tiff',
|
||||
0x52: 'webp',
|
||||
0x69: 'icns',
|
||||
0x89: 'png',
|
||||
0xff: 'jpg'
|
||||
}
|
||||
|
||||
export function detector(buffer: Buffer): imageType | undefined {
|
||||
const byte = buffer[0]
|
||||
if (byte in firstBytes) {
|
||||
const type = firstBytes[byte]
|
||||
if (type && typeHandlers[type].validate(buffer)) {
|
||||
return type
|
||||
}
|
||||
}
|
||||
|
||||
const finder = (key: imageType) => typeHandlers[key].validate(buffer)
|
||||
return keys.find(finder)
|
||||
}
|
146
packages/astro/src/assets/vendor/image-size/index.ts
vendored
146
packages/astro/src/assets/vendor/image-size/index.ts
vendored
|
@ -1,146 +0,0 @@
|
|||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import Queue from "../queue/queue.js";
|
||||
import { detector } from "./detector.js";
|
||||
import { typeHandlers, type imageType } from "./types.js";
|
||||
import type { ISizeCalculationResult } from "./types/interface.js";
|
||||
|
||||
type CallbackFn = (e: Error | null, r?: ISizeCalculationResult) => void;
|
||||
|
||||
// Maximum buffer size, with a default of 512 kilobytes.
|
||||
// TO-DO: make this adaptive based on the initial signature of the image
|
||||
const MaxBufferSize = 512 * 1024;
|
||||
|
||||
// This queue is for async `fs` operations, to avoid reaching file-descriptor limits
|
||||
const queue = new Queue({ concurrency: 100, autostart: true });
|
||||
|
||||
interface Options {
|
||||
disabledFS: boolean;
|
||||
disabledTypes: imageType[];
|
||||
}
|
||||
|
||||
const globalOptions: Options = {
|
||||
disabledFS: false,
|
||||
disabledTypes: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* Return size information based on a buffer
|
||||
*
|
||||
* @param {Buffer} buffer
|
||||
* @param {String} filepath
|
||||
* @returns {Object}
|
||||
*/
|
||||
function lookup(buffer: Buffer, filepath?: string): ISizeCalculationResult {
|
||||
// detect the file type.. don't rely on the extension
|
||||
const type = detector(buffer);
|
||||
|
||||
if (typeof type !== "undefined") {
|
||||
if (globalOptions.disabledTypes.indexOf(type) > -1) {
|
||||
throw new TypeError("disabled file type: " + type);
|
||||
}
|
||||
|
||||
// find an appropriate handler for this file type
|
||||
if (type in typeHandlers) {
|
||||
const size = typeHandlers[type].calculate(buffer, filepath);
|
||||
if (size !== undefined) {
|
||||
size.type = type;
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// throw up, if we don't understand the file
|
||||
throw new TypeError(
|
||||
"unsupported file type: " + type + " (file: " + filepath + ")"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a file into a buffer.
|
||||
* @param {String} filepath
|
||||
* @returns {Promise<Buffer>}
|
||||
*/
|
||||
async function asyncFileToBuffer(filepath: string): Promise<Buffer> {
|
||||
const handle = await fs.promises.open(filepath, "r");
|
||||
const { size } = await handle.stat();
|
||||
if (size <= 0) {
|
||||
await handle.close();
|
||||
throw new Error("Empty file");
|
||||
}
|
||||
const bufferSize = Math.min(size, MaxBufferSize);
|
||||
const buffer = Buffer.alloc(bufferSize);
|
||||
await handle.read(buffer, 0, bufferSize, 0);
|
||||
await handle.close();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously reads a file into a buffer, blocking the nodejs process.
|
||||
*
|
||||
* @param {String} filepath
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
function syncFileToBuffer(filepath: string): Buffer {
|
||||
// read from the file, synchronously
|
||||
const descriptor = fs.openSync(filepath, "r");
|
||||
const { size } = fs.fstatSync(descriptor);
|
||||
if (size <= 0) {
|
||||
fs.closeSync(descriptor);
|
||||
throw new Error("Empty file");
|
||||
}
|
||||
const bufferSize = Math.min(size, MaxBufferSize);
|
||||
const buffer = Buffer.alloc(bufferSize);
|
||||
fs.readSync(descriptor, buffer, 0, bufferSize, 0);
|
||||
fs.closeSync(descriptor);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
export default imageSize;
|
||||
export function imageSize(input: Buffer | string): ISizeCalculationResult;
|
||||
export function imageSize(input: string, callback: CallbackFn): void;
|
||||
|
||||
/**
|
||||
* @param {Buffer|string} input - buffer or relative/absolute path of the image file
|
||||
* @param {Function=} [callback] - optional function for async detection
|
||||
*/
|
||||
export function imageSize(
|
||||
input: Buffer | string,
|
||||
callback?: CallbackFn
|
||||
): ISizeCalculationResult | void {
|
||||
// Handle buffer input
|
||||
if (Buffer.isBuffer(input)) {
|
||||
return lookup(input);
|
||||
}
|
||||
|
||||
// input should be a string at this point
|
||||
if (typeof input !== "string" || globalOptions.disabledFS) {
|
||||
throw new TypeError("invalid invocation. input should be a Buffer");
|
||||
}
|
||||
|
||||
// resolve the file path
|
||||
const filepath = path.resolve(input);
|
||||
if (typeof callback === "function") {
|
||||
queue.push(() =>
|
||||
asyncFileToBuffer(filepath)
|
||||
.then((buffer) =>
|
||||
process.nextTick(callback, null, lookup(buffer, filepath))
|
||||
)
|
||||
.catch(callback)
|
||||
);
|
||||
} else {
|
||||
const buffer = syncFileToBuffer(filepath);
|
||||
return lookup(buffer, filepath);
|
||||
}
|
||||
}
|
||||
|
||||
export const disableFS = (v: boolean): void => {
|
||||
globalOptions.disabledFS = v;
|
||||
};
|
||||
export const disableTypes = (types: imageType[]): void => {
|
||||
globalOptions.disabledTypes = types;
|
||||
};
|
||||
export const setConcurrency = (c: number): void => {
|
||||
queue.concurrency = c;
|
||||
};
|
||||
export const types = Object.keys(typeHandlers);
|
|
@ -1,10 +0,0 @@
|
|||
type Bits = 16 | 32
|
||||
type MethodName = 'readUInt16BE' | 'readUInt16LE' | 'readUInt32BE' | 'readUInt32LE'
|
||||
|
||||
// Abstract reading multi-byte unsigned integers
|
||||
export function readUInt(buffer: Buffer, bits: Bits, offset: number, isBigEndian: boolean): number {
|
||||
offset = offset || 0
|
||||
const endian = isBigEndian ? 'BE' : 'LE'
|
||||
const methodName: MethodName = ('readUInt' + bits + endian) as MethodName
|
||||
return buffer[methodName].call(buffer, offset)
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
// load all available handlers explicitely for browserify support
|
||||
import { BMP } from './types/bmp.js'
|
||||
import { CUR } from './types/cur.js'
|
||||
import { DDS } from './types/dds.js'
|
||||
import { GIF } from './types/gif.js'
|
||||
import { ICNS } from './types/icns.js'
|
||||
import { ICO } from './types/ico.js'
|
||||
import { J2C } from './types/j2c.js'
|
||||
import { JP2 } from './types/jp2.js'
|
||||
import { JPG } from './types/jpg.js'
|
||||
import { KTX } from './types/ktx.js'
|
||||
import { PNG } from './types/png.js'
|
||||
import { PNM } from './types/pnm.js'
|
||||
import { PSD } from './types/psd.js'
|
||||
import { SVG } from './types/svg.js'
|
||||
import { TIFF } from './types/tiff.js'
|
||||
import { WEBP } from './types/webp.js'
|
||||
|
||||
export const typeHandlers = {
|
||||
bmp: BMP,
|
||||
cur: CUR,
|
||||
dds: DDS,
|
||||
gif: GIF,
|
||||
icns: ICNS,
|
||||
ico: ICO,
|
||||
j2c: J2C,
|
||||
jp2: JP2,
|
||||
jpg: JPG,
|
||||
ktx: KTX,
|
||||
png: PNG,
|
||||
pnm: PNM,
|
||||
psd: PSD,
|
||||
svg: SVG,
|
||||
tiff: TIFF,
|
||||
webp: WEBP,
|
||||
}
|
||||
|
||||
export type imageType = keyof typeof typeHandlers
|
|
@ -1,14 +0,0 @@
|
|||
import type { IImage } from './interface'
|
||||
|
||||
export const BMP: IImage = {
|
||||
validate(buffer) {
|
||||
return ('BM' === buffer.toString('ascii', 0, 2))
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
return {
|
||||
height: Math.abs(buffer.readInt32LE(22)),
|
||||
width: buffer.readUInt32LE(18)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
import { ICO } from './ico.js'
|
||||
import type { IImage } from './interface'
|
||||
|
||||
const TYPE_CURSOR = 2
|
||||
export const CUR: IImage = {
|
||||
validate(buffer) {
|
||||
if (buffer.readUInt16LE(0) !== 0) {
|
||||
return false
|
||||
}
|
||||
return buffer.readUInt16LE(2) === TYPE_CURSOR
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
return ICO.calculate(buffer)
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import type { IImage } from './interface'
|
||||
|
||||
export const DDS: IImage = {
|
||||
validate(buffer) {
|
||||
return buffer.readUInt32LE(0) === 0x20534444
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
return {
|
||||
height: buffer.readUInt32LE(12),
|
||||
width: buffer.readUInt32LE(16)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
import type { IImage } from './interface'
|
||||
|
||||
const gifRegexp = /^GIF8[79]a/
|
||||
export const GIF: IImage = {
|
||||
validate(buffer) {
|
||||
const signature = buffer.toString('ascii', 0, 6)
|
||||
return (gifRegexp.test(signature))
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
return {
|
||||
height: buffer.readUInt16LE(8),
|
||||
width: buffer.readUInt16LE(6)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
import type { IImage, ISize } from './interface'
|
||||
|
||||
/**
|
||||
* ICNS Header
|
||||
*
|
||||
* | Offset | Size | Purpose |
|
||||
* | 0 | 4 | Magic literal, must be "icns" (0x69, 0x63, 0x6e, 0x73) |
|
||||
* | 4 | 4 | Length of file, in bytes, msb first. |
|
||||
*
|
||||
*/
|
||||
const SIZE_HEADER = 4 + 4 // 8
|
||||
const FILE_LENGTH_OFFSET = 4 // MSB => BIG ENDIAN
|
||||
|
||||
/**
|
||||
* Image Entry
|
||||
*
|
||||
* | Offset | Size | Purpose |
|
||||
* | 0 | 4 | Icon type, see OSType below. |
|
||||
* | 4 | 4 | Length of data, in bytes (including type and length), msb first. |
|
||||
* | 8 | n | Icon data |
|
||||
*/
|
||||
const ENTRY_LENGTH_OFFSET = 4 // MSB => BIG ENDIAN
|
||||
|
||||
const ICON_TYPE_SIZE: {[key: string]: number} = {
|
||||
ICON: 32,
|
||||
'ICN#': 32,
|
||||
// m => 16 x 16
|
||||
'icm#': 16,
|
||||
icm4: 16,
|
||||
icm8: 16,
|
||||
// s => 16 x 16
|
||||
'ics#': 16,
|
||||
ics4: 16,
|
||||
ics8: 16,
|
||||
is32: 16,
|
||||
s8mk: 16,
|
||||
icp4: 16,
|
||||
// l => 32 x 32
|
||||
icl4: 32,
|
||||
icl8: 32,
|
||||
il32: 32,
|
||||
l8mk: 32,
|
||||
icp5: 32,
|
||||
ic11: 32,
|
||||
// h => 48 x 48
|
||||
ich4: 48,
|
||||
ich8: 48,
|
||||
ih32: 48,
|
||||
h8mk: 48,
|
||||
// . => 64 x 64
|
||||
icp6: 64,
|
||||
ic12: 32,
|
||||
// t => 128 x 128
|
||||
it32: 128,
|
||||
t8mk: 128,
|
||||
ic07: 128,
|
||||
// . => 256 x 256
|
||||
ic08: 256,
|
||||
ic13: 256,
|
||||
// . => 512 x 512
|
||||
ic09: 512,
|
||||
ic14: 512,
|
||||
// . => 1024 x 1024
|
||||
ic10: 1024,
|
||||
}
|
||||
|
||||
function readImageHeader(buffer: Buffer, imageOffset: number): [string, number] {
|
||||
const imageLengthOffset = imageOffset + ENTRY_LENGTH_OFFSET
|
||||
return [
|
||||
buffer.toString('ascii', imageOffset, imageLengthOffset),
|
||||
buffer.readUInt32BE(imageLengthOffset)
|
||||
]
|
||||
}
|
||||
|
||||
function getImageSize(type: string): ISize {
|
||||
const size = ICON_TYPE_SIZE[type]
|
||||
return { width: size, height: size, type }
|
||||
}
|
||||
|
||||
export const ICNS: IImage = {
|
||||
validate(buffer) {
|
||||
return ('icns' === buffer.toString('ascii', 0, 4))
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
const bufferLength = buffer.length
|
||||
const fileLength = buffer.readUInt32BE(FILE_LENGTH_OFFSET)
|
||||
let imageOffset = SIZE_HEADER
|
||||
|
||||
let imageHeader = readImageHeader(buffer, imageOffset)
|
||||
let imageSize = getImageSize(imageHeader[0])
|
||||
imageOffset += imageHeader[1]
|
||||
|
||||
if (imageOffset === fileLength) {
|
||||
return imageSize
|
||||
}
|
||||
|
||||
const result = {
|
||||
height: imageSize.height,
|
||||
images: [imageSize],
|
||||
width: imageSize.width
|
||||
}
|
||||
|
||||
while (imageOffset < fileLength && imageOffset < bufferLength) {
|
||||
imageHeader = readImageHeader(buffer, imageOffset)
|
||||
imageSize = getImageSize(imageHeader[0])
|
||||
imageOffset += imageHeader[1]
|
||||
result.images.push(imageSize)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
import type { IImage, ISize, ISizeCalculationResult } from './interface'
|
||||
|
||||
const TYPE_ICON = 1
|
||||
|
||||
/**
|
||||
* ICON Header
|
||||
*
|
||||
* | Offset | Size | Purpose |
|
||||
* | 0 | 2 | Reserved. Must always be 0. |
|
||||
* | 2 | 2 | Image type: 1 for icon (.ICO) image, 2 for cursor (.CUR) image. Other values are invalid. |
|
||||
* | 4 | 2 | Number of images in the file. |
|
||||
*
|
||||
*/
|
||||
const SIZE_HEADER = 2 + 2 + 2 // 6
|
||||
|
||||
/**
|
||||
* Image Entry
|
||||
*
|
||||
* | Offset | Size | Purpose |
|
||||
* | 0 | 1 | Image width in pixels. Can be any number between 0 and 255. Value 0 means width is 256 pixels. |
|
||||
* | 1 | 1 | Image height in pixels. Can be any number between 0 and 255. Value 0 means height is 256 pixels. |
|
||||
* | 2 | 1 | Number of colors in the color palette. Should be 0 if the image does not use a color palette. |
|
||||
* | 3 | 1 | Reserved. Should be 0. |
|
||||
* | 4 | 2 | ICO format: Color planes. Should be 0 or 1. |
|
||||
* | | | CUR format: The horizontal coordinates of the hotspot in number of pixels from the left. |
|
||||
* | 6 | 2 | ICO format: Bits per pixel. |
|
||||
* | | | CUR format: The vertical coordinates of the hotspot in number of pixels from the top. |
|
||||
* | 8 | 4 | The size of the image's data in bytes |
|
||||
* | 12 | 4 | The offset of BMP or PNG data from the beginning of the ICO/CUR file |
|
||||
*
|
||||
*/
|
||||
const SIZE_IMAGE_ENTRY = 1 + 1 + 1 + 1 + 2 + 2 + 4 + 4 // 16
|
||||
|
||||
function getSizeFromOffset(buffer: Buffer, offset: number): number {
|
||||
const value = buffer.readUInt8(offset)
|
||||
return value === 0 ? 256 : value
|
||||
}
|
||||
|
||||
function getImageSize(buffer: Buffer, imageIndex: number): ISize {
|
||||
const offset = SIZE_HEADER + (imageIndex * SIZE_IMAGE_ENTRY)
|
||||
return {
|
||||
height: getSizeFromOffset(buffer, offset + 1),
|
||||
width: getSizeFromOffset(buffer, offset)
|
||||
}
|
||||
}
|
||||
|
||||
export const ICO: IImage = {
|
||||
validate(buffer) {
|
||||
if (buffer.readUInt16LE(0) !== 0) {
|
||||
return false
|
||||
}
|
||||
return buffer.readUInt16LE(2) === TYPE_ICON
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
const nbImages = buffer.readUInt16LE(4)
|
||||
const imageSize = getImageSize(buffer, 0)
|
||||
|
||||
if (nbImages === 1) {
|
||||
return imageSize
|
||||
}
|
||||
|
||||
const imgs: ISize[] = [imageSize]
|
||||
for (let imageIndex = 1; imageIndex < nbImages; imageIndex += 1) {
|
||||
imgs.push(getImageSize(buffer, imageIndex))
|
||||
}
|
||||
|
||||
const result: ISizeCalculationResult = {
|
||||
height: imageSize.height,
|
||||
images: imgs,
|
||||
width: imageSize.width
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
export interface ISize {
|
||||
width: number | undefined
|
||||
height: number | undefined
|
||||
orientation?: number
|
||||
type?: string
|
||||
}
|
||||
|
||||
export interface ISizeCalculationResult extends ISize {
|
||||
images?: ISize[]
|
||||
}
|
||||
|
||||
export interface IImage {
|
||||
validate: (buffer: Buffer) => boolean
|
||||
calculate: (buffer: Buffer, filepath?: string) => ISizeCalculationResult
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
import type { IImage } from './interface'
|
||||
|
||||
export const J2C: IImage = {
|
||||
validate(buffer) {
|
||||
// TODO: this doesn't seem right. SIZ marker doesn't have to be right after the SOC
|
||||
return buffer.toString('hex', 0, 4) === 'ff4fff51'
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
return {
|
||||
height: buffer.readUInt32BE(12),
|
||||
width: buffer.readUInt32BE(8),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
import type { IImage, ISize } from './interface'
|
||||
|
||||
const BoxTypes = {
|
||||
ftyp: '66747970',
|
||||
ihdr: '69686472',
|
||||
jp2h: '6a703268',
|
||||
jp__: '6a502020',
|
||||
rreq: '72726571',
|
||||
xml_: '786d6c20'
|
||||
}
|
||||
|
||||
const calculateRREQLength = (box: Buffer): number => {
|
||||
const unit = box.readUInt8(0)
|
||||
let offset = 1 + (2 * unit)
|
||||
const numStdFlags = box.readUInt16BE(offset)
|
||||
const flagsLength = numStdFlags * (2 + unit)
|
||||
offset = offset + 2 + flagsLength
|
||||
const numVendorFeatures = box.readUInt16BE(offset)
|
||||
const featuresLength = numVendorFeatures * (16 + unit)
|
||||
return offset + 2 + featuresLength
|
||||
}
|
||||
|
||||
const parseIHDR = (box: Buffer): ISize => {
|
||||
return {
|
||||
height: box.readUInt32BE(4),
|
||||
width: box.readUInt32BE(8),
|
||||
}
|
||||
}
|
||||
|
||||
export const JP2: IImage = {
|
||||
validate(buffer) {
|
||||
const signature = buffer.toString('hex', 4, 8)
|
||||
const signatureLength = buffer.readUInt32BE(0)
|
||||
if (signature !== BoxTypes.jp__ || signatureLength < 1) {
|
||||
return false
|
||||
}
|
||||
|
||||
const ftypeBoxStart = signatureLength + 4
|
||||
const ftypBoxLength = buffer.readUInt32BE(signatureLength)
|
||||
const ftypBox = buffer.slice(ftypeBoxStart, ftypeBoxStart + ftypBoxLength)
|
||||
return ftypBox.toString('hex', 0, 4) === BoxTypes.ftyp
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
const signatureLength = buffer.readUInt32BE(0)
|
||||
const ftypBoxLength = buffer.readUInt16BE(signatureLength + 2)
|
||||
let offset = signatureLength + 4 + ftypBoxLength
|
||||
const nextBoxType = buffer.toString('hex', offset, offset + 4)
|
||||
switch (nextBoxType) {
|
||||
case BoxTypes.rreq:
|
||||
// WHAT ARE THESE 4 BYTES?????
|
||||
const MAGIC = 4
|
||||
offset = offset + 4 + MAGIC + calculateRREQLength(buffer.slice(offset + 4))
|
||||
return parseIHDR(buffer.slice(offset + 8, offset + 24))
|
||||
case BoxTypes.jp2h :
|
||||
return parseIHDR(buffer.slice(offset + 8, offset + 24))
|
||||
default:
|
||||
throw new TypeError('Unsupported header found: ' + buffer.toString('ascii', offset, offset + 4))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
// NOTE: we only support baseline and progressive JPGs here
|
||||
// due to the structure of the loader class, we only get a buffer
|
||||
// with a maximum size of 4096 bytes. so if the SOF marker is outside
|
||||
// if this range we can't detect the file size correctly.
|
||||
|
||||
import { readUInt } from '../readUInt.js'
|
||||
import type { IImage, ISize } from './interface'
|
||||
|
||||
const EXIF_MARKER = '45786966'
|
||||
const APP1_DATA_SIZE_BYTES = 2
|
||||
const EXIF_HEADER_BYTES = 6
|
||||
const TIFF_BYTE_ALIGN_BYTES = 2
|
||||
const BIG_ENDIAN_BYTE_ALIGN = '4d4d'
|
||||
const LITTLE_ENDIAN_BYTE_ALIGN = '4949'
|
||||
|
||||
// Each entry is exactly 12 bytes
|
||||
const IDF_ENTRY_BYTES = 12
|
||||
const NUM_DIRECTORY_ENTRIES_BYTES = 2
|
||||
|
||||
function isEXIF(buffer: Buffer): boolean {
|
||||
return (buffer.toString('hex', 2, 6) === EXIF_MARKER)
|
||||
}
|
||||
|
||||
function extractSize(buffer: Buffer, index: number): ISize {
|
||||
return {
|
||||
height : buffer.readUInt16BE(index),
|
||||
width : buffer.readUInt16BE(index + 2)
|
||||
}
|
||||
}
|
||||
|
||||
function extractOrientation(exifBlock: Buffer, isBigEndian: boolean) {
|
||||
// TODO: assert that this contains 0x002A
|
||||
// let STATIC_MOTOROLA_TIFF_HEADER_BYTES = 2
|
||||
// let TIFF_IMAGE_FILE_DIRECTORY_BYTES = 4
|
||||
|
||||
// TODO: derive from TIFF_IMAGE_FILE_DIRECTORY_BYTES
|
||||
const idfOffset = 8
|
||||
|
||||
// IDF osset works from right after the header bytes
|
||||
// (so the offset includes the tiff byte align)
|
||||
const offset = EXIF_HEADER_BYTES + idfOffset
|
||||
|
||||
const idfDirectoryEntries = readUInt(exifBlock, 16, offset, isBigEndian)
|
||||
|
||||
for (let directoryEntryNumber = 0; directoryEntryNumber < idfDirectoryEntries; directoryEntryNumber++) {
|
||||
const start = offset + NUM_DIRECTORY_ENTRIES_BYTES + (directoryEntryNumber * IDF_ENTRY_BYTES)
|
||||
const end = start + IDF_ENTRY_BYTES
|
||||
|
||||
// Skip on corrupt EXIF blocks
|
||||
if (start > exifBlock.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const block = exifBlock.slice(start, end)
|
||||
const tagNumber = readUInt(block, 16, 0, isBigEndian)
|
||||
|
||||
// 0x0112 (decimal: 274) is the `orientation` tag ID
|
||||
if (tagNumber === 274) {
|
||||
const dataFormat = readUInt(block, 16, 2, isBigEndian)
|
||||
if (dataFormat !== 3) {
|
||||
return
|
||||
}
|
||||
|
||||
// unsinged int has 2 bytes per component
|
||||
// if there would more than 4 bytes in total it's a pointer
|
||||
const numberOfComponents = readUInt(block, 32, 4, isBigEndian)
|
||||
if (numberOfComponents !== 1) {
|
||||
return
|
||||
}
|
||||
|
||||
return readUInt(block, 16, 8, isBigEndian)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validateExifBlock(buffer: Buffer, index: number) {
|
||||
// Skip APP1 Data Size
|
||||
const exifBlock = buffer.slice(APP1_DATA_SIZE_BYTES, index)
|
||||
|
||||
// Consider byte alignment
|
||||
const byteAlign = exifBlock.toString('hex', EXIF_HEADER_BYTES, EXIF_HEADER_BYTES + TIFF_BYTE_ALIGN_BYTES)
|
||||
|
||||
// Ignore Empty EXIF. Validate byte alignment
|
||||
const isBigEndian = byteAlign === BIG_ENDIAN_BYTE_ALIGN
|
||||
const isLittleEndian = byteAlign === LITTLE_ENDIAN_BYTE_ALIGN
|
||||
|
||||
if (isBigEndian || isLittleEndian) {
|
||||
return extractOrientation(exifBlock, isBigEndian)
|
||||
}
|
||||
}
|
||||
|
||||
function validateBuffer(buffer: Buffer, index: number): void {
|
||||
// index should be within buffer limits
|
||||
if (index > buffer.length) {
|
||||
throw new TypeError('Corrupt JPG, exceeded buffer limits')
|
||||
}
|
||||
// Every JPEG block must begin with a 0xFF
|
||||
if (buffer[index] !== 0xFF) {
|
||||
throw new TypeError('Invalid JPG, marker table corrupted')
|
||||
}
|
||||
}
|
||||
|
||||
export const JPG: IImage = {
|
||||
validate(buffer) {
|
||||
const SOIMarker = buffer.toString('hex', 0, 2)
|
||||
return ('ffd8' === SOIMarker)
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
// Skip 4 chars, they are for signature
|
||||
buffer = buffer.slice(4)
|
||||
|
||||
let orientation: number | undefined
|
||||
let next: number
|
||||
while (buffer.length) {
|
||||
// read length of the next block
|
||||
const i = buffer.readUInt16BE(0)
|
||||
|
||||
if (isEXIF(buffer)) {
|
||||
orientation = validateExifBlock(buffer, i)
|
||||
}
|
||||
|
||||
// ensure correct format
|
||||
validateBuffer(buffer, i)
|
||||
|
||||
// 0xFFC0 is baseline standard(SOF)
|
||||
// 0xFFC1 is baseline optimized(SOF)
|
||||
// 0xFFC2 is progressive(SOF2)
|
||||
next = buffer[i + 1]
|
||||
if (next === 0xC0 || next === 0xC1 || next === 0xC2) {
|
||||
const size = extractSize(buffer, i + 5)
|
||||
|
||||
// TODO: is orientation=0 a valid answer here?
|
||||
if (!orientation) {
|
||||
return size
|
||||
}
|
||||
|
||||
return {
|
||||
height: size.height,
|
||||
orientation,
|
||||
width: size.width
|
||||
}
|
||||
}
|
||||
|
||||
// move to the next block
|
||||
buffer = buffer.slice(i + 2)
|
||||
}
|
||||
|
||||
throw new TypeError('Invalid JPG, no size found')
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
import type { IImage } from './interface'
|
||||
|
||||
const SIGNATURE = 'KTX 11'
|
||||
|
||||
export const KTX: IImage = {
|
||||
validate(buffer) {
|
||||
return SIGNATURE === buffer.toString('ascii', 1, 7)
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
return {
|
||||
height: buffer.readUInt32LE(40),
|
||||
width: buffer.readUInt32LE(36),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
import type { IImage } from './interface'
|
||||
|
||||
const pngSignature = 'PNG\r\n\x1a\n'
|
||||
const pngImageHeaderChunkName = 'IHDR'
|
||||
|
||||
// Used to detect "fried" png's: http://www.jongware.com/pngdefry.html
|
||||
const pngFriedChunkName = 'CgBI'
|
||||
|
||||
export const PNG: IImage = {
|
||||
validate(buffer) {
|
||||
if (pngSignature === buffer.toString('ascii', 1, 8)) {
|
||||
let chunkName = buffer.toString('ascii', 12, 16)
|
||||
if (chunkName === pngFriedChunkName) {
|
||||
chunkName = buffer.toString('ascii', 28, 32)
|
||||
}
|
||||
if (chunkName !== pngImageHeaderChunkName) {
|
||||
throw new TypeError('Invalid PNG')
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
if (buffer.toString('ascii', 12, 16) === pngFriedChunkName) {
|
||||
return {
|
||||
height: buffer.readUInt32BE(36),
|
||||
width: buffer.readUInt32BE(32)
|
||||
}
|
||||
}
|
||||
return {
|
||||
height: buffer.readUInt32BE(20),
|
||||
width: buffer.readUInt32BE(16)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
import type { IImage, ISize } from './interface'
|
||||
|
||||
const PNMTypes: { [signature: string]: string } = {
|
||||
P1: 'pbm/ascii',
|
||||
P2: 'pgm/ascii',
|
||||
P3: 'ppm/ascii',
|
||||
P4: 'pbm',
|
||||
P5: 'pgm',
|
||||
P6: 'ppm',
|
||||
P7: 'pam',
|
||||
PF: 'pfm'
|
||||
}
|
||||
|
||||
const Signatures = Object.keys(PNMTypes)
|
||||
|
||||
type Handler = (type: string[]) => ISize
|
||||
const handlers: { [type: string]: Handler} = {
|
||||
default: (lines) => {
|
||||
let dimensions: string[] = []
|
||||
|
||||
while (lines.length > 0) {
|
||||
const line = lines.shift()!
|
||||
if (line[0] === '#') {
|
||||
continue
|
||||
}
|
||||
dimensions = line.split(' ')
|
||||
break
|
||||
}
|
||||
|
||||
if (dimensions.length === 2) {
|
||||
return {
|
||||
height: parseInt(dimensions[1], 10),
|
||||
width: parseInt(dimensions[0], 10),
|
||||
}
|
||||
} else {
|
||||
throw new TypeError('Invalid PNM')
|
||||
}
|
||||
},
|
||||
pam: (lines) => {
|
||||
const size: { [key: string]: number } = {}
|
||||
while (lines.length > 0) {
|
||||
const line = lines.shift()!
|
||||
if (line.length > 16 || line.charCodeAt(0) > 128) {
|
||||
continue
|
||||
}
|
||||
const [key, value] = line.split(' ')
|
||||
if (key && value) {
|
||||
size[key.toLowerCase()] = parseInt(value, 10)
|
||||
}
|
||||
if (size.height && size.width) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (size.height && size.width) {
|
||||
return {
|
||||
height: size.height,
|
||||
width: size.width
|
||||
}
|
||||
} else {
|
||||
throw new TypeError('Invalid PAM')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const PNM: IImage = {
|
||||
validate(buffer) {
|
||||
const signature = buffer.toString('ascii', 0, 2)
|
||||
return Signatures.includes(signature)
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
const signature = buffer.toString('ascii', 0, 2)
|
||||
const type = PNMTypes[signature]
|
||||
// TODO: this probably generates garbage. move to a stream based parser
|
||||
const lines = buffer.toString('ascii', 3).split(/[\r\n]+/)
|
||||
const handler = handlers[type] || handlers.default
|
||||
return handler(lines)
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
import type { IImage } from './interface'
|
||||
|
||||
export const PSD: IImage = {
|
||||
validate(buffer) {
|
||||
return ('8BPS' === buffer.toString('ascii', 0, 4))
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
return {
|
||||
height: buffer.readUInt32BE(14),
|
||||
width: buffer.readUInt32BE(18)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
import type { IImage, ISize } from './interface'
|
||||
|
||||
interface IAttributes {
|
||||
width: number | null
|
||||
height: number | null
|
||||
viewbox?: IAttributes | null
|
||||
}
|
||||
|
||||
const svgReg = /<svg\s([^>"']|"[^"]*"|'[^']*')*>/
|
||||
|
||||
const extractorRegExps = {
|
||||
height: /\sheight=(['"])([^%]+?)\1/,
|
||||
root: svgReg,
|
||||
viewbox: /\sviewBox=(['"])(.+?)\1/i,
|
||||
width: /\swidth=(['"])([^%]+?)\1/,
|
||||
}
|
||||
|
||||
const INCH_CM = 2.54
|
||||
const units: { [unit: string]: number } = {
|
||||
in: 96,
|
||||
cm: 96 / INCH_CM,
|
||||
em: 16,
|
||||
ex: 8,
|
||||
m: 96 / INCH_CM * 100,
|
||||
mm: 96 / INCH_CM / 10,
|
||||
pc: 96 / 72 / 12,
|
||||
pt: 96 / 72,
|
||||
px: 1
|
||||
}
|
||||
|
||||
const unitsReg = new RegExp(`^([0-9.]+(?:e\\d+)?)(${Object.keys(units).join('|')})?$`)
|
||||
|
||||
function parseLength(len: string) {
|
||||
const m = unitsReg.exec(len)
|
||||
if (!m) {
|
||||
return undefined
|
||||
}
|
||||
return Math.round(Number(m[1]) * (units[m[2]] || 1))
|
||||
}
|
||||
|
||||
function parseViewbox(viewbox: string): IAttributes {
|
||||
const bounds = viewbox.split(' ')
|
||||
return {
|
||||
height: parseLength(bounds[3])!,
|
||||
width: parseLength(bounds[2])!
|
||||
}
|
||||
}
|
||||
|
||||
function parseAttributes(root: string): IAttributes {
|
||||
const width = root.match(extractorRegExps.width)
|
||||
const height = root.match(extractorRegExps.height)
|
||||
const viewbox = root.match(extractorRegExps.viewbox)
|
||||
return {
|
||||
height: height && parseLength(height[2])!,
|
||||
viewbox: viewbox && parseViewbox(viewbox[2])!,
|
||||
width: width && parseLength(width[2])!,
|
||||
}
|
||||
}
|
||||
|
||||
function calculateByDimensions(attrs: IAttributes): ISize {
|
||||
return {
|
||||
height: attrs.height!,
|
||||
width: attrs.width!,
|
||||
}
|
||||
}
|
||||
|
||||
function calculateByViewbox(attrs: IAttributes, viewbox: IAttributes): ISize {
|
||||
const ratio = (viewbox.width!) / (viewbox.height!)
|
||||
if (attrs.width) {
|
||||
return {
|
||||
height: Math.floor(attrs.width / ratio),
|
||||
width: attrs.width,
|
||||
}
|
||||
}
|
||||
if (attrs.height) {
|
||||
return {
|
||||
height: attrs.height,
|
||||
width: Math.floor(attrs.height * ratio),
|
||||
}
|
||||
}
|
||||
return {
|
||||
height: viewbox.height!,
|
||||
width: viewbox.width!,
|
||||
}
|
||||
}
|
||||
|
||||
export const SVG: IImage = {
|
||||
validate(buffer) {
|
||||
const str = String(buffer)
|
||||
return svgReg.test(str)
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
const root = buffer.toString('utf8').match(extractorRegExps.root)
|
||||
if (root) {
|
||||
const attrs = parseAttributes(root[0])
|
||||
if (attrs.width && attrs.height) {
|
||||
return calculateByDimensions(attrs)
|
||||
}
|
||||
if (attrs.viewbox) {
|
||||
return calculateByViewbox(attrs, attrs.viewbox)
|
||||
}
|
||||
}
|
||||
throw new TypeError('Invalid SVG')
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
// based on http://www.compix.com/fileformattif.htm
|
||||
// TO-DO: support big-endian as well
|
||||
import * as fs from 'node:fs'
|
||||
import { readUInt } from '../readUInt.js'
|
||||
import type { IImage } from './interface'
|
||||
|
||||
// Read IFD (image-file-directory) into a buffer
|
||||
function readIFD(buffer: Buffer, filepath: string, isBigEndian: boolean) {
|
||||
|
||||
const ifdOffset = readUInt(buffer, 32, 4, isBigEndian)
|
||||
|
||||
// read only till the end of the file
|
||||
let bufferSize = 1024
|
||||
const fileSize = fs.statSync(filepath).size
|
||||
if (ifdOffset + bufferSize > fileSize) {
|
||||
bufferSize = fileSize - ifdOffset - 10
|
||||
}
|
||||
|
||||
// populate the buffer
|
||||
const endBuffer = Buffer.alloc(bufferSize)
|
||||
const descriptor = fs.openSync(filepath, 'r')
|
||||
fs.readSync(descriptor, endBuffer, 0, bufferSize, ifdOffset)
|
||||
fs.closeSync(descriptor)
|
||||
|
||||
return endBuffer.slice(2)
|
||||
}
|
||||
|
||||
// TIFF values seem to be messed up on Big-Endian, this helps
|
||||
function readValue(buffer: Buffer, isBigEndian: boolean): number {
|
||||
const low = readUInt(buffer, 16, 8, isBigEndian)
|
||||
const high = readUInt(buffer, 16, 10, isBigEndian)
|
||||
return (high << 16) + low
|
||||
}
|
||||
|
||||
// move to the next tag
|
||||
function nextTag(buffer: Buffer) {
|
||||
if (buffer.length > 24) {
|
||||
return buffer.slice(12)
|
||||
}
|
||||
}
|
||||
|
||||
// Extract IFD tags from TIFF metadata
|
||||
function extractTags(buffer: Buffer, isBigEndian: boolean) {
|
||||
const tags: {[key: number]: number} = {}
|
||||
|
||||
let temp: Buffer | undefined = buffer
|
||||
while (temp?.length) {
|
||||
const code = readUInt(temp, 16, 0, isBigEndian)
|
||||
const type = readUInt(temp, 16, 2, isBigEndian)
|
||||
const length = readUInt(temp, 32, 4, isBigEndian)
|
||||
|
||||
// 0 means end of IFD
|
||||
if (code === 0) {
|
||||
break
|
||||
} else {
|
||||
// 256 is width, 257 is height
|
||||
// if (code === 256 || code === 257) {
|
||||
if (length === 1 && (type === 3 || type === 4)) {
|
||||
tags[code] = readValue(temp, isBigEndian)
|
||||
}
|
||||
|
||||
// move to the next tag
|
||||
temp = nextTag(temp)
|
||||
}
|
||||
}
|
||||
|
||||
return tags
|
||||
}
|
||||
|
||||
// Test if the TIFF is Big Endian or Little Endian
|
||||
function determineEndianness(buffer: Buffer) {
|
||||
const signature = buffer.toString('ascii', 0, 2)
|
||||
if ('II' === signature) {
|
||||
return 'LE'
|
||||
} else if ('MM' === signature) {
|
||||
return 'BE'
|
||||
}
|
||||
}
|
||||
|
||||
const signatures = [
|
||||
// '492049', // currently not supported
|
||||
'49492a00', // Little endian
|
||||
'4d4d002a', // Big Endian
|
||||
// '4d4d002a', // BigTIFF > 4GB. currently not supported
|
||||
]
|
||||
|
||||
export const TIFF: IImage = {
|
||||
validate(buffer) {
|
||||
return signatures.includes(buffer.toString('hex', 0, 4))
|
||||
},
|
||||
|
||||
calculate(buffer, filepath) {
|
||||
if (!filepath) {
|
||||
throw new TypeError('Tiff doesn\'t support buffer')
|
||||
}
|
||||
|
||||
// Determine BE/LE
|
||||
const isBigEndian = determineEndianness(buffer) === 'BE'
|
||||
|
||||
// read the IFD
|
||||
const ifdBuffer = readIFD(buffer, filepath, isBigEndian)
|
||||
|
||||
// extract the tags from the IFD
|
||||
const tags = extractTags(ifdBuffer, isBigEndian)
|
||||
|
||||
const width = tags[256]
|
||||
const height = tags[257]
|
||||
|
||||
if (!width || !height) {
|
||||
throw new TypeError('Invalid Tiff. Missing tags')
|
||||
}
|
||||
|
||||
return { height, width }
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
// based on https://developers.google.com/speed/webp/docs/riff_container
|
||||
import type { IImage, ISize } from './interface'
|
||||
|
||||
function calculateExtended(buffer: Buffer): ISize {
|
||||
return {
|
||||
height: 1 + buffer.readUIntLE(7, 3),
|
||||
width: 1 + buffer.readUIntLE(4, 3)
|
||||
}
|
||||
}
|
||||
|
||||
function calculateLossless(buffer: Buffer): ISize {
|
||||
return {
|
||||
height: 1 + (((buffer[4] & 0xF) << 10) | (buffer[3] << 2) | ((buffer[2] & 0xC0) >> 6)),
|
||||
width: 1 + (((buffer[2] & 0x3F) << 8) | buffer[1])
|
||||
}
|
||||
}
|
||||
|
||||
function calculateLossy(buffer: Buffer): ISize {
|
||||
// `& 0x3fff` returns the last 14 bits
|
||||
// TO-DO: include webp scaling in the calculations
|
||||
return {
|
||||
height: buffer.readInt16LE(8) & 0x3fff,
|
||||
width: buffer.readInt16LE(6) & 0x3fff
|
||||
}
|
||||
}
|
||||
|
||||
export const WEBP: IImage = {
|
||||
validate(buffer) {
|
||||
const riffHeader = 'RIFF' === buffer.toString('ascii', 0, 4)
|
||||
const webpHeader = 'WEBP' === buffer.toString('ascii', 8, 12)
|
||||
const vp8Header = 'VP8' === buffer.toString('ascii', 12, 15)
|
||||
return (riffHeader && webpHeader && vp8Header)
|
||||
},
|
||||
|
||||
calculate(buffer) {
|
||||
const chunkHeader = buffer.toString('ascii', 12, 16)
|
||||
buffer = buffer.slice(20, 30)
|
||||
|
||||
// Extended webp stream signature
|
||||
if (chunkHeader === 'VP8X') {
|
||||
const extendedHeader = buffer[0]
|
||||
const validStart = (extendedHeader & 0xc0) === 0
|
||||
const validEnd = (extendedHeader & 0x01) === 0
|
||||
if (validStart && validEnd) {
|
||||
return calculateExtended(buffer)
|
||||
} else {
|
||||
// TODO: breaking change
|
||||
throw new TypeError('Invalid WebP')
|
||||
}
|
||||
}
|
||||
|
||||
// Lossless webp stream signature
|
||||
if (chunkHeader === 'VP8 ' && buffer[0] !== 0x2f) {
|
||||
return calculateLossy(buffer)
|
||||
}
|
||||
|
||||
// Lossy webp stream signature
|
||||
const signature = buffer.toString('hex', 3, 6)
|
||||
if (chunkHeader === 'VP8L' && signature !== '9d012a') {
|
||||
return calculateLossless(buffer)
|
||||
}
|
||||
|
||||
throw new TypeError('Invalid WebP')
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
Copyright (c) 2014 Jesse Tane <jesse.tane@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
225
packages/astro/src/assets/vendor/queue/queue.js
vendored
225
packages/astro/src/assets/vendor/queue/queue.js
vendored
|
@ -1,225 +0,0 @@
|
|||
const has = Object.prototype.hasOwnProperty
|
||||
|
||||
/**
|
||||
* Since CustomEvent is only supported in nodejs since version 19,
|
||||
* you have to create your own class instead of using CustomEvent
|
||||
* @see https://github.com/nodejs/node/issues/40678
|
||||
* */
|
||||
export class QueueEvent extends Event {
|
||||
constructor (name, detail) {
|
||||
super(name)
|
||||
this.detail = detail
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default class Queue extends EventTarget {
|
||||
constructor (options = {}) {
|
||||
super()
|
||||
const { concurrency = Infinity, timeout = 0, autostart = false, results = null } = options
|
||||
|
||||
this.concurrency = concurrency
|
||||
this.timeout = timeout
|
||||
this.autostart = autostart
|
||||
this.results = results
|
||||
this.pending = 0
|
||||
this.session = 0
|
||||
this.running = false
|
||||
this.jobs = []
|
||||
this.timers = []
|
||||
|
||||
this.addEventListener('error', this._errorHandler)
|
||||
}
|
||||
|
||||
_errorHandler(evt) {
|
||||
this.end(evt.detail.error);
|
||||
}
|
||||
|
||||
pop () {
|
||||
return this.jobs.pop()
|
||||
}
|
||||
|
||||
shift () {
|
||||
return this.jobs.shift()
|
||||
}
|
||||
|
||||
indexOf (searchElement, fromIndex) {
|
||||
return this.jobs.indexOf(searchElement, fromIndex)
|
||||
}
|
||||
|
||||
lastIndexOf (searchElement, fromIndex) {
|
||||
if (fromIndex !== undefined) { return this.jobs.lastIndexOf(searchElement, fromIndex) }
|
||||
return this.jobs.lastIndexOf(searchElement)
|
||||
}
|
||||
|
||||
slice (start, end) {
|
||||
this.jobs = this.jobs.slice(start, end)
|
||||
return this
|
||||
}
|
||||
|
||||
reverse () {
|
||||
this.jobs.reverse()
|
||||
return this
|
||||
}
|
||||
|
||||
push (...workers) {
|
||||
const methodResult = this.jobs.push(...workers)
|
||||
if (this.autostart) {
|
||||
this.start()
|
||||
}
|
||||
return methodResult
|
||||
}
|
||||
|
||||
unshift (...workers) {
|
||||
const methodResult = this.jobs.unshift(...workers)
|
||||
if (this.autostart) {
|
||||
this.start()
|
||||
}
|
||||
return methodResult
|
||||
}
|
||||
|
||||
splice (start, deleteCount, ...workers) {
|
||||
this.jobs.splice(start, deleteCount, ...workers)
|
||||
if (this.autostart) {
|
||||
this.start()
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
get length () {
|
||||
return this.pending + this.jobs.length
|
||||
}
|
||||
|
||||
start (callback) {
|
||||
let awaiter;
|
||||
|
||||
if (callback) {
|
||||
this._addCallbackToEndEvent(callback)
|
||||
} else {
|
||||
awaiter = this._createPromiseToEndEvent();
|
||||
}
|
||||
|
||||
this.running = true
|
||||
|
||||
if (this.pending >= this.concurrency) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.jobs.length === 0) {
|
||||
if (this.pending === 0) {
|
||||
this.done()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const job = this.jobs.shift()
|
||||
const session = this.session
|
||||
const timeout = (job !== undefined) && has.call(job, 'timeout') ? job.timeout : this.timeout
|
||||
let once = true
|
||||
let timeoutId = null
|
||||
let didTimeout = false
|
||||
let resultIndex = null
|
||||
|
||||
const next = (error, ...result) => {
|
||||
if (once && this.session === session) {
|
||||
once = false
|
||||
this.pending--
|
||||
if (timeoutId !== null) {
|
||||
this.timers = this.timers.filter((tID) => tID !== timeoutId)
|
||||
clearTimeout(timeoutId)
|
||||
}
|
||||
|
||||
if (error) {
|
||||
this.dispatchEvent(new QueueEvent('error', { error, job }))
|
||||
} else if (!didTimeout) {
|
||||
if (resultIndex !== null && this.results !== null) {
|
||||
this.results[resultIndex] = [...result]
|
||||
}
|
||||
this.dispatchEvent(new QueueEvent('success', { result: [...result], job }))
|
||||
}
|
||||
|
||||
if (this.session === session) {
|
||||
if (this.pending === 0 && this.jobs.length === 0) {
|
||||
this.done()
|
||||
} else if (this.running) {
|
||||
this.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
timeoutId = setTimeout(() => {
|
||||
didTimeout = true
|
||||
this.dispatchEvent(new QueueEvent('timeout', { next, job }))
|
||||
next()
|
||||
}, timeout)
|
||||
this.timers.push(timeoutId)
|
||||
}
|
||||
|
||||
if (this.results != null) {
|
||||
resultIndex = this.results.length
|
||||
this.results[resultIndex] = null
|
||||
}
|
||||
|
||||
this.pending++
|
||||
this.dispatchEvent(new QueueEvent('start', { job }))
|
||||
|
||||
const promise = job(next)
|
||||
|
||||
if (promise !== undefined && typeof promise.then === 'function') {
|
||||
promise.then(function (result) {
|
||||
return next(undefined, result)
|
||||
}).catch(function (err) {
|
||||
return next(err || true)
|
||||
})
|
||||
}
|
||||
|
||||
if (this.running && this.jobs.length > 0) {
|
||||
return this.start()
|
||||
}
|
||||
|
||||
return awaiter;
|
||||
}
|
||||
|
||||
stop () {
|
||||
this.running = false
|
||||
}
|
||||
|
||||
end (error) {
|
||||
this.clearTimers()
|
||||
this.jobs.length = 0
|
||||
this.pending = 0
|
||||
this.done(error)
|
||||
}
|
||||
|
||||
clearTimers () {
|
||||
this.timers.forEach((timer) => {
|
||||
clearTimeout(timer)
|
||||
})
|
||||
|
||||
this.timers = []
|
||||
}
|
||||
|
||||
_addCallbackToEndEvent (cb) {
|
||||
const onend = (evt) => {
|
||||
this.removeEventListener('end', onend)
|
||||
cb(evt.detail.error, this.results)
|
||||
}
|
||||
this.addEventListener('end', onend)
|
||||
}
|
||||
|
||||
_createPromiseToEndEvent() {
|
||||
return new Promise((resolve) => {
|
||||
this._addCallbackToEndEvent((error, results) => {
|
||||
resolve({ error, results });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
done (error) {
|
||||
this.session++
|
||||
this.running = false
|
||||
this.dispatchEvent(new QueueEvent('end', { error }))
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import MagicString from 'magic-string';
|
||||
import type * as vite from 'vite';
|
||||
import { normalizePath } from 'vite';
|
||||
import type { AstroPluginOptions, ImageTransform } from '../@types/astro';
|
||||
import type { AstroPluginOptions, ImageTransform } from '../@types/astro.js';
|
||||
import {
|
||||
appendForwardSlash,
|
||||
joinPaths,
|
||||
|
@ -14,7 +14,7 @@ import { hashTransform, propsToFilename } from './utils/transformToPath.js';
|
|||
|
||||
const resolvedVirtualModuleId = '\0' + VIRTUAL_MODULE_ID;
|
||||
|
||||
const assetRegex = new RegExp(`\.(${VALID_INPUT_FORMATS.join('|')})$`, 'i');
|
||||
const assetRegex = new RegExp(`\\.(${VALID_INPUT_FORMATS.join('|')})$`, 'i');
|
||||
|
||||
export default function assets({
|
||||
settings,
|
||||
|
|
|
@ -3,13 +3,11 @@ import parser from '@babel/parser';
|
|||
import traverse from '@babel/traverse';
|
||||
import * as t from '@babel/types';
|
||||
|
||||
// @ts-expect-error @babel/traverse isn't ESM and needs this trick
|
||||
export const visit = traverse.default as typeof traverse;
|
||||
export const visit = traverse.default;
|
||||
export { t };
|
||||
|
||||
export async function generate(ast: t.File) {
|
||||
// @ts-expect-error @babel/generator isn't ESM and needs this trick
|
||||
const astToText = generator.default as typeof generator;
|
||||
const astToText = generator.default;
|
||||
const { code } = astToText(ast);
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { UserConfig } from 'vite';
|
||||
import type { AstroUserConfig } from '../@types/astro';
|
||||
import type { AstroUserConfig } from '../@types/astro.js';
|
||||
import { Logger } from '../core/logger/core.js';
|
||||
|
||||
export function defineConfig(config: AstroUserConfig) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type fsMod from 'node:fs';
|
||||
import type { Plugin, ViteDevServer } from 'vite';
|
||||
import type { AstroSettings } from '../@types/astro';
|
||||
import type { AstroSettings } from '../@types/astro.js';
|
||||
import { attachContentServerListeners } from '../content/server-listeners.js';
|
||||
import type { Logger } from '../core/logger/core.js';
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import { normalizePath, type ViteDevServer } from 'vite';
|
|||
import type { AstroSettings, ContentEntryType } from '../@types/astro.js';
|
||||
import { AstroError } from '../core/errors/errors.js';
|
||||
import { AstroErrorData } from '../core/errors/index.js';
|
||||
import type { Logger } from '../core/logger/core';
|
||||
import type { Logger } from '../core/logger/core.js';
|
||||
import { isRelativePath } from '../core/path.js';
|
||||
import { CONTENT_TYPES_FILE, VIRTUAL_MODULE_ID } from './consts.js';
|
||||
import {
|
||||
|
|
|
@ -5,7 +5,7 @@ import type { AstroSettings } from '../@types/astro.js';
|
|||
import { moduleIsTopLevelPage, walkParentInfos } from '../core/build/graph.js';
|
||||
import { getPageDataByViteID, type BuildInternals } from '../core/build/internal.js';
|
||||
import type { AstroBuildPlugin } from '../core/build/plugin.js';
|
||||
import type { StaticBuildOptions } from '../core/build/types';
|
||||
import type { StaticBuildOptions } from '../core/build/types.js';
|
||||
import type { ModuleLoader } from '../core/module-loader/loader.js';
|
||||
import { createViteLoader } from '../core/module-loader/vite.js';
|
||||
import { joinPaths, prependForwardSlash } from '../core/path.js';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { deserializeRouteData } from '../routing/manifest/serialization.js';
|
||||
import type { RouteInfo, SerializedSSRManifest, SSRManifest } from './types';
|
||||
import type { RouteInfo, SerializedSSRManifest, SSRManifest } from './types.js';
|
||||
|
||||
export function deserializeManifest(serializedManifest: SerializedSSRManifest): SSRManifest {
|
||||
const routes: RouteInfo[] = [];
|
||||
|
|
|
@ -5,8 +5,8 @@ import type {
|
|||
RouteData,
|
||||
SSRElement,
|
||||
SSRManifest,
|
||||
} from '../../@types/astro';
|
||||
import type { SinglePageBuiltModule } from '../build/types';
|
||||
} from '../../@types/astro.js';
|
||||
import type { SinglePageBuiltModule } from '../build/types.js';
|
||||
import { getSetCookiesFromResponse } from '../cookies/index.js';
|
||||
import { consoleLogDestination } from '../logger/console.js';
|
||||
import { AstroIntegrationLogger, Logger } from '../logger/core.js';
|
||||
|
@ -25,7 +25,7 @@ import {
|
|||
} from '../render/ssr-element.js';
|
||||
import { matchRoute } from '../routing/match.js';
|
||||
import { EndpointNotFoundError, SSRRoutePipeline } from './ssrPipeline.js';
|
||||
import type { RouteInfo } from './types';
|
||||
import type { RouteInfo } from './types.js';
|
||||
export { deserializeManifest } from './common.js';
|
||||
|
||||
const clientLocalsSymbol = Symbol.for('astro.locals');
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { RouteData } from '../../@types/astro';
|
||||
import type { SerializedSSRManifest, SSRManifest } from './types';
|
||||
import type { RouteData } from '../../@types/astro.js';
|
||||
import type { SerializedSSRManifest, SSRManifest } from './types.js';
|
||||
|
||||
import * as fs from 'node:fs';
|
||||
import { IncomingMessage } from 'node:http';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Pipeline } from '../pipeline.js';
|
||||
import type { Environment } from '../render';
|
||||
import type { Environment } from '../render/index.js';
|
||||
|
||||
/**
|
||||
* Thrown when an endpoint contains a response with the header "X-Astro-Response" === 'Not-Found'
|
||||
|
|
|
@ -4,8 +4,8 @@ import type {
|
|||
SSRComponentMetadata,
|
||||
SSRLoadedRenderer,
|
||||
SSRResult,
|
||||
} from '../../@types/astro';
|
||||
import type { SinglePageBuiltModule } from '../build/types';
|
||||
} from '../../@types/astro.js';
|
||||
import type { SinglePageBuiltModule } from '../build/types.js';
|
||||
|
||||
export type ComponentPath = string;
|
||||
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import type { AstroConfig, AstroSettings, SSRLoadedRenderer } from '../../@types/astro';
|
||||
import type { AstroConfig, AstroSettings, SSRLoadedRenderer } from '../../@types/astro.js';
|
||||
import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js';
|
||||
import { BEFORE_HYDRATION_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
|
||||
import type { SSRManifest } from '../app/types';
|
||||
import type { SSRManifest } from '../app/types.js';
|
||||
import { Logger } from '../logger/core.js';
|
||||
import { Pipeline } from '../pipeline.js';
|
||||
import { createEnvironment } from '../render/index.js';
|
||||
import { createAssetLink } from '../render/ssr-element.js';
|
||||
import type { BuildInternals } from './internal';
|
||||
import type { BuildInternals } from './internal.js';
|
||||
import { ASTRO_PAGE_RESOLVED_MODULE_ID } from './plugins/plugin-pages.js';
|
||||
import { RESOLVED_SPLIT_MODULE_ID } from './plugins/plugin-ssr.js';
|
||||
import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js';
|
||||
import type { PageBuildData, StaticBuildOptions } from './types';
|
||||
import type { PageBuildData, StaticBuildOptions } from './types.js';
|
||||
|
||||
/**
|
||||
* This pipeline is responsible to gather the files emitted by the SSR build and generate the pages by executing these files.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import npath from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import type { AstroConfig, RouteType } from '../../@types/astro';
|
||||
import type { AstroConfig, RouteType } from '../../@types/astro.js';
|
||||
import { appendForwardSlash } from '../../core/path.js';
|
||||
|
||||
const STATUS_CODE_PAGES = new Set(['/404', '/500']);
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { GetModuleInfo } from 'rollup';
|
|||
|
||||
import crypto from 'node:crypto';
|
||||
import npath from 'node:path';
|
||||
import type { AstroSettings } from '../../@types/astro';
|
||||
import type { AstroSettings } from '../../@types/astro.js';
|
||||
import { viteID } from '../util.js';
|
||||
import { getTopLevelPages } from './graph.js';
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import type {
|
|||
SSRError,
|
||||
SSRLoadedRenderer,
|
||||
SSRManifest,
|
||||
} from '../../@types/astro';
|
||||
} from '../../@types/astro.js';
|
||||
import {
|
||||
generateImage as generateImageInternal,
|
||||
getStaticImageList,
|
||||
|
@ -57,7 +57,7 @@ import type {
|
|||
SinglePageBuiltModule,
|
||||
StaticBuildOptions,
|
||||
StylesheetAsset,
|
||||
} from './types';
|
||||
} from './types.js';
|
||||
import { getTimeStat } from './util.js';
|
||||
|
||||
function createEntryURL(filePath: string, outFolder: URL) {
|
||||
|
|
|
@ -9,7 +9,7 @@ import type {
|
|||
AstroSettings,
|
||||
ManifestData,
|
||||
RuntimeMode,
|
||||
} from '../../@types/astro';
|
||||
} from '../../@types/astro.js';
|
||||
import { injectImageEndpoint } from '../../assets/internal.js';
|
||||
import { telemetry } from '../../events/index.js';
|
||||
import { eventCliSession } from '../../events/session.js';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { Rollup } from 'vite';
|
||||
import type { RouteData, SSRResult } from '../../@types/astro';
|
||||
import type { PageOptions } from '../../vite-plugin-astro/types';
|
||||
import type { RouteData, SSRResult } from '../../@types/astro.js';
|
||||
import type { PageOptions } from '../../vite-plugin-astro/types.js';
|
||||
import { prependForwardSlash, removeFileExtension } from '../path.js';
|
||||
import { viteID } from '../util.js';
|
||||
import {
|
||||
|
@ -9,7 +9,7 @@ import {
|
|||
} from './plugins/plugin-pages.js';
|
||||
import { RESOLVED_SPLIT_MODULE_ID } from './plugins/plugin-ssr.js';
|
||||
import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js';
|
||||
import type { PageBuildData, StylesheetAsset, ViteID } from './types';
|
||||
import type { PageBuildData, StylesheetAsset, ViteID } from './types.js';
|
||||
|
||||
export interface BuildInternals {
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { AstroSettings, ManifestData } from '../../@types/astro';
|
||||
import type { Logger } from '../logger/core';
|
||||
import type { AllPagesData } from './types';
|
||||
import type { AstroSettings, ManifestData } from '../../@types/astro.js';
|
||||
import type { Logger } from '../logger/core.js';
|
||||
import type { AllPagesData } from './types.js';
|
||||
|
||||
import * as colors from 'kleur/colors';
|
||||
import { debug } from '../logger/core.js';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { BuildInternals } from './internal';
|
||||
import type { StaticBuildOptions, ViteBuildReturn } from './types';
|
||||
import type { BuildInternals } from './internal.js';
|
||||
import type { StaticBuildOptions, ViteBuildReturn } from './types.js';
|
||||
|
||||
type RollupOutputArray = Extract<ViteBuildReturn, Array<any>>;
|
||||
type OutputChunkorAsset = RollupOutputArray[number]['output'][number];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { astroConfigBuildPlugin } from '../../../content/vite-plugin-content-assets.js';
|
||||
import { astroHeadBuildPlugin } from '../../../vite-plugin-head/index.js';
|
||||
import type { AstroBuildPluginContainer } from '../plugin';
|
||||
import type { AstroBuildPluginContainer } from '../plugin.js';
|
||||
import { pluginAliasResolve } from './plugin-alias-resolve.js';
|
||||
import { pluginAnalyzer } from './plugin-analyzer.js';
|
||||
import { pluginComponentEntry } from './plugin-component-entry.js';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { ModuleInfo, PluginContext } from 'rollup';
|
||||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { PluginMetadata as AstroPluginMetadata } from '../../../vite-plugin-astro/types';
|
||||
import type { PluginMetadata as AstroPluginMetadata } from '../../../vite-plugin-astro/types.js';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import type { AstroBuildPlugin } from '../plugin.js';
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ import * as npath from 'node:path';
|
|||
import type { GetModuleInfo } from 'rollup';
|
||||
import { type ResolvedConfig, type Plugin as VitePlugin } from 'vite';
|
||||
import { isBuildableCSSRequest } from '../../../vite-plugin-astro-server/util.js';
|
||||
import type { BuildInternals } from '../internal';
|
||||
import type { AstroBuildPlugin } from '../plugin';
|
||||
import type { PageBuildData, StaticBuildOptions, StylesheetAsset } from '../types';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import type { AstroBuildPlugin } from '../plugin.js';
|
||||
import type { PageBuildData, StaticBuildOptions, StylesheetAsset } from '../types.js';
|
||||
|
||||
import { PROPAGATED_ASSET_FLAG } from '../../../content/consts.js';
|
||||
import * as assetName from '../css-asset-name.js';
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { AstroSettings } from '../../../@types/astro';
|
||||
import type { AstroSettings } from '../../../@types/astro.js';
|
||||
import { viteID } from '../../util.js';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import { getPageDataByViteID } from '../internal.js';
|
||||
import type { AstroBuildPlugin } from '../plugin';
|
||||
import type { OutputChunk, StaticBuildOptions } from '../types';
|
||||
import type { AstroBuildPlugin } from '../plugin.js';
|
||||
import type { OutputChunk, StaticBuildOptions } from '../types.js';
|
||||
|
||||
function virtualHoistedEntry(id: string) {
|
||||
return id.startsWith('/astro/hoisted.js?q=');
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import type { AstroBuildPlugin } from '../plugin';
|
||||
import type { AstroBuildPlugin } from '../plugin.js';
|
||||
import { normalizeEntryId } from './plugin-component-entry.js';
|
||||
|
||||
export function vitePluginInternals(input: Set<string>, internals: BuildInternals): VitePlugin {
|
||||
|
|
|
@ -4,14 +4,14 @@ import type { OutputChunk } from 'rollup';
|
|||
import { type Plugin as VitePlugin } from 'vite';
|
||||
import { runHookBuildSsr } from '../../../integrations/index.js';
|
||||
import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../../vite-plugin-scripts/index.js';
|
||||
import type { SerializedRouteInfo, SerializedSSRManifest } from '../../app/types';
|
||||
import type { SerializedRouteInfo, SerializedSSRManifest } from '../../app/types.js';
|
||||
import { joinPaths, prependForwardSlash } from '../../path.js';
|
||||
import { serializeRouteData } from '../../routing/index.js';
|
||||
import { addRollupInput } from '../add-rollup-input.js';
|
||||
import { getOutFile, getOutFolder } from '../common.js';
|
||||
import { cssOrder, mergeInlineCss, type BuildInternals } from '../internal.js';
|
||||
import type { AstroBuildPlugin } from '../plugin';
|
||||
import type { StaticBuildOptions } from '../types';
|
||||
import type { AstroBuildPlugin } from '../plugin.js';
|
||||
import type { StaticBuildOptions } from '../types.js';
|
||||
|
||||
const manifestReplace = '@@ASTRO_MANIFEST_REPLACE@@';
|
||||
const replaceExp = new RegExp(`['"](${manifestReplace})['"]`, 'g');
|
||||
|
@ -46,8 +46,8 @@ function vitePluginManifest(options: StaticBuildOptions, internals: BuildInterna
|
|||
`import { _privateSetManifestDontUseThis } from 'astro:ssr-manifest'`
|
||||
);
|
||||
|
||||
contents.push(`
|
||||
const manifest = _deserializeManifest('${manifestReplace}');
|
||||
contents.push(`
|
||||
const manifest = _deserializeManifest('${manifestReplace}');
|
||||
_privateSetManifestDontUseThis(manifest);
|
||||
`);
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@ import type { Plugin as VitePlugin } from 'vite';
|
|||
import { getOutputDirectory } from '../../../prerender/utils.js';
|
||||
import { MIDDLEWARE_PATH_SEGMENT_NAME } from '../../constants.js';
|
||||
import { addRollupInput } from '../add-rollup-input.js';
|
||||
import type { BuildInternals } from '../internal';
|
||||
import type { AstroBuildPlugin } from '../plugin';
|
||||
import type { StaticBuildOptions } from '../types';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import type { AstroBuildPlugin } from '../plugin.js';
|
||||
import type { StaticBuildOptions } from '../types.js';
|
||||
|
||||
export const MIDDLEWARE_MODULE_ID = '@astro-middleware';
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { extname } from 'node:path';
|
||||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { AstroSettings } from '../../../@types/astro';
|
||||
import type { AstroSettings } from '../../../@types/astro.js';
|
||||
import { routeIsRedirect } from '../../redirects/index.js';
|
||||
import { addRollupInput } from '../add-rollup-input.js';
|
||||
import { type BuildInternals } from '../internal.js';
|
||||
import type { AstroBuildPlugin } from '../plugin';
|
||||
import type { StaticBuildOptions } from '../types';
|
||||
import type { AstroBuildPlugin } from '../plugin.js';
|
||||
import type { StaticBuildOptions } from '../types.js';
|
||||
import { MIDDLEWARE_MODULE_ID } from './plugin-middleware.js';
|
||||
import { RENDERERS_MODULE_ID } from './plugin-renderers.js';
|
||||
import { ASTRO_PAGE_EXTENSION_POST_PATTERN, getPathFromVirtualModulePageName } from './util.js';
|
||||
|
|
|
@ -3,7 +3,7 @@ import type { Plugin as VitePlugin } from 'vite';
|
|||
import { getPrerenderMetadata } from '../../../prerender/metadata.js';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import type { AstroBuildPlugin } from '../plugin.js';
|
||||
import type { StaticBuildOptions } from '../types';
|
||||
import type { StaticBuildOptions } from '../types.js';
|
||||
import { extendManualChunks } from './util.js';
|
||||
|
||||
function vitePluginPrerender(opts: StaticBuildOptions, internals: BuildInternals): VitePlugin {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import { addRollupInput } from '../add-rollup-input.js';
|
||||
import type { AstroBuildPlugin } from '../plugin';
|
||||
import type { StaticBuildOptions } from '../types';
|
||||
import type { AstroBuildPlugin } from '../plugin.js';
|
||||
import type { StaticBuildOptions } from '../types.js';
|
||||
|
||||
export const RENDERERS_MODULE_ID = '@astro-renderers';
|
||||
export const RESOLVED_RENDERERS_MODULE_ID = `\0${RENDERERS_MODULE_ID}`;
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { join } from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { AstroAdapter, AstroConfig } from '../../../@types/astro';
|
||||
import type { AstroAdapter, AstroConfig } from '../../../@types/astro.js';
|
||||
import { isFunctionPerRouteEnabled } from '../../../integrations/index.js';
|
||||
import { isServerLikeOutput } from '../../../prerender/utils.js';
|
||||
import { routeIsRedirect } from '../../redirects/index.js';
|
||||
import { addRollupInput } from '../add-rollup-input.js';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import type { AstroBuildPlugin } from '../plugin';
|
||||
import type { StaticBuildOptions } from '../types';
|
||||
import type { AstroBuildPlugin } from '../plugin.js';
|
||||
import type { StaticBuildOptions } from '../types.js';
|
||||
import { SSR_MANIFEST_VIRTUAL_MODULE_ID } from './plugin-manifest.js';
|
||||
import { ASTRO_PAGE_MODULE_ID } from './plugin-pages.js';
|
||||
import { RENDERERS_MODULE_ID } from './plugin-renderers.js';
|
||||
|
@ -246,8 +246,8 @@ function generateSSRCode(config: AstroConfig, adapter: AstroAdapter) {
|
|||
}
|
||||
|
||||
contents.push(`import * as adapter from '${adapter.serverEntrypoint}';
|
||||
import { renderers } from '${RENDERERS_MODULE_ID}';
|
||||
import { manifest as defaultManifest} from '${SSR_MANIFEST_VIRTUAL_MODULE_ID}';
|
||||
import { renderers } from '${RENDERERS_MODULE_ID}';
|
||||
import { manifest as defaultManifest} from '${SSR_MANIFEST_VIRTUAL_MODULE_ID}';
|
||||
const _manifest = Object.assign(defaultManifest, {
|
||||
${pageMap},
|
||||
renderers,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue