Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion biome.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
// Enforce separate type imports for type-only imports to avoid bundling unneeded code
"useImportType": "error",
"useExportType": "error",
"useNumberNamespace": "warn"
"useNumberNamespace": "warn",
"noInferrableTypes": "error"
},
"suspicious": {
// This one is specific to catch `console.log`. The rest of logs are permitted
Expand Down
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export default [
'@typescript-eslint/consistent-indexed-object-style': 'off',
'@typescript-eslint/consistent-type-definitions': 'off',
'@typescript-eslint/dot-notation': 'off',
'@typescript-eslint/no-inferrable-types': 'off',
'@typescript-eslint/no-base-to-string': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-floating-promises': 'off',
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/core/cookies/cookies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface AstroCookieGetOptions {
decode?: (value: string) => string;
}

type AstroCookieDeleteOptions = Omit<AstroCookieSetOptions, 'expires' | 'maxAge' | 'encode'>;
export type AstroCookieDeleteOptions = Omit<AstroCookieSetOptions, 'expires' | 'maxAge' | 'encode'>;

interface AstroCookieInterface {
value: string;
Expand Down
8 changes: 0 additions & 8 deletions packages/astro/test/units/_temp-fixtures/package.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-check
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import {
Expand All @@ -8,6 +7,7 @@ import {
isActionError,
isInputError,
} from '../../../dist/actions/runtime/client.js';
import type { ActionErrorCode } from '../../../dist/actions/runtime/types.js';

describe('ActionError', () => {
it('sets code, status, and message from constructor', () => {
Expand Down Expand Up @@ -42,7 +42,7 @@ describe('ActionError', () => {

describe('ActionError.codeToStatus', () => {
it('maps all known codes to correct HTTP status', () => {
for (const [code, status] of Object.entries(codeToStatusMap)) {
for (const [code, status] of Object.entries(codeToStatusMap) as [ActionErrorCode, number][]) {
assert.equal(ActionError.codeToStatus(code), status, `Expected ${code} to map to ${status}`);
}
});
Expand Down Expand Up @@ -95,7 +95,7 @@ describe('ActionInputError', () => {
{ code: 'invalid_type', message: 'Expected string', path: ['name'] },
{ code: 'too_small', message: 'Too short', path: ['name'] },
{ code: 'invalid_type', message: 'Required', path: ['email'] },
];
] as unknown as ConstructorParameters<typeof ActionInputError>[0];
const error = new ActionInputError(issues);
assert.equal(error.code, 'BAD_REQUEST');
assert.equal(error.status, 400);
Expand All @@ -111,7 +111,9 @@ describe('ActionInputError', () => {
});

it('handles issues without paths', () => {
const issues = [{ code: 'custom', message: 'Something wrong', path: [] }];
const issues = [
{ code: 'custom', message: 'Something wrong', path: [] },
] as unknown as ConstructorParameters<typeof ActionInputError>[0];
const error = new ActionInputError(issues);
assert.deepEqual(error.fields, {});
});
Expand Down Expand Up @@ -146,7 +148,7 @@ describe('isActionError', () => {

describe('isInputError', () => {
it('returns true for ActionInputError instances', () => {
const issues = [{ code: 'invalid_type', message: 'bad', path: ['x'] }];
const issues = [{ code: 'invalid_type', message: 'bad', path: ['x'] }] as unknown as ConstructorParameters<typeof ActionInputError>[0];
assert.equal(isInputError(new ActionInputError(issues)), true);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-check
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
// @ts-check
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import type { APIContext } from '../../../dist/types/public/context.js';
import type { SafeResult } from '../../../dist/actions/runtime/types.js';
import { createActionsProxy, ActionError } from '../../../dist/actions/runtime/client.js';

/**
* Creates a proxy with a spy handleAction that records calls and returns a configurable result.
* @param {object} [opts]
* @param {import('../../../dist/actions/runtime/client.js').SafeResult} [opts.result]
*/
function setup(opts = {}) {
const result = opts.result ?? { data: 'ok', error: undefined };
/** @type {{ param: any; path: string; context: any }[]} */
const calls = [];

const handleAction = async (param, path, context) => {
// #region Helpers

interface SetupOptions {
result?: SafeResult<any, any>;
}

interface CallRecord {
param: unknown;
path: string;
context: APIContext | undefined;
}

function setup(opts: SetupOptions = {}) {
const result: SafeResult<any, any> = opts.result ?? { data: 'ok', error: undefined };
const calls: CallRecord[] = [];

const handleAction = async (param: unknown, path: string, context: APIContext | undefined) => {
calls.push({ param, path, context });
return result;
};
Expand All @@ -22,6 +29,10 @@ function setup(opts = {}) {
return { proxy, calls };
}

// #endregion

// #region Tests

describe('createActionsProxy', () => {
describe('path building', () => {
it('builds a top-level path from property access', async () => {
Expand Down Expand Up @@ -121,3 +132,5 @@ describe('createActionsProxy', () => {
});
});
});

// #endregion
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ describe('formDataToObject', () => {
});

const res = formDataToObject(formData, input);
assert.ok(isNaN(res.age));
assert.ok(isNaN(res.age as number));
});

it('should handle boolean checks', () => {
const formData = new FormData();
formData.set('isCool', 'yes');
formData.set('isTrue', true);
formData.set('isFalse', false);
formData.set('isTrue', String(true));
formData.set('isFalse', String(false));
formData.set('falseString', 'false');

const input = z.object({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-check
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import * as devalue from 'devalue';
Expand All @@ -8,6 +7,7 @@ import {
ActionInputError,
deserializeActionResult,
} from '../../../dist/actions/runtime/client.js';
import type { ActionErrorCode } from '../../../dist/actions/runtime/types.js';

describe('serializeActionResult', () => {
describe('data results', () => {
Expand Down Expand Up @@ -89,7 +89,8 @@ describe('serializeActionResult', () => {
const result = serializeActionResult({ data: undefined, error: undefined });
assert.equal(result.type, 'empty');
assert.equal(result.status, 204);
assert.equal(result.body, undefined);
// The 'empty' variant has no body field — verify it's absent at runtime
assert.equal('body' in result ? result.body : undefined, undefined);
});
});

Expand All @@ -110,7 +111,7 @@ describe('serializeActionResult', () => {
it('serializes an ActionInputError with issues and fields', () => {
const issues = [
{ code: 'invalid_type', expected: 'string', message: 'Required', path: ['comment'] },
];
] as unknown as ConstructorParameters<typeof ActionInputError>[0];
const error = new ActionInputError(issues);
const result = serializeActionResult({ data: undefined, error });
assert.equal(result.type, 'error');
Expand All @@ -125,7 +126,7 @@ describe('serializeActionResult', () => {
});

it('uses correct status for different error codes', () => {
const codes = [
const codes: [ActionErrorCode, number][] = [
['BAD_REQUEST', 400],
['NOT_FOUND', 404],
['INTERNAL_SERVER_ERROR', 500],
Expand Down Expand Up @@ -183,7 +184,7 @@ describe('deserializeActionResult', () => {
it('deserializes an ActionInputError result', () => {
const issues = [
{ code: 'invalid_type', expected: 'string', message: 'Required', path: ['name'] },
];
] as unknown as ConstructorParameters<typeof ActionInputError>[0];
const serialized = serializeActionResult({
data: undefined,
error: new ActionInputError(issues),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,34 @@ import { describe, it } from 'node:test';
import { pathToFileURL } from 'node:url';
import { resolveConfig } from 'vite';
import { compileAstro } from '../../../dist/vite-plugin-astro/compile.js';
import type { AstroConfig } from '../../../dist/types/public/config.js';
import type { CompileProps } from '../../../dist/core/compile/compile.js';
import { Logger } from '../../../dist/core/logger/core.js';
import { nodeLogDestination } from '../../../dist/core/logger/node.js';

/**
* Compile Astro source with a given base path
* @param {string} source - Astro source code
* @param {string} base - Base path configuration
*/
async function compileWithBase(source, base = '/') {
const logger = new Logger({ dest: nodeLogDestination, level: 'silent' });

/** Compile Astro source with a given base path. */
async function compileWithBase(source: string, base = '/') {
const viteConfig = await resolveConfig({ configFile: false }, 'serve');
const result = await compileAstro({
compileProps: {
astroConfig: {
root: pathToFileURL('/'),
base,
experimental: {},
build: {
format: 'directory',
},
trailingSlash: 'ignore',
},
viteConfig,
preferences: {
get: () => Promise.resolve(false),
},
filename: '/src/pages/index.astro',
source,
},
const props: CompileProps = {
astroConfig: {
root: pathToFileURL('/'),
base,
experimental: {},
build: { format: 'directory' },
trailingSlash: 'ignore',
} as AstroConfig,
viteConfig,
toolbarEnabled: false,
filename: '/src/pages/index.astro',
source,
};
return compileAstro({
compileProps: props as any,
astroFileToCompileMetadata: new Map(),
logger: {
info: () => {},
warn: () => {},
error: () => {},
debug: () => {},
},
logger,
});
return result;
}

describe('CSS Base Path Rewriting', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { pathToFileURL } from 'node:url';
import { resolveConfig } from 'vite';
import { compile } from '../../../dist/core/compile/index.js';
import { AggregateError } from '../../../dist/core/errors/index.js';
import type { AstroConfig } from '../../../dist/types/public/config.js';

describe('astro/src/core/compile', () => {
describe('Invalid CSS', () => {
Expand All @@ -14,8 +15,9 @@ describe('astro/src/core/compile', () => {
astroConfig: {
root: pathToFileURL('/'),
experimental: {},
},
} as AstroConfig,
viteConfig: await resolveConfig({ configFile: false }, 'serve'),
toolbarEnabled: false,
filename: '/src/pages/index.astro',
source: `
---
Expand All @@ -37,7 +39,7 @@ describe('astro/src/core/compile', () => {
}

assert.equal(error instanceof AggregateError, true);
assert.equal(error.errors[0].message.includes('expected ")"'), true);
assert.equal((error as AggregateError).errors[0].message.includes('expected ")"'), true);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ import { describe, it } from 'node:test';
import { pathToFileURL } from 'node:url';
import { resolveConfig } from 'vite';
import { compile } from '../../../dist/core/compile/compile-rs.js';
import type { AstroConfig } from '../../../dist/types/public/config.js';

/**
* @param {string} source
* @param {object} [configOverrides]
*/
async function compileWithRust(source, configOverrides = {}) {
async function compileWithRust(source: string, configOverrides: Partial<AstroConfig> = {}) {
const viteConfig = await resolveConfig({ configFile: false }, 'serve');
return compile({
astroConfig: {
Expand All @@ -20,7 +17,7 @@ async function compileWithRust(source, configOverrides = {}) {
devToolbar: { enabled: false },
site: undefined,
...configOverrides,
},
} as AstroConfig,
viteConfig,
toolbarEnabled: false,
filename: '/src/components/index.astro',
Expand Down Expand Up @@ -130,9 +127,10 @@ console.log('hello');
it('throws a CompilerError on unclosed tags', async () => {
await assert.rejects(
() => compileWithRust('<p>Unclosed tag'),
(err) => {
assert.ok(err.message || err.name);
assert.ok(err.message.includes('Unexpected token'));
(err: unknown) => {
const e = err as { message?: string; name?: string };
assert.ok(e.message || e.name);
assert.ok(e.message?.includes('Unexpected token'));
return true;
},
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ describe('mergeConfig', () => {
it('keeps server.allowedHosts as boolean', () => {
const defaults = {
server: {
allowedHosts: [],
// Typed as string[] to match AstroConfig's allowedHosts field
allowedHosts: [] as string[],
},
};
// allowedHosts can also be true (allow all) — cast to satisfy DeepPartial
const overrides = {
server: {
allowedHosts: true,
allowedHosts: true as boolean | string[],
},
};
const merged = mergeConfig(defaults, overrides);
const merged = mergeConfig(defaults, overrides as typeof defaults);
assert.equal(merged.server.allowedHosts, true);
});
});
Loading
Loading