Skip to content

Commit

Permalink
✨ Update error pages (#178)
Browse files Browse the repository at this point in the history
  • Loading branch information
perdy committed Mar 4, 2025
1 parent 6ce324f commit 4ece54d
Show file tree
Hide file tree
Showing 87 changed files with 8,607 additions and 13,583 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test_and_publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 16
node-version: 22
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test_pull_request_branch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 16
node-version: 22
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
Expand Down
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ dist/
downloads/
eggs/
.eggs/
lib/
./lib/
lib64/
parts/
sdist/
Expand Down Expand Up @@ -61,4 +61,5 @@ demo.db
test.db

# Templates
flama/templates
flama/templates
templates/out
18 changes: 12 additions & 6 deletions flama/debug/data_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ def from_exception(cls, exc: Exception, context: int = 10) -> "Error":
frames = inspect.getinnerframes(exc.__traceback__, context) if exc.__traceback__ else []
exc_cls = exc if inspect.isclass(exc) else exc.__class__
return cls(
error=f"{exc_cls.__module__}.{exc_cls.__name__}" if exc_cls.__module__ != "builtins" else exc_cls.__name__,
error=(
f"{exc_cls.__module__}.{exc_cls.__name__}"
if exc_cls.__module__ not in ("builtins", "__main__")
else exc_cls.__name__
),
description=str(exc),
traceback=[Frame.from_frame_info(frame=frame) for frame in frames],
)
Expand Down Expand Up @@ -144,20 +148,22 @@ def from_route(cls, route: t.Union["Route", "WebSocketRoute"]) -> "Endpoint":

@dataclasses.dataclass(frozen=True)
class App:
urls: list[t.Union[Endpoint, "App"]]
apps: list["App"]
endpoints: list[Endpoint]
path: str
name: t.Optional[str] = None

@classmethod
def from_app(cls, app: t.Any, path: str = "/", name: t.Optional[str] = None) -> "App":
urls: list[t.Union[Endpoint, App]] = []
apps: list[App] = []
endpoints: list[Endpoint] = []
for route in app.routes:
try:
urls.append(App.from_app(route.app, path=route.path.path, name=route.name))
apps.append(App.from_app(route.app, path=route.path.path, name=route.name))
except AttributeError:
urls.append(Endpoint.from_route(route))
endpoints.append(Endpoint.from_route(route))

return cls(urls=urls, path=path, name=name)
return cls(apps=apps, endpoints=endpoints, path=path, name=name)


@dataclasses.dataclass(frozen=True)
Expand Down
20 changes: 19 additions & 1 deletion flama/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,15 +210,30 @@ def __init__(self, *args, **kwargs):
*args,
**{
**kwargs,
"comment_start_string": "||*",
"comment_end_string": "*||",
"block_start_string": "||%",
"block_end_string": "%||",
"variable_start_string": "||@",
"variable_end_string": "@||",
},
)

self.filters["safe"] = self.safe
self.filters["safe_json"] = self.safe_json

@t.overload
def _escape(self, value: str) -> str: ...
@t.overload
def _escape(self, value: bool) -> bool: ...
@t.overload
def _escape(self, value: int) -> int: ...
@t.overload
def _escape(self, value: float) -> float: ...
@t.overload
def _escape(self, value: None) -> None: ...
@t.overload
def _escape(self, value: types.JSONField) -> types.JSONField: ...
def _escape(self, value: types.JSONField) -> types.JSONField:
if isinstance(value, (list, tuple)):
return [self._escape(x) for x in value]
Expand All @@ -227,10 +242,13 @@ def _escape(self, value: types.JSONField) -> types.JSONField:
return {k: self._escape(v) for k, v in value.items()}

if isinstance(value, str):
return html.escape(value).replace("\n", "
")
return html.escape(value).replace("\n", "

")

return value

def safe(self, value: str) -> str:
return self._escape(value)

def safe_json(self, value: types.JSONField):
return json.dumps(self._escape(value)).replace('"', '\\"')

Expand Down
2 changes: 1 addition & 1 deletion flama/types/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
__all__ = ["JSONField", "JSONSchema"]


JSONField = t.Union[str, int, float, bool, None, list["JSONField"], dict[str, "JSONField"]]
JSONField = t.Union[str, bool, int, float, None, list["JSONField"], dict[str, "JSONField"]]
JSONSchema = dict[str, JSONField]
48 changes: 48 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"@tabler/icons-react": "^3.30.0"
}
}
11 changes: 0 additions & 11 deletions templates/.babelrc

This file was deleted.

2 changes: 1 addition & 1 deletion templates/.eslintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*.config.js
*.config.ts
.husky/
node_modules/
node_modules/
23 changes: 23 additions & 0 deletions templates/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/** @type {import("@babel/core").TransformOptions} */
const config = {
presets: [
[
'@babel/preset-env',
{
targets: '> 0.25%, not dead',
useBuiltIns: 'usage',
corejs: { version: 3, proposals: true },
},
],
[
'@babel/preset-react',
{
runtime: 'automatic',
},
],
'@babel/preset-typescript',
],
plugins: ['@babel/plugin-transform-runtime', '@babel/plugin-transform-spread'],
}

export default config
58 changes: 58 additions & 0 deletions templates/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import path from 'node:path'

import js from '@eslint/js'
import prettierConfig from 'eslint-config-prettier'
import importPlugin from 'eslint-plugin-import'
import reactPlugin from 'eslint-plugin-react'
import reactHooksPlugin from 'eslint-plugin-react-hooks'
import globals from 'globals'
import ts from 'typescript-eslint'

/** @type {import("eslint").Linter.Config[]} */
export default [
{
ignores: ['.*.js', '.*.ts', 'node_modules/', 'dist/', '.next/', 'public/', 'out/'],
},
{
languageOptions: {
globals: { ...globals.browser, ...globals.node, ...globals.serviceworker },
},
},
prettierConfig,
js.configs.recommended,
...ts.configs.strict,
...ts.configs.stylistic,
{
files: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'],
...importPlugin.flatConfigs.recommended,
rules: {
// turn on errors for missing imports
'import/no-unresolved': 'error',
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^React$' }],
},
settings: {
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx'],
},
'import/resolver': {
typescript: {
project: path.resolve(process.cwd(), 'tsconfig.json'),
},
},
},
},
{
files: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'],
...reactPlugin.configs.flat.recommended,
plugins: {
...reactPlugin.configs.flat.recommended.plugins,
react: reactPlugin,
'react-hooks': reactHooksPlugin,
},
rules: {
...reactPlugin.configs.flat.recommended.rules,
...reactPlugin.configs['jsx-runtime'].rules,
...reactHooksPlugin.configs.recommended.rules,
},
},
]
Loading

0 comments on commit 4ece54d

Please sign in to comment.