nuxt-cereal
v1.3.2
Published
🥣 Cereal-ize JSON data into fully-typed constants, enums, & options in Nuxt.
Downloads
112
Readme
nuxt-cereal
🥣 Cereal-ize JSON data into literally-typed constants, enums, & options in Nuxt.
Configuration
- Install the module
pnpm add nuxt-cereal
- Create a config
// ~/cereal.config.ts
import { defineCerealConfig } from "nuxt-cereal/config";
export default defineCerealConfig({
constants: {
foo: "an example string",
},
enums: {
bar: ["primary", "secondary", "tertiary"],
},
options: {
baz: [
{ key: 1, label: "One" },
{ key: 2, label: "Two" },
],
},
});
- Activate the module
// ~/nuxt.config.ts
import cereal from "./cereal.config";
export default defineNuxtConfig({
modules: ["nuxt-cereal"],
cereal,
});
- Eat some cereal, you are done!
Features
Define a JSON config object for:
constants
A key/value collection of static strings & numbersenums
A key/value collection of static string arrays & number arraysoptions
A key/value collection of static option arrays w/key
&label
properties
The config object is "cereal-ized" into read-only literals & implemented in Nuxt using a set of utility types/composables.
Types
Type templates are created using the JSON definitions & are automatically available in composables/components:
| Type | Description |
| ----------------------------------- | ---------------------------------------------------- |
| Constant
| String-literal keys of the constants
cereal config |
| ConstantValue<C extends Constant>
| Literal value of the provided constants
config key |
| Enum
| String-literal keys of the enums
cereal config |
| EnumValue<E extends Enum>
| Literal values of the provided enums
config key |
| EnumValueItem<E extends Enum>
| Template values of the provided enums
config key |
| Option
| String-literal keys of the options
cereal config |
| OptionValue<O extends Option>
| Literal values of the provided options
config key |
| OptionValueItem<O extends Option>
| Template values of the provided options
config key |
Example
These utility types can be useful when creating components. Let's say we have a button component that has a variant
property that can be set to either filled
, outlined
, or plain
. We can configure that option as an enum
and use the helper types to define our component properties:
// ~/cereal.config.ts
export default defineCerealConfig({
enums: {
buttonVariant: ["filled", "outlined", "plain"],
},
});
<script setup lang="ts">
// ~/components/Button.vue
defineProps<{
variant: EnumValue<"buttonVariant">; // a string-literal type of the options in our config
}>();
</script>
<template>
<button :data-variant="variant">
<slot />
</button>
</template>
Functions
Type-safe utility functions that enable access to the configuration literal values are automatically imported in any component/composable:
| Function | Description |
| ---------------------- | ----------------------------------------------------------------------------- |
| isConstant(key)
| Check if a provided string is a constants
key & cast to Constant
if valid |
| useConstant(key)
| Grab the literal value represented by the provided constants
key |
| useConstantsConfig()
| Grab the entire constants
configuration as an object literal |
| useConstantsKeys()
| Grab an array ofavailable constants
configuration keys |
| isEnum(key)
| Check if a provided string is a enums
key & cast to Enum
if valid |
| useEnum(key)
| Grab the literal value represented by the provided enums
key |
| useEnumsConfig()
| Grab the entire enums
configuration as an object literal |
| useEnumsKeys()
| Grab an array ofavailable enums
configuration keys |
| isOption(key)
| Check if a provided string is a options
key & cast to Option
if valid |
| useOption(key)
| Grab the literal value represented by the provided options
key |
| useOptionsConfig()
| Grab the entire options
configuration as an object literal |
| useOptionsKeys()
| Grab an array ofavailable options
configuration keys |
Example
These functions can be leveraged w/ generics to extend the power of our components even further. Imagine we have a pre-defined set of dropdowns needed for a form. We can quickly build a component that uses our cereal-ized data to provide a type-safe selector that only needs a key
to get started:
// ~/cereal.config.ts
export default defineCerealConfig({
options: {
breakfast: [
{ key: "cereal", label: "Cereal" },
{ key: "pancakes", label: "Pancakes" },
{ key: "eggs", label: "Eggs" },
],
lunch: [
{ key: "sandwhich", label: "Sandwhich" },
{ key: "soup", label: "Soup" },
{ key: "salad", label: "Salad" },
],
dinner: [
{ key: "steak", label: "Steak" },
{ key: "lobster", label: "Lobster" },
{ key: "risotto", label: "Risotto" },
],
},
});
<script setup lang="ts" generic="O extends Option">
// ~/components/Select.vue
const props = defineProps<{
option: O; // "breakfast" | "lunch" | "dinner"
modelValue?: OptionValueItem<O>["key"]; // if "breakfast" is the option, allowed values are "cereal" | "pancakes" | "eggs"
}>();
const emits = defineEmits<{
"update:modelValue": [OptionValueItem<O>];
}>();
const options = useOption(props.option);
const modelValue = useVModel(props, "modelValue", emits, { passive: true }); // https://vueuse.org/core/useVModel/#usevmodel
</script>
<template>
<select v-model="modelValue">
<option v-for="o in options" :key="o.key" :value="o.key">
{{ o.label }}
</option>
</select>
</template>
License
MIT License © 2024-PRESENT Alexander Thorwaldson