feat(i18n): better virtual module functions (#8778)
Co-authored-by: Martin Trapp <94928215+martrapp@users.noreply.github.com>
This commit is contained in:
parent
9f3f110268
commit
7678ef33a0
11 changed files with 463 additions and 46 deletions
5
packages/astro/client.d.ts
vendored
5
packages/astro/client.d.ts
vendored
|
@ -129,7 +129,12 @@ declare module 'astro:transitions/client' {
|
|||
|
||||
declare module 'astro:i18n' {
|
||||
type I18nModule = typeof import('./dist/i18n/index.js');
|
||||
|
||||
// TODO: documentation
|
||||
export const getI18nBaseUrl: (locale: string) => string;
|
||||
|
||||
// TODO: documentation
|
||||
export const getLocalesBaseUrl: () => string[];
|
||||
}
|
||||
|
||||
declare module 'astro:middleware' {
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
"default": "./dist/core/middleware/namespace.js"
|
||||
},
|
||||
"./transitions": "./dist/transitions/index.js",
|
||||
"./transitions": "./dist/transitions/index.js",
|
||||
"./transitions/router": "./dist/transitions/router.js",
|
||||
"./i18n": "./dist/i18n/index.js"
|
||||
},
|
||||
"imports": {
|
||||
|
|
|
@ -5,7 +5,6 @@ import { fileURLToPath } from 'node:url';
|
|||
import type { OutputAsset, OutputChunk } from 'rollup';
|
||||
import type { BufferEncoding } from 'vfile';
|
||||
import type {
|
||||
AstroConfig,
|
||||
AstroSettings,
|
||||
ComponentInstance,
|
||||
GetStaticPathsItem,
|
||||
|
@ -58,7 +57,7 @@ import type {
|
|||
StaticBuildOptions,
|
||||
StylesheetAsset,
|
||||
} from './types.js';
|
||||
import { getTimeStat } from './util.js';
|
||||
import { getTimeStat, shouldAppendForwardSlash } from './util.js';
|
||||
|
||||
function createEntryURL(filePath: string, outFolder: URL) {
|
||||
return new URL('./' + filePath + `?time=${Date.now()}`, outFolder);
|
||||
|
@ -431,26 +430,6 @@ interface GeneratePathOptions {
|
|||
mod: ComponentInstance;
|
||||
}
|
||||
|
||||
function shouldAppendForwardSlash(
|
||||
trailingSlash: AstroConfig['trailingSlash'],
|
||||
buildFormat: AstroConfig['build']['format']
|
||||
): boolean {
|
||||
switch (trailingSlash) {
|
||||
case 'always':
|
||||
return true;
|
||||
case 'never':
|
||||
return false;
|
||||
case 'ignore': {
|
||||
switch (buildFormat) {
|
||||
case 'directory':
|
||||
return true;
|
||||
case 'file':
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addPageName(pathname: string, opts: StaticBuildOptions): void {
|
||||
const trailingSlash = opts.settings.config.trailingSlash;
|
||||
const buildFormat = opts.settings.config.build.format;
|
||||
|
|
|
@ -1,4 +1,29 @@
|
|||
import type { AstroConfig } from '../../@types/astro.js';
|
||||
|
||||
export function getTimeStat(timeStart: number, timeEnd: number) {
|
||||
const buildTime = timeEnd - timeStart;
|
||||
return buildTime < 750 ? `${Math.round(buildTime)}ms` : `${(buildTime / 1000).toFixed(2)}s`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the Astro configuration, it tells if a slash should be appended or not
|
||||
*/
|
||||
export function shouldAppendForwardSlash(
|
||||
trailingSlash: AstroConfig['trailingSlash'],
|
||||
buildFormat: AstroConfig['build']['format']
|
||||
): boolean {
|
||||
switch (trailingSlash) {
|
||||
case 'always':
|
||||
return true;
|
||||
case 'never':
|
||||
return false;
|
||||
case 'ignore': {
|
||||
switch (buildFormat) {
|
||||
case 'directory':
|
||||
return true;
|
||||
case 'file':
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import astroScriptsPlugin from '../vite-plugin-scripts/index.js';
|
|||
import astroScriptsPageSSRPlugin from '../vite-plugin-scripts/page-ssr.js';
|
||||
import { vitePluginSSRManifest } from '../vite-plugin-ssr-manifest/index.js';
|
||||
import { joinPaths } from './path.js';
|
||||
import astroInternalization from '../i18n/vite-plugin-i18n.js';
|
||||
|
||||
interface CreateViteOptions {
|
||||
settings: AstroSettings;
|
||||
|
@ -134,6 +135,7 @@ export async function createVite(
|
|||
vitePluginSSRManifest(),
|
||||
astroAssetsPlugin({ settings, logger, mode }),
|
||||
astroTransitions(),
|
||||
!!settings.config.experimental.i18n && astroInternalization({ settings, logger }),
|
||||
],
|
||||
publicDir: fileURLToPath(settings.config.publicDir),
|
||||
root: fileURLToPath(settings.config.root),
|
||||
|
|
|
@ -1243,5 +1243,15 @@ export const UnsupportedConfigTransformError = {
|
|||
hint: 'See the devalue library for all supported types: https://github.com/rich-harris/devalue',
|
||||
} satisfies ErrorData;
|
||||
|
||||
export const MissingLocale = {
|
||||
name: 'MissingLocaleError',
|
||||
title: 'The provided locale does not exist.',
|
||||
message: (locale: string, locales: string[]) => {
|
||||
return `The locale \`${locale}\` does not exist in the configured locales. Available locales: ${locales.join(
|
||||
', '
|
||||
)}.`;
|
||||
},
|
||||
} satisfies ErrorData;
|
||||
|
||||
// Generic catch-all - Only use this in extreme cases, like if there was a cosmic ray bit flip
|
||||
export const UnknownError = { name: 'UnknownError', title: 'Unknown Error.' } satisfies ErrorData;
|
||||
|
|
|
@ -1,21 +1,58 @@
|
|||
import { AstroError } from '../core/errors/index.js';
|
||||
import { MissingLocale } from '../core/errors/errors-data.js';
|
||||
import type { AstroConfig } from '../@types/astro.js';
|
||||
import type { Logger } from '../core/logger/core.js';
|
||||
import { shouldAppendForwardSlash } from '../core/build/util.js';
|
||||
|
||||
type GetI18nBaseUrl = {
|
||||
locale: string;
|
||||
base: string;
|
||||
locales: string[];
|
||||
trailingSlash: AstroConfig['trailingSlash'];
|
||||
format: AstroConfig['build']['format'];
|
||||
};
|
||||
/**
|
||||
* The base URL
|
||||
*/
|
||||
export function getI18nBaseUrl(locale: string, config: AstroConfig, logger: Logger) {
|
||||
const base = config.base;
|
||||
|
||||
if (!config.experimental.i18n) {
|
||||
logger.error('i18n', "The project isn't using i18n features, no need to use this function.");
|
||||
return base ? `/${base}/` : '/';
|
||||
export function getI18nBaseUrl({ locale, base, locales, trailingSlash, format }: GetI18nBaseUrl) {
|
||||
if (!locales.includes(locale)) {
|
||||
throw new AstroError({
|
||||
...MissingLocale,
|
||||
message: MissingLocale.message(locale, locales),
|
||||
});
|
||||
}
|
||||
|
||||
if (base) {
|
||||
logger.debug('i18n', 'The project has a base directory, using it.');
|
||||
return `${base}/${locale}/`;
|
||||
const normalizedLocale = normalizeLocale(locale);
|
||||
if (shouldAppendForwardSlash(trailingSlash, format)) {
|
||||
return `${base}${normalizedLocale}/`;
|
||||
} else {
|
||||
return `/${locale}/`;
|
||||
return `${base}/${normalizedLocale}`;
|
||||
}
|
||||
}
|
||||
|
||||
type GetLocalesBaseUrl = {
|
||||
base: string;
|
||||
locales: string[];
|
||||
trailingSlash: AstroConfig['trailingSlash'];
|
||||
format: AstroConfig['build']['format'];
|
||||
};
|
||||
|
||||
export function getLocalesBaseUrl({ base, locales, trailingSlash, format }: GetLocalesBaseUrl) {
|
||||
return locales.map((locale) => {
|
||||
const normalizedLocale = normalizeLocale(locale);
|
||||
if (shouldAppendForwardSlash(trailingSlash, format)) {
|
||||
return `${base}${normalizedLocale}/`;
|
||||
} else {
|
||||
return `${base}/${normalizedLocale}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Given a locale, this function:
|
||||
* - replaces the `_` with a `-`;
|
||||
* - transforms all letters to be lower case;
|
||||
*/
|
||||
function normalizeLocale(locale: string): string {
|
||||
return locale.replaceAll('_', '-').toLowerCase();
|
||||
}
|
||||
|
|
|
@ -13,12 +13,25 @@ type AstroInternalization = {
|
|||
export default function astroInternalization({ settings }: AstroInternalization): vite.Plugin {
|
||||
return {
|
||||
name: 'astro:i18n',
|
||||
async resolveId(id) {
|
||||
if (id === virtualModuleId) {
|
||||
return resolvedVirtualModuleId;
|
||||
}
|
||||
},
|
||||
load(id) {
|
||||
if (id === resolvedVirtualModuleId) {
|
||||
return `
|
||||
import { getI18nBaseUrl as getI18nBaseUrlInternal } from "astro/i18n";
|
||||
|
||||
export getI18nBaseUrl = (locale) => getI18nBaseUrlInternal(locale, ${settings.config});
|
||||
import { getI18nBaseUrl as getI18nBaseUrlInternal, getLocalesBaseUrl as _getLocalesBaseUrl } from "astro/i18n";
|
||||
|
||||
const defaultLocale = ${JSON.stringify(settings.config.experimental.i18n!.defaultLocale)};
|
||||
const locales = ${JSON.stringify(settings.config.experimental.i18n!.locales)};
|
||||
const fallback = ${JSON.stringify(settings.config.experimental.i18n!.fallback)};
|
||||
const base = ${JSON.stringify(settings.config.base)};
|
||||
const trailingSlash = ${JSON.stringify(settings.config.trailingSlash)};
|
||||
const format = ${JSON.stringify(settings.config.build.format)};
|
||||
|
||||
export const getI18nBaseUrl = (locale) => getI18nBaseUrlInternal({ locale, base, locales, trailingSlash, format });
|
||||
export const getLocalesBaseUrl = () => _getLocalesBaseUrl({ base, locales, trailingSlash, format });
|
||||
`;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import { getI18nBaseUrl } from '../../../dist/i18n/index.js';
|
||||
import { getI18nBaseUrl, getLocalesBaseUrl } from '../../../dist/i18n/index.js';
|
||||
import { expect } from 'chai';
|
||||
import { Logger } from '../../../dist/core/logger/core.js';
|
||||
|
||||
const logger = new Logger();
|
||||
describe('getI18nBaseUrl', () => {
|
||||
it('should correctly return the URL with the base', () => {
|
||||
/**
|
||||
|
@ -14,13 +12,70 @@ describe('getI18nBaseUrl', () => {
|
|||
experimental: {
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'es'],
|
||||
locales: ['en', 'en_US', 'es'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(getI18nBaseUrl('en', config, logger)).to.eq('/blog/en/');
|
||||
expect(getI18nBaseUrl('es', config, logger)).to.eq('/blog/es/');
|
||||
// directory format
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'en',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'directory',
|
||||
})
|
||||
).to.eq('/blog/en/');
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'es',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'directory',
|
||||
})
|
||||
).to.eq('/blog/es/');
|
||||
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'en_US',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'directory',
|
||||
})
|
||||
).to.throw;
|
||||
|
||||
// file format
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'en',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'file',
|
||||
})
|
||||
).to.eq('/blog/en/');
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'es',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'file',
|
||||
})
|
||||
).to.eq('/blog/es/');
|
||||
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'en_US',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'file',
|
||||
})
|
||||
).to.throw;
|
||||
});
|
||||
|
||||
it('should correctly return the URL without base', () => {
|
||||
|
@ -37,7 +92,286 @@ describe('getI18nBaseUrl', () => {
|
|||
},
|
||||
};
|
||||
|
||||
expect(getI18nBaseUrl('en', config, logger)).to.eq('/en/');
|
||||
expect(getI18nBaseUrl('es', config, logger)).to.eq('/es/');
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'en',
|
||||
base: '/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'directory',
|
||||
})
|
||||
).to.eq('/en/');
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'es',
|
||||
base: '/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'directory',
|
||||
})
|
||||
).to.eq('/es/');
|
||||
});
|
||||
|
||||
it('should correctly handle the trailing slash', () => {
|
||||
/**
|
||||
*
|
||||
* @type {import("../../../dist/@types").AstroUserConfig}
|
||||
*/
|
||||
const config = {
|
||||
experimental: {
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'es'],
|
||||
},
|
||||
},
|
||||
};
|
||||
// directory format
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'en',
|
||||
base: '/blog',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'never',
|
||||
format: 'directory',
|
||||
})
|
||||
).to.eq('/blog/en');
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'es',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'directory',
|
||||
})
|
||||
).to.eq('/blog/es/');
|
||||
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'en',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'ignore',
|
||||
format: 'directory',
|
||||
})
|
||||
).to.eq('/blog/en/');
|
||||
|
||||
// directory file
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'en',
|
||||
base: '/blog',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'never',
|
||||
format: 'file',
|
||||
})
|
||||
).to.eq('/blog/en');
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'es',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'file',
|
||||
})
|
||||
).to.eq('/blog/es/');
|
||||
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'en',
|
||||
// ignore + file => no trailing slash
|
||||
base: '/blog',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'ignore',
|
||||
format: 'file',
|
||||
})
|
||||
).to.eq('/blog/en');
|
||||
});
|
||||
|
||||
it('should normalize locales', () => {
|
||||
/**
|
||||
*
|
||||
* @type {import("../../../dist/@types").AstroUserConfig}
|
||||
*/
|
||||
const config = {
|
||||
base: '/blog',
|
||||
experimental: {
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'en_US', 'en_AU'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'en_US',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'directory',
|
||||
})
|
||||
).to.eq('/blog/en-us/');
|
||||
|
||||
expect(
|
||||
getI18nBaseUrl({
|
||||
locale: 'en_AU',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'directory',
|
||||
})
|
||||
).to.eq('/blog/en-au/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLocalesBaseUrl', () => {
|
||||
it('should retrieve the correct list of base URL with locales [format: directory, trailingSlash: never]', () => {
|
||||
/**
|
||||
*
|
||||
* @type {import("../../../dist/@types").AstroUserConfig}
|
||||
*/
|
||||
const config = {
|
||||
experimental: {
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'en_US', 'es'],
|
||||
},
|
||||
},
|
||||
};
|
||||
// directory format
|
||||
expect(
|
||||
getLocalesBaseUrl({
|
||||
locale: 'en',
|
||||
base: '/blog',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'never',
|
||||
format: 'directory',
|
||||
})
|
||||
).to.have.members(['/blog/en', '/blog/en-us', '/blog/es']);
|
||||
});
|
||||
|
||||
it('should retrieve the correct list of base URL with locales [format: directory, trailingSlash: always]', () => {
|
||||
/**
|
||||
*
|
||||
* @type {import("../../../dist/@types").AstroUserConfig}
|
||||
*/
|
||||
const config = {
|
||||
experimental: {
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'en_US', 'es'],
|
||||
},
|
||||
},
|
||||
};
|
||||
// directory format
|
||||
expect(
|
||||
getLocalesBaseUrl({
|
||||
locale: 'en',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'directory',
|
||||
})
|
||||
).to.have.members(['/blog/en/', '/blog/en-us/', '/blog/es/']);
|
||||
});
|
||||
|
||||
it('should retrieve the correct list of base URL with locales [format: file, trailingSlash: always]', () => {
|
||||
/**
|
||||
*
|
||||
* @type {import("../../../dist/@types").AstroUserConfig}
|
||||
*/
|
||||
const config = {
|
||||
experimental: {
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'en_US', 'es'],
|
||||
},
|
||||
},
|
||||
};
|
||||
// directory format
|
||||
expect(
|
||||
getLocalesBaseUrl({
|
||||
locale: 'en',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'always',
|
||||
format: 'file',
|
||||
})
|
||||
).to.have.members(['/blog/en/', '/blog/en-us/', '/blog/es/']);
|
||||
});
|
||||
|
||||
it('should retrieve the correct list of base URL with locales [format: file, trailingSlash: never]', () => {
|
||||
/**
|
||||
*
|
||||
* @type {import("../../../dist/@types").AstroUserConfig}
|
||||
*/
|
||||
const config = {
|
||||
experimental: {
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'en_US', 'es'],
|
||||
},
|
||||
},
|
||||
};
|
||||
// directory format
|
||||
expect(
|
||||
getLocalesBaseUrl({
|
||||
locale: 'en',
|
||||
base: '/blog',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'never',
|
||||
format: 'file',
|
||||
})
|
||||
).to.have.members(['/blog/en', '/blog/en-us', '/blog/es']);
|
||||
});
|
||||
|
||||
it('should retrieve the correct list of base URL with locales [format: file, trailingSlash: ignore]', () => {
|
||||
/**
|
||||
*
|
||||
* @type {import("../../../dist/@types").AstroUserConfig}
|
||||
*/
|
||||
const config = {
|
||||
experimental: {
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'en_US', 'es'],
|
||||
},
|
||||
},
|
||||
};
|
||||
// directory format
|
||||
expect(
|
||||
getLocalesBaseUrl({
|
||||
locale: 'en',
|
||||
base: '/blog',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'ignore',
|
||||
format: 'file',
|
||||
})
|
||||
).to.have.members(['/blog/en', '/blog/en-us', '/blog/es']);
|
||||
});
|
||||
|
||||
it('should retrieve the correct list of base URL with locales [format: directory, trailingSlash: ignore]', () => {
|
||||
/**
|
||||
*
|
||||
* @type {import("../../../dist/@types").AstroUserConfig}
|
||||
*/
|
||||
const config = {
|
||||
experimental: {
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'en_US', 'es'],
|
||||
},
|
||||
},
|
||||
};
|
||||
// directory format
|
||||
expect(
|
||||
getLocalesBaseUrl({
|
||||
locale: 'en',
|
||||
base: '/blog/',
|
||||
locales: config.experimental.i18n.locales,
|
||||
trailingSlash: 'ignore',
|
||||
format: 'directory',
|
||||
})
|
||||
).to.have.members(['/blog/en/', '/blog/en-us/', '/blog/es/']);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -20,6 +20,7 @@ process.on('SIGTERM', exit);
|
|||
// if you make any changes to the flow or wording here.
|
||||
export async function main() {
|
||||
// Clear console because PNPM startup is super ugly
|
||||
// eslint-disable-next-line no-console
|
||||
console.clear();
|
||||
// NOTE: In the v7.x version of npm, the default behavior of `npm init` was changed
|
||||
// to no longer require `--` to pass args and instead pass `--` directly to us. This
|
||||
|
|
|
@ -2755,6 +2755,18 @@ importers:
|
|||
specifier: ^10.17.1
|
||||
version: 10.17.1
|
||||
|
||||
packages/astro/test/fixtures/i18n-routing:
|
||||
dependencies:
|
||||
astro:
|
||||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
|
||||
packages/astro/test/fixtures/i18n-routing-base:
|
||||
dependencies:
|
||||
astro:
|
||||
specifier: workspace:*
|
||||
version: link:../../..
|
||||
|
||||
packages/astro/test/fixtures/import-ts-with-js:
|
||||
dependencies:
|
||||
astro:
|
||||
|
@ -17267,7 +17279,6 @@ packages:
|
|||
engines: {node: '>=14.0'}
|
||||
dependencies:
|
||||
busboy: 1.6.0
|
||||
dev: true
|
||||
|
||||
/unherit@3.0.1:
|
||||
resolution: {integrity: sha512-akOOQ/Yln8a2sgcLj4U0Jmx0R5jpIg2IUyRrWOzmEbjBtGzBdHtSeFKgoEcoH4KYIG/Pb8GQ/BwtYm0GCq1Sqg==}
|
||||
|
|
Loading…
Reference in a new issue