- Delete old Vite+Svelte frontend - Initialize new SvelteKit project with TypeScript - Configure Tailwind CSS v4 + DaisyUI - Implement JWT authentication with auto-refresh - Create login page with form validation (Zod) - Add protected route guards - Update Docker configuration for single-stage build - Add E2E tests with Playwright (6/11 passing) - Fix Svelte 5 reactivity with $state() runes Known issues: - 5 E2E tests failing (timing/async issues) - Token refresh implementation needs debugging - Validation error display timing
149 lines
6.1 KiB
JavaScript
149 lines
6.1 KiB
JavaScript
import { FindVariableContext } from './ast-utils.js';
|
|
export function extractExpressionPrefixVariable(context, expression) {
|
|
return extractExpressionPrefixVariableInternal(new FindVariableContext(context), expression);
|
|
}
|
|
export function extractExpressionPrefixLiteral(context, expression) {
|
|
return extractExpressionPrefixLiteralInternal(new FindVariableContext(context), expression);
|
|
}
|
|
export function extractExpressionSuffixLiteral(context, expression) {
|
|
return extractExpressionSuffixLiteralInternal(new FindVariableContext(context), expression);
|
|
}
|
|
// Variable prefix extraction
|
|
function extractExpressionPrefixVariableInternal(context, expression) {
|
|
switch (expression.type) {
|
|
case 'BinaryExpression':
|
|
return extractBinaryExpressionPrefixVariable(context, expression);
|
|
case 'Identifier':
|
|
return extractVariablePrefixVariable(context, expression);
|
|
case 'MemberExpression':
|
|
return extractMemberExpressionPrefixVariable(expression);
|
|
case 'TemplateLiteral':
|
|
return extractTemplateLiteralPrefixVariable(context, expression);
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
function extractBinaryExpressionPrefixVariable(context, expression) {
|
|
return expression.left.type !== 'PrivateIdentifier'
|
|
? extractExpressionPrefixVariableInternal(context, expression.left)
|
|
: null;
|
|
}
|
|
function extractVariablePrefixVariable(context, expression) {
|
|
const variable = context.findVariable(expression);
|
|
if (variable === null ||
|
|
variable.identifiers.length !== 1 ||
|
|
variable.identifiers[0].parent.type !== 'VariableDeclarator' ||
|
|
variable.identifiers[0].parent.init === null) {
|
|
return expression;
|
|
}
|
|
return (extractExpressionPrefixVariableInternal(context, variable.identifiers[0].parent.init) ??
|
|
expression);
|
|
}
|
|
function extractMemberExpressionPrefixVariable(expression) {
|
|
return expression.property.type === 'Identifier' ? expression.property : null;
|
|
}
|
|
function extractTemplateLiteralPrefixVariable(context, expression) {
|
|
const literalParts = [...expression.expressions, ...expression.quasis].sort((a, b) => a.range[0] < b.range[0] ? -1 : 1);
|
|
for (const part of literalParts) {
|
|
if (part.type === 'TemplateElement' && part.value.raw === '') {
|
|
// Skip empty quasi in the begining
|
|
continue;
|
|
}
|
|
if (part.type !== 'TemplateElement') {
|
|
return extractExpressionPrefixVariableInternal(context, part);
|
|
}
|
|
return null;
|
|
}
|
|
return null;
|
|
}
|
|
// Literal prefix extraction
|
|
function extractExpressionPrefixLiteralInternal(context, expression) {
|
|
switch (expression.type) {
|
|
case 'BinaryExpression':
|
|
return extractBinaryExpressionPrefixLiteral(context, expression);
|
|
case 'Identifier':
|
|
return extractVariablePrefixLiteral(context, expression);
|
|
case 'Literal':
|
|
return typeof expression.value === 'string' ? expression.value : null;
|
|
case 'SvelteLiteral':
|
|
return expression.value;
|
|
case 'TemplateLiteral':
|
|
return extractTemplateLiteralPrefixLiteral(context, expression);
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
function extractBinaryExpressionPrefixLiteral(context, expression) {
|
|
return expression.left.type !== 'PrivateIdentifier'
|
|
? extractExpressionPrefixLiteralInternal(context, expression.left)
|
|
: null;
|
|
}
|
|
function extractVariablePrefixLiteral(context, expression) {
|
|
const variable = context.findVariable(expression);
|
|
if (variable === null ||
|
|
variable.identifiers.length !== 1 ||
|
|
variable.identifiers[0].parent.type !== 'VariableDeclarator' ||
|
|
variable.identifiers[0].parent.init === null) {
|
|
return null;
|
|
}
|
|
return extractExpressionPrefixLiteralInternal(context, variable.identifiers[0].parent.init);
|
|
}
|
|
function extractTemplateLiteralPrefixLiteral(context, expression) {
|
|
const literalParts = [...expression.expressions, ...expression.quasis].sort((a, b) => a.range[0] < b.range[0] ? -1 : 1);
|
|
for (const part of literalParts) {
|
|
if (part.type === 'TemplateElement') {
|
|
if (part.value.raw === '') {
|
|
// Skip empty quasi
|
|
continue;
|
|
}
|
|
return part.value.raw;
|
|
}
|
|
return extractExpressionPrefixLiteralInternal(context, part);
|
|
}
|
|
return null;
|
|
}
|
|
// Literal suffix extraction
|
|
function extractExpressionSuffixLiteralInternal(context, expression) {
|
|
switch (expression.type) {
|
|
case 'BinaryExpression':
|
|
return extractBinaryExpressionSuffixLiteral(context, expression);
|
|
case 'Identifier':
|
|
return extractVariableSuffixLiteral(context, expression);
|
|
case 'Literal':
|
|
return typeof expression.value === 'string' ? expression.value : null;
|
|
case 'SvelteLiteral':
|
|
return expression.value;
|
|
case 'TemplateLiteral':
|
|
return extractTemplateLiteralSuffixLiteral(context, expression);
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
function extractBinaryExpressionSuffixLiteral(context, expression) {
|
|
return extractExpressionSuffixLiteralInternal(context, expression.right);
|
|
}
|
|
function extractVariableSuffixLiteral(context, expression) {
|
|
const variable = context.findVariable(expression);
|
|
if (variable === null ||
|
|
variable.identifiers.length !== 1 ||
|
|
variable.identifiers[0].parent.type !== 'VariableDeclarator' ||
|
|
variable.identifiers[0].parent.init === null) {
|
|
return null;
|
|
}
|
|
return extractExpressionSuffixLiteralInternal(context, variable.identifiers[0].parent.init);
|
|
}
|
|
function extractTemplateLiteralSuffixLiteral(context, expression) {
|
|
const literalParts = [...expression.expressions, ...expression.quasis].sort((a, b) => a.range[0] < b.range[0] ? -1 : 1);
|
|
for (const part of literalParts.reverse()) {
|
|
if (part.type === 'TemplateElement') {
|
|
if (part.value.raw === '') {
|
|
// Skip empty quasi
|
|
continue;
|
|
}
|
|
return part.value.raw;
|
|
}
|
|
return extractExpressionSuffixLiteralInternal(context, part);
|
|
}
|
|
return null;
|
|
}
|