Skip to content

Commit 6ec4852

Browse files
committed
docs: substantially improved code-level docs
Much more to do, but it's coming along!
1 parent 6807c9a commit 6ec4852

File tree

6 files changed

+171
-94
lines changed

6 files changed

+171
-94
lines changed

packages/perseus/src/error_pages.rs

+28-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,26 @@ use web_sys::Element;
2121
pub type ErrorPageTemplate<G> =
2222
Box<dyn Fn(Scope, String, u16, String, Option<Rc<Translator>>) -> View<G> + Send + Sync>;
2323

24-
/// A type alias for the `HashMap` the user should provide for error pages.
24+
/// A representation of the views configured in an app for responding to errors.
25+
///
26+
/// On the web, errors occur frequently beyond app logic, usually in communication
27+
/// with servers, which will return [HTTP status codes](https://httpstatuses.com/) that indicate
28+
/// a success or failure. If a non-success error code is received, then Perseus will
29+
/// automatically render the appropriate error page, based on that status code.
30+
/// If no page has been explicitly constructed for that status code, then the fallback
31+
/// page will be used.
32+
///
33+
/// Each error page is a closure returning a [`View`] that takes four parameters:
34+
/// a reactive scope, the URL the user was on when the error occurred (which they'll still
35+
/// be on, no route change occurs when rendering an error page), the status code itself,
36+
/// a `String` of the actual error message, and a [`Translator`] (which may not be available
37+
/// if the error occurred before translations data could be fetched and processed, in which
38+
/// case you should try to display language-agnostic information).
39+
///
40+
/// In development, you can get away with not defining any error pages for your app, as
41+
/// Perseus has a simple inbuilt default, though, when you try to go to production (e.g. with `perseus deploy`),
42+
/// you'll receive an error message in building. In other words, you must define your own error
43+
/// pages for release mode.
2544
pub struct ErrorPages<G: Html> {
2645
status_pages: HashMap<u16, ErrorPageTemplate<G>>,
2746
fallback: ErrorPageTemplate<G>,
@@ -32,7 +51,9 @@ impl<G: Html> std::fmt::Debug for ErrorPages<G> {
3251
}
3352
}
3453
impl<G: Html> ErrorPages<G> {
35-
/// Creates a new definition of error pages with just a fallback.
54+
/// Creates a new definition of error pages with just a fallback page, which will
55+
/// be used when an error occurs whose status code has not been explicitly handled by
56+
/// some other error page.
3657
pub fn new(
3758
fallback: impl Fn(Scope, String, u16, String, Option<Rc<Translator>>) -> View<G>
3859
+ Send
@@ -45,8 +66,10 @@ impl<G: Html> ErrorPages<G> {
4566
}
4667
}
4768
/// Adds a new page for the given status code. If a page was already defined
48-
/// for the given code, it will be updated by the mechanics of
49-
/// the internal `HashMap`.
69+
/// for the given code, it will be updated by replacement, through the mechanics of
70+
/// the internal `HashMap`. While there is no requirement for this to be a
71+
/// valid HTTP status code, there would be no point in defining a handler
72+
/// for a status code not on [this list](https://httpstatuses.com)
5073
pub fn add_page(
5174
&mut self,
5275
status: u16,
@@ -60,7 +83,7 @@ impl<G: Html> ErrorPages<G> {
6083
/// Adds a new page for the given status code. If a page was already defined
6184
/// for the given code, it will be updated by the mechanics of
6285
/// the internal `HashMap`. This differs from `.add_page()` in that it takes
63-
/// an `Rc`, which is useful for plugins.
86+
/// an `Rc`, which can be useful for plugins.
6487
pub fn add_page_rc(&mut self, status: u16, page: ErrorPageTemplate<G>) {
6588
self.status_pages.insert(status, page);
6689
}

packages/perseus/src/errors.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -255,9 +255,8 @@ impl<E: std::error::Error + Send + Sync + 'static> From<E> for GenericErrorWithC
255255
}
256256
}
257257

258-
/// Creates a new `GenericErrorWithCause` efficiently. This allows you to
259-
/// explicitly return errors from anything that returns
260-
/// `RenderFnResultWithCause`, which includes both an error and a statement of
258+
/// Creates a new [`GenericErrorWithCause` (the error type behind [`RenderFnResultWithCause`]) efficiently. This allows you to
259+
/// explicitly return errors from any state-generation functions, including both an error and a statement of
261260
/// whether the server or the client is responsible. With this macro, you can
262261
/// use any of the following syntaxes (substituting `"error!"` for any error
263262
/// that can be converted with `.into()` into a `Box<dyn std::error::Error>`):

packages/perseus/src/init.rs

+51-40
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,9 @@ where
9393
}
9494
}
9595

96-
/// The options for constructing a Perseus app. These encompass all the
97-
/// information Perseus needs to know to create your app. Every Perseus app
98-
/// using the engine must export one of these.
99-
///
100-
/// Note that this is an interim storage point, it's not depended on by any part
101-
/// of the core logic, and therefore custom engines can entirely ignore this.
96+
/// The options for constructing a Perseus app. This `struct` will tie
97+
/// together all your code, declaring to Perseus where your templates,
98+
/// error pages, static content, etc. are.
10299
#[derive(Debug)]
103100
pub struct PerseusAppBase<G: Html, M: MutableStore, T: TranslationsManager> {
104101
/// The HTML ID of the root `<div>` element into which Perseus will be
@@ -157,8 +154,8 @@ pub struct PerseusAppBase<G: Html, M: MutableStore, T: TranslationsManager> {
157154
// because things are completely generic there
158155
impl<G: Html, T: TranslationsManager> PerseusAppBase<G, FsMutableStore, T> {
159156
/// Creates a new instance of a Perseus app using the default
160-
/// filesystem-based mutable store. For most apps, this will be sufficient.
161-
/// Note that this initializes the translations manager as a dummy, and
157+
/// filesystem-based mutable store (see [`FsMutableStore`]). For most apps, this will be sufficient.
158+
/// Note that this initializes the translations manager as a dummy (see [`FsTranslationsManager`]), and
162159
/// adds no templates or error pages.
163160
///
164161
/// In development, you can get away with defining no error pages, but
@@ -174,8 +171,8 @@ impl<G: Html, T: TranslationsManager> PerseusAppBase<G, FsMutableStore, T> {
174171
Self::new_with_mutable_store(FsMutableStore::new("./dist/mutable".to_string()))
175172
}
176173
/// Creates a new instance of a Perseus app using the default
177-
/// filesystem-based mutable store. For most apps, this will be sufficient.
178-
/// Note that this initializes the translations manager as a dummy, and
174+
/// filesystem-based mutable store (see [`FsMutableStore`]). For most apps, this will be sufficient.
175+
/// Note that this initializes the translations manager as a dummy (see [`FsTranslationsManager`]), and
179176
/// adds no templates or error pages.
180177
///
181178
/// In development, you can get away with defining no error pages, but
@@ -195,8 +192,8 @@ impl<G: Html, T: TranslationsManager> PerseusAppBase<G, FsMutableStore, T> {
195192
// automatically for them
196193
impl<G: Html, M: MutableStore> PerseusAppBase<G, M, FsTranslationsManager> {
197194
/// The same as `.locales_and_translations_manager()`, but this accepts a
198-
/// literal `Locales` `struct`, which means this can be used when you're
199-
/// using `FsTranslationsManager` but when you don't know if your app is
195+
/// literal [`Locales`] `struct`, which means this can be used when you're
196+
/// using [`FsTranslationsManager`] but when you don't know if your app is
200197
/// using i18n or not (almost always middleware).
201198
pub fn locales_lit_and_translations_manager(mut self, locales: Locales) -> Self {
202199
#[cfg(not(target_arch = "wasm32"))]
@@ -233,7 +230,7 @@ impl<G: Html, M: MutableStore> PerseusAppBase<G, M, FsTranslationsManager> {
233230
self
234231
}
235232
/// Sets the internationalization information for an app using the default
236-
/// translations manager (`FsTranslationsManager`). This handles locale
233+
/// translations manager ([`FsTranslationsManager`]). This handles locale
237234
/// caching and the like automatically for you, though you could
238235
/// alternatively use `.locales()` and `.translations_manager()`
239236
/// independently to customize various behaviors. This takes the same
@@ -260,7 +257,8 @@ impl<G: Html, M: MutableStore> PerseusAppBase<G, M, FsTranslationsManager> {
260257
// manager
261258
impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
262259
/// Creates a new instance of a Perseus app, with the default options and a
263-
/// custom mutable store.
260+
/// customizable [`MutableStore`], using the default dummy [`FsTranslationsManager`]
261+
/// by default (though this can be changed).
264262
#[allow(unused_variables)]
265263
pub fn new_with_mutable_store(mutable_store: M) -> Self {
266264
Self {
@@ -302,6 +300,7 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
302300
/// Internal function for Wasm initialization. This should never be called
303301
/// by the user!
304302
#[cfg(target_arch = "wasm32")]
303+
#[doc(hidden)]
305304
fn new_wasm() -> Self {
306305
Self {
307306
root: "root".to_string(),
@@ -328,12 +327,18 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
328327

329328
// Setters (these all consume `self`)
330329
/// Sets the HTML ID of the `<div>` element at which to insert Perseus.
330+
/// In your index view, this should use [`PerseusRoot`].
331+
///
332+
/// *Note:* if you're using string HTML, the `<div>` with this ID MUST look
333+
/// *exactly* like this: `<div id="some-id-here"></div>`, spacing and
334+
/// all!
331335
pub fn root(mut self, val: &str) -> Self {
332336
self.root = val.to_string();
333337
self
334338
}
335339
/// Sets the location of the directory storing static assets to be hosted
336-
/// under the URL `/.perseus/static/`.
340+
/// under the URL `/.perseus/static/`. By default, this is `static/` at
341+
/// the root of your project.
337342
#[allow(unused_variables)]
338343
#[allow(unused_mut)]
339344
pub fn static_dir(mut self, val: &str) -> Self {
@@ -345,22 +350,27 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
345350
}
346351
/// Sets all the app's templates. This takes a vector of boxed functions
347352
/// that return templates.
353+
///
354+
/// Usually, it's preferred to run `.template()` once for each template,
355+
/// rather than manually constructing this more inconvenient type.
348356
pub fn templates(mut self, val: Vec<Box<dyn Fn() -> Template<G>>>) -> Self {
349357
self.template_getters.0 = val;
350358
self
351359
}
352360
/// Adds a single new template to the app (convenience function). This takes
353-
/// a function that returns a template.
361+
/// a *function that returns a template* (for internal reasons).
362+
///
363+
/// See [`Template`] for further details.
354364
pub fn template(mut self, val: impl Fn() -> Template<G> + 'static) -> Self {
355365
self.template_getters.0.push(Box::new(val));
356366
self
357367
}
358-
/// Sets the app's error pages.
368+
/// Sets the app's error pages. See [`ErrorPages`] for further details.
359369
pub fn error_pages(mut self, val: impl Fn() -> ErrorPages<G> + 'static) -> Self {
360370
self.error_pages = ErrorPagesGetter(Box::new(val));
361371
self
362372
}
363-
/// Sets the app's global state creator.
373+
/// Sets the app's [`GlobalStateCreator`].
364374
#[allow(unused_variables)]
365375
#[allow(unused_mut)]
366376
pub fn global_state_creator(mut self, val: GlobalStateCreator) -> Self {
@@ -376,7 +386,7 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
376386
/// supported.
377387
///
378388
/// Note that this does not update the translations manager, which must be
379-
/// done separately (if you're using `FsTranslationsManager`, the default,
389+
/// done separately (if you're using [`FsTranslationsManager`], the default,
380390
/// you can use `.locales_and_translations_manager()` to set both at
381391
/// once).
382392
///
@@ -393,23 +403,23 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
393403
};
394404
self
395405
}
396-
/// Sets the locales information directly based on an instance of `Locales`.
406+
/// Sets the locales information directly based on an instance of [`Locales`].
397407
/// Usually, end users will use `.locales()` instead for a friendlier
398408
/// interface.
399409
pub fn locales_lit(mut self, val: Locales) -> Self {
400410
self.locales = val;
401411
self
402412
}
403413
/// Sets the translations manager. If you're using the default translations
404-
/// manager (`FsTranslationsManager`), you can use
414+
/// manager ([`FsTranslationsManager`]), you can use
405415
/// `.locales_and_translations_manager()` to set this automatically
406416
/// based on the locales information. This takes a `Future<Output = T>`,
407417
/// where `T` is your translations manager's type.
408418
///
409419
/// The reason that this takes a `Future` is to avoid the use of `.await` in
410420
/// your app definition code, which must be synchronous due to constraints
411-
/// of Perseus' client-side systems. When your code is run on the
412-
/// server, the `Future` will be `.await`ed on, but on Wasm, it will be
421+
/// of Perseus' browser-side systems. When your code is run on the
422+
/// server, the `Future` will be `.await`ed on, but in Wasm, it will be
413423
/// discarded and ignored, since the translations manager isn't needed in
414424
/// Wasm.
415425
///
@@ -444,7 +454,8 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
444454
}
445455
/// Sets all the app's static aliases. This takes a map of URLs (e.g.
446456
/// `/file`) to resource paths, relative to the project directory (e.g.
447-
/// `style.css`).
457+
/// `style.css`). Generally, calling `.static_alias()` many times is
458+
/// preferred.
448459
#[allow(unused_variables)]
449460
#[allow(unused_mut)]
450461
pub fn static_aliases(mut self, val: HashMap<String, String>) -> Self {
@@ -454,8 +465,7 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
454465
}
455466
self
456467
}
457-
/// Adds a single static alias (convenience function). This takes a URL path
458-
/// (e.g. `/file`) followed by a path to a resource (which must be within
468+
/// Adds a single static alias. This takes a URL path (e.g. `/file`) followed by a path to a resource (which must be within
459469
/// the project directory, e.g. `style.css`).
460470
#[allow(unused_variables)]
461471
#[allow(unused_mut)]
@@ -466,12 +476,13 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
466476
.insert(url.to_string(), resource.to_string());
467477
self
468478
}
469-
/// Sets the plugins that the app will use.
479+
/// Sets the plugins that the app will use. See [`Plugins`] for
480+
/// further details.
470481
pub fn plugins(mut self, val: Plugins<G>) -> Self {
471482
self.plugins = Rc::new(val);
472483
self
473484
}
474-
/// Sets the mutable store for the app to use, which you would change for
485+
/// Sets the [`MutableStore`] for the app to use, which you would change for
475486
/// some production server environments if you wanted to store build
476487
/// artifacts that can change at runtime in a place other than on the
477488
/// filesystem (created for serverless functions specifically).
@@ -484,7 +495,7 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
484495
}
485496
self
486497
}
487-
/// Sets the immutable store for the app to use. You should almost never
498+
/// Sets the [`ImmutableStore`] for the app to use. You should almost never
488499
/// need to change this unless you're not working with the CLI.
489500
#[allow(unused_variables)]
490501
#[allow(unused_mut)]
@@ -550,7 +561,7 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
550561
/// this into `::get_html_shell()` to do that).
551562
///
552563
/// Note that this automatically adds `<!DOCTYPE html>` to the start of the
553-
/// HTMl shell produced, which can only be overriden with a control plugin
564+
/// HTML shell produced, which can only be overriden with a control plugin
554565
/// (though you should really never do this in Perseus, which targets
555566
/// HTML on the web).
556567
#[cfg(not(target_arch = "wasm32"))]
@@ -715,7 +726,7 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
715726

716727
map
717728
}
718-
/// Gets the error pages used in the app. This returns an `Rc`.
729+
/// Gets the [`ErrorPages`] used in the app. This returns an `Rc`.
719730
pub fn get_error_pages(&self) -> ErrorPages<G> {
720731
let mut error_pages = (self.error_pages.0)();
721732
let extra_error_pages = self
@@ -732,7 +743,7 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
732743

733744
error_pages
734745
}
735-
/// Gets the global state creator. This can't be directly modified by
746+
/// Gets the [`GlobalStateCreator`]. This can't be directly modified by
736747
/// plugins because of reactive type complexities.
737748
#[cfg(not(target_arch = "wasm32"))]
738749
pub fn get_global_state_creator(&self) -> Arc<GlobalStateCreator> {
@@ -748,7 +759,7 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
748759
.run(locales.clone(), self.plugins.get_plugin_data())
749760
.unwrap_or(locales)
750761
}
751-
/// Gets the server-side translations manager. Like the mutable store, this
762+
/// Gets the server-side [`TranslationsManager`]. Like the mutable store, this
752763
/// can't be modified by plugins due to trait complexities.
753764
///
754765
/// This involves evaluating the future stored for the translations manager,
@@ -760,7 +771,7 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
760771
Tm::Full(tm) => tm.await,
761772
}
762773
}
763-
/// Gets the immutable store.
774+
/// Gets the [`ImmutableStore`].
764775
#[cfg(not(target_arch = "wasm32"))]
765776
pub fn get_immutable_store(&self) -> ImmutableStore {
766777
let immutable_store = self.immutable_store.clone();
@@ -771,7 +782,7 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
771782
.run(immutable_store.clone(), self.plugins.get_plugin_data())
772783
.unwrap_or(immutable_store)
773784
}
774-
/// Gets the mutable store. This can't be modified by plugins due to trait
785+
/// Gets the [`MutableStore`]. This can't be modified by plugins due to trait
775786
/// complexities, so plugins should instead expose a function that the user
776787
/// can use to manually set it.
777788
#[cfg(not(target_arch = "wasm32"))]
@@ -838,7 +849,7 @@ impl<G: Html, M: MutableStore, T: TranslationsManager> PerseusAppBase<G, M, T> {
838849
}
839850

840851
/// The component that represents the entrypoint at which Perseus will inject
841-
/// itself. You can use this with the `.index_view()` method of `PerseusApp` to
852+
/// itself. You can use this with the `.index_view()` method of [`PerseusAppBase`] to
842853
/// avoid having to create the entrypoint `<div>` manually.
843854
#[component]
844855
#[allow(non_snake_case)]
@@ -852,13 +863,13 @@ use crate::i18n::FsTranslationsManager;
852863
use crate::stores::FsMutableStore;
853864

854865
/// An alias for the usual kind of Perseus app, which uses the filesystem-based
855-
/// mutable store and translations manager.
866+
/// mutable store and translations manager. See [`PerseusAppBase`] for details.
856867
pub type PerseusApp<G> = PerseusAppBase<G, FsMutableStore, FsTranslationsManager>;
857-
/// An alias for a Perseus app that uses a custom mutable store type.
868+
/// An alias for a Perseus app that uses a custom mutable store type. See [`PerseusAppBase`] for details.
858869
pub type PerseusAppWithMutableStore<G, M> = PerseusAppBase<G, M, FsTranslationsManager>;
859-
/// An alias for a Perseus app that uses a custom translations manager type.
870+
/// An alias for a Perseus app that uses a custom translations manager type. See [`PerseusAppBase`] for details.
860871
pub type PerseusAppWithTranslationsManager<G, T> = PerseusAppBase<G, FsMutableStore, T>;
861872
/// An alias for a fully customizable Perseus app that can accept a custom
862873
/// mutable store and a custom translations manager. Alternatively, you could
863-
/// just use `PerseusAppBase` directly.
874+
/// just use [`PerseusAppBase`] directly.
864875
pub type PerseusAppWithMutableStoreAndTranslationsManager<G, M, T> = PerseusAppBase<G, M, T>;

0 commit comments

Comments
 (0)