contentbase 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +460 -0
- package/bun.lock +473 -0
- package/examples/sdlc-queries.ts +161 -0
- package/package.json +41 -0
- package/showcases/national-parks/models.ts +74 -0
- package/showcases/national-parks/parks/acadia.mdx +40 -0
- package/showcases/national-parks/parks/yosemite.mdx +44 -0
- package/showcases/national-parks/parks/zion.mdx +44 -0
- package/showcases/national-parks/queries.ts +103 -0
- package/showcases/national-parks/trails/angels-landing.mdx +19 -0
- package/showcases/national-parks/trails/cathedral-lakes.mdx +19 -0
- package/showcases/national-parks/trails/half-dome.mdx +19 -0
- package/showcases/national-parks/trails/jordan-pond-path.mdx +19 -0
- package/showcases/national-parks/trails/mist-trail.mdx +19 -0
- package/showcases/national-parks/trails/observation-point.mdx +19 -0
- package/showcases/national-parks/trails/precipice-trail.mdx +19 -0
- package/showcases/national-parks/trails/the-narrows.mdx +19 -0
- package/showcases/recipes/cuisines/chinese.mdx +28 -0
- package/showcases/recipes/cuisines/italian.mdx +32 -0
- package/showcases/recipes/cuisines/mexican.mdx +28 -0
- package/showcases/recipes/models.ts +77 -0
- package/showcases/recipes/queries.ts +89 -0
- package/showcases/recipes/recipes/chinese/egg-fried-rice.mdx +43 -0
- package/showcases/recipes/recipes/chinese/mapo-tofu.mdx +47 -0
- package/showcases/recipes/recipes/italian/bruschetta.mdx +38 -0
- package/showcases/recipes/recipes/italian/cacio-e-pepe.mdx +39 -0
- package/showcases/recipes/recipes/italian/tiramisu.mdx +43 -0
- package/showcases/recipes/recipes/mexican/chicken-tinga.mdx +44 -0
- package/showcases/recipes/recipes/mexican/guacamole.mdx +39 -0
- package/showcases/vinyl-collection/albums/bitches-brew.mdx +36 -0
- package/showcases/vinyl-collection/albums/i-put-a-spell-on-you.mdx +35 -0
- package/showcases/vinyl-collection/albums/in-rainbows.mdx +35 -0
- package/showcases/vinyl-collection/albums/kind-of-blue.mdx +32 -0
- package/showcases/vinyl-collection/albums/ok-computer.mdx +37 -0
- package/showcases/vinyl-collection/albums/wild-is-the-wind.mdx +35 -0
- package/showcases/vinyl-collection/artists/miles-davis.mdx +27 -0
- package/showcases/vinyl-collection/artists/nina-simone.mdx +26 -0
- package/showcases/vinyl-collection/artists/radiohead.mdx +27 -0
- package/showcases/vinyl-collection/models.ts +73 -0
- package/showcases/vinyl-collection/queries.ts +87 -0
- package/src/ast-query.ts +132 -0
- package/src/cli/commands/action.ts +44 -0
- package/src/cli/commands/create.ts +59 -0
- package/src/cli/commands/export.ts +24 -0
- package/src/cli/commands/init.ts +75 -0
- package/src/cli/commands/inspect.ts +46 -0
- package/src/cli/commands/validate.ts +75 -0
- package/src/cli/index.ts +20 -0
- package/src/cli/load-collection.ts +53 -0
- package/src/collection.ts +399 -0
- package/src/define-model.ts +80 -0
- package/src/document.ts +468 -0
- package/src/index.ts +47 -0
- package/src/model-instance.ts +227 -0
- package/src/node-shortcuts.ts +87 -0
- package/src/parse.ts +123 -0
- package/src/query/collection-query.ts +149 -0
- package/src/query/index.ts +5 -0
- package/src/query/operators.ts +37 -0
- package/src/query/query-builder.ts +109 -0
- package/src/relationships/belongs-to.ts +50 -0
- package/src/relationships/has-many.ts +136 -0
- package/src/relationships/index.ts +57 -0
- package/src/relationships/types.ts +7 -0
- package/src/section.ts +29 -0
- package/src/types.ts +221 -0
- package/src/utils/index.ts +11 -0
- package/src/utils/inflect.ts +82 -0
- package/src/utils/normalize-headings.ts +31 -0
- package/src/utils/parse-table.ts +30 -0
- package/src/utils/read-directory.ts +35 -0
- package/src/utils/stringify-ast.ts +9 -0
- package/src/validator.ts +52 -0
- package/test/ast-query.test.ts +128 -0
- package/test/collection.test.ts +99 -0
- package/test/define-model.test.ts +78 -0
- package/test/document.test.ts +225 -0
- package/test/fixtures/sdlc/epics/authentication.mdx +42 -0
- package/test/fixtures/sdlc/epics/searching-and-browsing.mdx +21 -0
- package/test/fixtures/sdlc/models.ts +89 -0
- package/test/fixtures/sdlc/stories/authentication/a-user-should-be-able-to-register.mdx +20 -0
- package/test/helpers.ts +21 -0
- package/test/model-instance.test.ts +197 -0
- package/test/query.test.ts +167 -0
- package/test/relationships.test.ts +84 -0
- package/test/section.test.ts +99 -0
- package/test/validator.test.ts +62 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +11 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
region: East Asia
|
|
3
|
+
spiceLevel: medium
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Chinese
|
|
7
|
+
|
|
8
|
+
Chinese cuisine spans thousands of years and dozens of regional traditions. The emphasis on wok technique, balancing the five flavors, and textural contrast sets it apart.
|
|
9
|
+
|
|
10
|
+
## Staple Ingredients
|
|
11
|
+
|
|
12
|
+
- Soy sauce
|
|
13
|
+
- Sesame oil
|
|
14
|
+
- Rice vinegar
|
|
15
|
+
- Ginger
|
|
16
|
+
- Scallions
|
|
17
|
+
- Shaoxing wine
|
|
18
|
+
- Cornstarch
|
|
19
|
+
|
|
20
|
+
## Recipes
|
|
21
|
+
|
|
22
|
+
### Mapo Tofu
|
|
23
|
+
|
|
24
|
+
Silken tofu in a fiery, numbing sauce — the signature dish of Sichuan province.
|
|
25
|
+
|
|
26
|
+
### Egg Fried Rice
|
|
27
|
+
|
|
28
|
+
The ultimate pantry-clearing weeknight meal, elevated by proper wok technique.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
region: Southern Europe
|
|
3
|
+
spiceLevel: mild
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Italian
|
|
7
|
+
|
|
8
|
+
Italian cooking centers on simplicity — fresh, high-quality ingredients prepared with minimal fuss. Regional variation is enormous, from the butter-rich dishes of the north to the olive-oil-and-tomato base of the south.
|
|
9
|
+
|
|
10
|
+
## Staple Ingredients
|
|
11
|
+
|
|
12
|
+
- Olive oil
|
|
13
|
+
- Garlic
|
|
14
|
+
- San Marzano tomatoes
|
|
15
|
+
- Parmigiano-Reggiano
|
|
16
|
+
- Fresh basil
|
|
17
|
+
- Dried pasta
|
|
18
|
+
- Mozzarella
|
|
19
|
+
|
|
20
|
+
## Recipes
|
|
21
|
+
|
|
22
|
+
### Cacio e Pepe
|
|
23
|
+
|
|
24
|
+
A Roman classic that turns three ingredients into something transcendent.
|
|
25
|
+
|
|
26
|
+
### Tiramisu
|
|
27
|
+
|
|
28
|
+
The iconic layered coffee dessert — no baking required.
|
|
29
|
+
|
|
30
|
+
### Bruschetta
|
|
31
|
+
|
|
32
|
+
Toasted bread with ripe tomatoes, garlic, and basil.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
region: North America
|
|
3
|
+
spiceLevel: hot
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Mexican
|
|
7
|
+
|
|
8
|
+
Mexican food is built on a foundation of corn, beans, and chiles that predates European contact. The layering of salsas, fresh garnishes, and slow-cooked meats makes it endlessly satisfying.
|
|
9
|
+
|
|
10
|
+
## Staple Ingredients
|
|
11
|
+
|
|
12
|
+
- Dried chiles (ancho, guajillo, chipotle)
|
|
13
|
+
- Corn tortillas
|
|
14
|
+
- Black beans
|
|
15
|
+
- Cilantro
|
|
16
|
+
- Limes
|
|
17
|
+
- Cumin
|
|
18
|
+
- Avocado
|
|
19
|
+
|
|
20
|
+
## Recipes
|
|
21
|
+
|
|
22
|
+
### Guacamole
|
|
23
|
+
|
|
24
|
+
The essential dip — ripe avocados, lime, and a little heat.
|
|
25
|
+
|
|
26
|
+
### Chicken Tinga
|
|
27
|
+
|
|
28
|
+
Shredded chicken braised in a smoky chipotle-tomato sauce.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineModel,
|
|
3
|
+
section,
|
|
4
|
+
hasMany,
|
|
5
|
+
belongsTo,
|
|
6
|
+
z,
|
|
7
|
+
} from "../../src/index";
|
|
8
|
+
import { toString } from "mdast-util-to-string";
|
|
9
|
+
import { parseTable } from "../../src/utils/parse-table";
|
|
10
|
+
|
|
11
|
+
// ─── Cuisine (parent) ───
|
|
12
|
+
|
|
13
|
+
export const Cuisine = defineModel("Cuisine", {
|
|
14
|
+
prefix: "cuisines",
|
|
15
|
+
meta: z.object({
|
|
16
|
+
region: z.string(),
|
|
17
|
+
spiceLevel: z.enum(["mild", "medium", "hot", "very-hot"]).optional(),
|
|
18
|
+
}),
|
|
19
|
+
sections: {
|
|
20
|
+
stapleIngredients: section("Staple Ingredients", {
|
|
21
|
+
extract: (q) => q.selectAll("listItem").map((n) => toString(n)),
|
|
22
|
+
schema: z.array(z.string()),
|
|
23
|
+
}),
|
|
24
|
+
},
|
|
25
|
+
relationships: {
|
|
26
|
+
recipes: hasMany(() => Recipe, { heading: "Recipes" }),
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// ─── Recipe ───
|
|
31
|
+
|
|
32
|
+
export const Recipe = defineModel("Recipe", {
|
|
33
|
+
prefix: "recipes",
|
|
34
|
+
meta: z.object({
|
|
35
|
+
course: z.enum(["appetizer", "main", "side", "dessert", "drink"]),
|
|
36
|
+
servings: z.number(),
|
|
37
|
+
prepTime: z.string(),
|
|
38
|
+
cookTime: z.string(),
|
|
39
|
+
difficulty: z.enum(["easy", "medium", "hard"]).default("medium"),
|
|
40
|
+
cuisine: z.string().optional(),
|
|
41
|
+
vegetarian: z.boolean().default(false),
|
|
42
|
+
}),
|
|
43
|
+
sections: {
|
|
44
|
+
ingredients: section("Ingredients", {
|
|
45
|
+
extract: (q) => {
|
|
46
|
+
const tables = q.selectAll("table");
|
|
47
|
+
if (tables.length > 0) {
|
|
48
|
+
return parseTable(tables[0]);
|
|
49
|
+
}
|
|
50
|
+
return q.selectAll("listItem").map((n) => toString(n));
|
|
51
|
+
},
|
|
52
|
+
schema: z.union([
|
|
53
|
+
z.array(z.record(z.string(), z.string())),
|
|
54
|
+
z.array(z.string()),
|
|
55
|
+
]),
|
|
56
|
+
}),
|
|
57
|
+
steps: section("Steps", {
|
|
58
|
+
extract: (q) => q.selectAll("listItem").map((n) => toString(n)),
|
|
59
|
+
schema: z.array(z.string()).min(1),
|
|
60
|
+
}),
|
|
61
|
+
notes: section("Notes", {
|
|
62
|
+
extract: (q) => q.selectAll("listItem").map((n) => toString(n)),
|
|
63
|
+
schema: z.array(z.string()),
|
|
64
|
+
}),
|
|
65
|
+
},
|
|
66
|
+
relationships: {
|
|
67
|
+
cuisine: belongsTo(() => Cuisine, {
|
|
68
|
+
foreignKey: (doc) => doc.meta.cuisine as string,
|
|
69
|
+
}),
|
|
70
|
+
},
|
|
71
|
+
computed: {
|
|
72
|
+
isQuick: (self: any) => {
|
|
73
|
+
const mins = parseInt(self.meta.prepTime) + parseInt(self.meta.cookTime);
|
|
74
|
+
return mins <= 30;
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example queries for the Recipes showcase.
|
|
3
|
+
*
|
|
4
|
+
* Run with: bun showcases/recipes/queries.ts
|
|
5
|
+
*/
|
|
6
|
+
import { Collection } from "../../src/index";
|
|
7
|
+
import { Cuisine, Recipe } from "./models";
|
|
8
|
+
|
|
9
|
+
const collection = new Collection({
|
|
10
|
+
rootPath: new URL(".", import.meta.url).pathname,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
collection.register(Cuisine);
|
|
14
|
+
collection.register(Recipe);
|
|
15
|
+
await collection.load();
|
|
16
|
+
|
|
17
|
+
// ── All recipes ──
|
|
18
|
+
const allRecipes = await collection.query(Recipe).fetchAll();
|
|
19
|
+
console.log(`Total recipes: ${allRecipes.length}`);
|
|
20
|
+
|
|
21
|
+
// ── Filter by course ──
|
|
22
|
+
const appetizers = await collection
|
|
23
|
+
.query(Recipe)
|
|
24
|
+
.where("meta.course", "appetizer")
|
|
25
|
+
.fetchAll();
|
|
26
|
+
console.log(`\nAppetizers: ${appetizers.map((r) => r.title).join(", ")}`);
|
|
27
|
+
|
|
28
|
+
const mains = await collection
|
|
29
|
+
.query(Recipe)
|
|
30
|
+
.where("meta.course", "main")
|
|
31
|
+
.fetchAll();
|
|
32
|
+
console.log(`Mains: ${mains.map((r) => r.title).join(", ")}`);
|
|
33
|
+
|
|
34
|
+
const desserts = await collection
|
|
35
|
+
.query(Recipe)
|
|
36
|
+
.where("meta.course", "dessert")
|
|
37
|
+
.fetchAll();
|
|
38
|
+
console.log(`Desserts: ${desserts.map((r) => r.title).join(", ")}`);
|
|
39
|
+
|
|
40
|
+
// ── Vegetarian recipes ──
|
|
41
|
+
const veggie = await collection
|
|
42
|
+
.query(Recipe)
|
|
43
|
+
.where("meta.vegetarian", true)
|
|
44
|
+
.fetchAll();
|
|
45
|
+
console.log(
|
|
46
|
+
`\nVegetarian recipes: ${veggie.map((r) => r.title).join(", ")}`
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// ── Easy recipes ──
|
|
50
|
+
const easyOnes = await collection
|
|
51
|
+
.query(Recipe)
|
|
52
|
+
.where("meta.difficulty", "easy")
|
|
53
|
+
.fetchAll();
|
|
54
|
+
console.log(`Easy recipes: ${easyOnes.map((r) => r.title).join(", ")}`);
|
|
55
|
+
|
|
56
|
+
// ── Ingredients as structured data ──
|
|
57
|
+
const cacioEPepe = await collection.query(Recipe).first();
|
|
58
|
+
if (cacioEPepe) {
|
|
59
|
+
console.log(`\n--- ${cacioEPepe.title} ---`);
|
|
60
|
+
console.log("Ingredients (table data):", cacioEPepe.sections.ingredients);
|
|
61
|
+
console.log("Steps:", cacioEPepe.sections.steps);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ── Cuisine → Recipes relationship (hasMany) ──
|
|
65
|
+
const italian = collection.getModel("cuisines/italian", Cuisine);
|
|
66
|
+
console.log(`\n--- ${italian.title} Cuisine ---`);
|
|
67
|
+
console.log("Staple ingredients:", italian.sections.stapleIngredients);
|
|
68
|
+
const italianRecipes = italian.relationships.recipes.fetchAll();
|
|
69
|
+
console.log(
|
|
70
|
+
`Recipes under this cuisine: ${italianRecipes.map((r) => r.title).join(", ")}`
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// ── Recipe → Cuisine relationship (belongsTo) ──
|
|
74
|
+
const mapo = collection.getModel("recipes/chinese/mapo-tofu", Recipe);
|
|
75
|
+
const parentCuisine = mapo.relationships.cuisine.fetch();
|
|
76
|
+
console.log(`\n${mapo.title} belongs to cuisine: ${parentCuisine.title}`);
|
|
77
|
+
|
|
78
|
+
// ── Computed properties ──
|
|
79
|
+
console.log(`\nQuick recipes (<=30 min total):`);
|
|
80
|
+
for (const recipe of allRecipes) {
|
|
81
|
+
console.log(` ${recipe.title}: ${recipe.computed.isQuick ? "yes" : "no"}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ── Serialize to JSON ──
|
|
85
|
+
const json = mapo.toJSON({
|
|
86
|
+
sections: ["ingredients", "steps"],
|
|
87
|
+
computed: ["isQuick"],
|
|
88
|
+
});
|
|
89
|
+
console.log(`\nMapo Tofu as JSON:`, JSON.stringify(json, null, 2));
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
course: main
|
|
3
|
+
servings: 2
|
|
4
|
+
prepTime: "5 min"
|
|
5
|
+
cookTime: "10 min"
|
|
6
|
+
difficulty: easy
|
|
7
|
+
cuisine: chinese
|
|
8
|
+
vegetarian: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Egg Fried Rice
|
|
12
|
+
|
|
13
|
+
The secret to great fried rice is day-old rice and a screaming hot wok. This is pantry cooking at its finest — minimal ingredients, maximum technique.
|
|
14
|
+
|
|
15
|
+
## Ingredients
|
|
16
|
+
|
|
17
|
+
| Ingredient | Amount | Notes |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| Cooked jasmine rice | 400g | Day-old, cold from fridge |
|
|
20
|
+
| Eggs | 3 | Beaten |
|
|
21
|
+
| Scallions | 3 stalks | Thinly sliced |
|
|
22
|
+
| Soy sauce | 1.5 tbsp | Light soy |
|
|
23
|
+
| Sesame oil | 1 tsp | Toasted |
|
|
24
|
+
| White pepper | Pinch | |
|
|
25
|
+
| Vegetable oil | 2 tbsp | High smoke point |
|
|
26
|
+
| Salt | To taste | |
|
|
27
|
+
|
|
28
|
+
## Steps
|
|
29
|
+
|
|
30
|
+
1. Break up the cold rice with your hands so there are no clumps
|
|
31
|
+
2. Heat a wok over the highest heat until it just starts to smoke
|
|
32
|
+
3. Add oil, then immediately pour in the beaten eggs
|
|
33
|
+
4. Scramble the eggs for 10 seconds until just set, then break into pieces
|
|
34
|
+
5. Add the rice and press it flat against the wok — let it sear without stirring for 30 seconds
|
|
35
|
+
6. Toss and repeat the searing step twice more until the rice is hot and slightly crispy
|
|
36
|
+
7. Add soy sauce around the edges of the wok so it sizzles and seasons evenly
|
|
37
|
+
8. Finish with sesame oil, white pepper, and scallions — one final toss and serve
|
|
38
|
+
|
|
39
|
+
## Notes
|
|
40
|
+
|
|
41
|
+
- Freshly cooked rice is too wet and will steam instead of fry
|
|
42
|
+
- A carbon steel wok over a gas burner is ideal but cast iron works too
|
|
43
|
+
- The less you stir, the better the char
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
course: main
|
|
3
|
+
servings: 4
|
|
4
|
+
prepTime: "10 min"
|
|
5
|
+
cookTime: "20 min"
|
|
6
|
+
difficulty: medium
|
|
7
|
+
cuisine: chinese
|
|
8
|
+
vegetarian: false
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Mapo Tofu
|
|
12
|
+
|
|
13
|
+
The definitive Sichuan comfort food. Silky tofu swimming in a fiery, numbing sauce of doubanjiang, chili oil, and fermented black beans. The combination of ma (numbing) and la (spicy) is addictive.
|
|
14
|
+
|
|
15
|
+
## Ingredients
|
|
16
|
+
|
|
17
|
+
| Ingredient | Amount | Notes |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| Silken tofu | 400g | Medium-firm, cubed |
|
|
20
|
+
| Ground pork | 150g | Or beef |
|
|
21
|
+
| Doubanjiang (chili bean paste) | 2 tbsp | Pixian brand preferred |
|
|
22
|
+
| Sichuan peppercorns | 1 tbsp | Toasted and ground |
|
|
23
|
+
| Garlic | 4 cloves | Minced |
|
|
24
|
+
| Ginger | 1 tbsp | Minced |
|
|
25
|
+
| Scallions | 4 stalks | White and green separated |
|
|
26
|
+
| Fermented black beans | 1 tbsp | Rinsed and chopped |
|
|
27
|
+
| Soy sauce | 1 tbsp | Light |
|
|
28
|
+
| Cornstarch slurry | 2 tbsp | Mixed with 2 tbsp water |
|
|
29
|
+
| Vegetable oil | 2 tbsp | |
|
|
30
|
+
| Chili flakes | 1 tsp | Optional |
|
|
31
|
+
|
|
32
|
+
## Steps
|
|
33
|
+
|
|
34
|
+
1. Gently simmer the cubed tofu in salted water for 5 minutes to warm through and firm it slightly — drain and set aside
|
|
35
|
+
2. Heat oil in a wok over high heat, then brown the ground pork until the fat renders
|
|
36
|
+
3. Push the pork to the side and add doubanjiang, stir-frying until the oil turns red
|
|
37
|
+
4. Add garlic, ginger, scallion whites, and black beans — cook until fragrant
|
|
38
|
+
5. Pour in a cup of water or stock and bring to a simmer
|
|
39
|
+
6. Slide in the tofu gently and let it braise for 5 minutes
|
|
40
|
+
7. Add soy sauce and the cornstarch slurry, tilting the wok to distribute
|
|
41
|
+
8. Finish with ground Sichuan peppercorn and a shower of scallion greens
|
|
42
|
+
|
|
43
|
+
## Notes
|
|
44
|
+
|
|
45
|
+
- Blanching the tofu prevents it from breaking apart in the wok
|
|
46
|
+
- Doubanjiang is the soul of this dish — don't substitute with generic chili paste
|
|
47
|
+
- Serve over steamed rice to catch the sauce
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
course: appetizer
|
|
3
|
+
servings: 6
|
|
4
|
+
prepTime: "10 min"
|
|
5
|
+
cookTime: "5 min"
|
|
6
|
+
difficulty: easy
|
|
7
|
+
cuisine: italian
|
|
8
|
+
vegetarian: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Bruschetta
|
|
12
|
+
|
|
13
|
+
The simplest Italian appetizer — and one of the best. Peak-summer tomatoes are essential; don't bother making this with mealy off-season ones.
|
|
14
|
+
|
|
15
|
+
## Ingredients
|
|
16
|
+
|
|
17
|
+
| Ingredient | Amount | Notes |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| Ripe tomatoes | 500g | Diced, seeds removed |
|
|
20
|
+
| Garlic | 3 cloves | 1 for rubbing, 2 minced |
|
|
21
|
+
| Fresh basil | 10 leaves | Torn, not chopped |
|
|
22
|
+
| Extra virgin olive oil | 3 tbsp | Good quality |
|
|
23
|
+
| Balsamic vinegar | 1 tsp | Optional |
|
|
24
|
+
| Crusty bread | 1 loaf | Sliced 1cm thick |
|
|
25
|
+
| Salt | To taste | Flaky sea salt is nice |
|
|
26
|
+
|
|
27
|
+
## Steps
|
|
28
|
+
|
|
29
|
+
1. Dice the tomatoes, remove seeds, and toss with minced garlic, basil, olive oil, and salt
|
|
30
|
+
2. Let the tomato mixture sit for 15 minutes so the flavors meld
|
|
31
|
+
3. Grill or toast the bread slices until golden and crisp
|
|
32
|
+
4. Rub each warm slice with a halved garlic clove
|
|
33
|
+
5. Spoon the tomato mixture onto the bread and serve immediately
|
|
34
|
+
|
|
35
|
+
## Notes
|
|
36
|
+
|
|
37
|
+
- Make this only when you have great tomatoes — it lives or dies by that single ingredient
|
|
38
|
+
- The bread should be sturdy enough to hold the topping without going soggy
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
course: main
|
|
3
|
+
servings: 4
|
|
4
|
+
prepTime: "5 min"
|
|
5
|
+
cookTime: "15 min"
|
|
6
|
+
difficulty: medium
|
|
7
|
+
cuisine: italian
|
|
8
|
+
vegetarian: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Cacio e Pepe
|
|
12
|
+
|
|
13
|
+
A Roman classic that turns three humble ingredients — pasta, Pecorino Romano, and black pepper — into something transcendent. The trick is building a creamy emulsion without any cream.
|
|
14
|
+
|
|
15
|
+
## Ingredients
|
|
16
|
+
|
|
17
|
+
| Ingredient | Amount | Notes |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| Tonnarelli or spaghetti | 400g | Dried, not fresh |
|
|
20
|
+
| Pecorino Romano | 200g | Finely grated |
|
|
21
|
+
| Black pepper | 2 tbsp | Freshly cracked, coarse |
|
|
22
|
+
| Pasta water | As needed | Starchy — use a small pot |
|
|
23
|
+
| Salt | To taste | Go easy, the cheese is salty |
|
|
24
|
+
|
|
25
|
+
## Steps
|
|
26
|
+
|
|
27
|
+
1. Bring a small pot of salted water to a boil — less water means starchier pasta water, which is key
|
|
28
|
+
2. Toast the black pepper in a dry skillet over medium heat until fragrant, about 1 minute
|
|
29
|
+
3. Add a ladle of pasta water to the pepper skillet and let it reduce slightly
|
|
30
|
+
4. Cook the pasta until 1 minute shy of al dente, then transfer directly to the skillet
|
|
31
|
+
5. Remove from heat and add grated Pecorino in small handfuls, tossing constantly
|
|
32
|
+
6. Add splashes of pasta water as needed to form a smooth, creamy sauce
|
|
33
|
+
7. Serve immediately with extra pepper and cheese on top
|
|
34
|
+
|
|
35
|
+
## Notes
|
|
36
|
+
|
|
37
|
+
- The pasta water starch is what makes the sauce emulsify — do not rinse the pasta
|
|
38
|
+
- Work quickly once you add the cheese; too much heat will cause it to clump
|
|
39
|
+
- Purists insist on Pecorino only — no Parmigiano
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
course: dessert
|
|
3
|
+
servings: 8
|
|
4
|
+
prepTime: "30 min"
|
|
5
|
+
cookTime: "0 min"
|
|
6
|
+
difficulty: easy
|
|
7
|
+
cuisine: italian
|
|
8
|
+
vegetarian: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Tiramisu
|
|
12
|
+
|
|
13
|
+
The iconic Italian layered dessert. Espresso-soaked ladyfingers and a mascarpone cream that sets overnight into something magical. No baking required.
|
|
14
|
+
|
|
15
|
+
## Ingredients
|
|
16
|
+
|
|
17
|
+
| Ingredient | Amount | Notes |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| Mascarpone | 500g | Room temperature |
|
|
20
|
+
| Egg yolks | 6 | Large |
|
|
21
|
+
| Sugar | 120g | Granulated |
|
|
22
|
+
| Savoiardi (ladyfingers) | 300g | The dry, crisp kind |
|
|
23
|
+
| Espresso | 400ml | Cooled to room temp |
|
|
24
|
+
| Cocoa powder | For dusting | Dutch process preferred |
|
|
25
|
+
| Dark rum | 2 tbsp | Optional, or use Marsala |
|
|
26
|
+
|
|
27
|
+
## Steps
|
|
28
|
+
|
|
29
|
+
1. Brew the espresso and let it cool completely — stir in the rum if using
|
|
30
|
+
2. Whisk egg yolks and sugar until thick, pale, and ribbon-like
|
|
31
|
+
3. Fold the mascarpone into the yolk mixture gently until smooth
|
|
32
|
+
4. Quickly dip each ladyfinger into the espresso — just a brief dunk, not a soak
|
|
33
|
+
5. Arrange a layer of dipped ladyfingers in the bottom of a dish
|
|
34
|
+
6. Spread half the mascarpone cream over the ladyfingers
|
|
35
|
+
7. Repeat with a second layer of ladyfingers and the remaining cream
|
|
36
|
+
8. Cover and refrigerate for at least 6 hours, preferably overnight
|
|
37
|
+
9. Dust generously with cocoa powder before serving
|
|
38
|
+
|
|
39
|
+
## Notes
|
|
40
|
+
|
|
41
|
+
- The ladyfingers should be damp, not soggy — a one-second dip is enough
|
|
42
|
+
- This must rest overnight for the flavors to meld and the texture to set
|
|
43
|
+
- Keeps well in the fridge for 3 days
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
course: main
|
|
3
|
+
servings: 6
|
|
4
|
+
prepTime: "15 min"
|
|
5
|
+
cookTime: "35 min"
|
|
6
|
+
difficulty: medium
|
|
7
|
+
cuisine: mexican
|
|
8
|
+
vegetarian: false
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Chicken Tinga
|
|
12
|
+
|
|
13
|
+
Shredded chicken braised in a smoky chipotle-tomato sauce. Originally from Puebla, this is the kind of dish that gets better as leftovers. Pile it into tostadas, tacos, or just eat it over rice.
|
|
14
|
+
|
|
15
|
+
## Ingredients
|
|
16
|
+
|
|
17
|
+
| Ingredient | Amount | Notes |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| Chicken thighs | 700g | Boneless, skinless |
|
|
20
|
+
| Chipotles in adobo | 3 chiles | Plus 2 tbsp adobo sauce |
|
|
21
|
+
| Crushed tomatoes | 400g | One can |
|
|
22
|
+
| White onion | 1 large | Sliced |
|
|
23
|
+
| Garlic | 4 cloves | Minced |
|
|
24
|
+
| Dried oregano | 1 tsp | Mexican oregano preferred |
|
|
25
|
+
| Cumin | 1/2 tsp | Ground |
|
|
26
|
+
| Chicken broth | 1/2 cup | |
|
|
27
|
+
| Vegetable oil | 1 tbsp | |
|
|
28
|
+
| Salt | To taste | |
|
|
29
|
+
|
|
30
|
+
## Steps
|
|
31
|
+
|
|
32
|
+
1. Season the chicken thighs with salt and sear in oil until golden on both sides — remove and set aside
|
|
33
|
+
2. In the same pot, soften the onion slices until translucent
|
|
34
|
+
3. Add garlic, oregano, and cumin — cook until fragrant
|
|
35
|
+
4. Add the crushed tomatoes, chipotles, adobo sauce, and broth — stir and bring to a simmer
|
|
36
|
+
5. Return the chicken to the pot, cover, and braise on low for 25 minutes
|
|
37
|
+
6. Remove the chicken and shred with two forks
|
|
38
|
+
7. Return the shredded chicken to the sauce and simmer uncovered for 5 more minutes to thicken
|
|
39
|
+
|
|
40
|
+
## Notes
|
|
41
|
+
|
|
42
|
+
- Adjust the number of chipotles to control the heat level
|
|
43
|
+
- This freezes beautifully for up to 3 months
|
|
44
|
+
- Serve on tostadas with crema, pickled onions, and crumbled queso fresco
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
course: appetizer
|
|
3
|
+
servings: 4
|
|
4
|
+
prepTime: "10 min"
|
|
5
|
+
cookTime: "0 min"
|
|
6
|
+
difficulty: easy
|
|
7
|
+
cuisine: mexican
|
|
8
|
+
vegetarian: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Guacamole
|
|
12
|
+
|
|
13
|
+
Ripe avocados, lime, and a little heat. The key is restraint — don't over-mash, don't over-season, and don't make it more than 30 minutes ahead.
|
|
14
|
+
|
|
15
|
+
## Ingredients
|
|
16
|
+
|
|
17
|
+
| Ingredient | Amount | Notes |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| Ripe avocados | 3 | Hass, should yield to gentle pressure |
|
|
20
|
+
| Lime juice | 2 tbsp | Fresh |
|
|
21
|
+
| Red onion | 1/4 cup | Finely diced |
|
|
22
|
+
| Serrano chile | 1 | Seeded and minced |
|
|
23
|
+
| Cilantro | 3 tbsp | Chopped |
|
|
24
|
+
| Salt | 3/4 tsp | Kosher |
|
|
25
|
+
| Ripe tomato | 1 small | Diced, optional |
|
|
26
|
+
|
|
27
|
+
## Steps
|
|
28
|
+
|
|
29
|
+
1. Halve the avocados, remove the pit, and scoop the flesh into a bowl
|
|
30
|
+
2. Add salt and lime juice, then mash with a fork to your preferred texture — leave it chunky
|
|
31
|
+
3. Fold in the onion, serrano, cilantro, and tomato if using
|
|
32
|
+
4. Taste and adjust salt and lime
|
|
33
|
+
5. Serve immediately with warm tortilla chips
|
|
34
|
+
|
|
35
|
+
## Notes
|
|
36
|
+
|
|
37
|
+
- The avocados must be ripe — there is no fixing an unripe avocado
|
|
38
|
+
- A molcajete gives the best texture, but a fork works fine
|
|
39
|
+
- Press plastic wrap directly onto the surface to prevent browning if you must store it
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
artist: miles-davis
|
|
3
|
+
year: 1970
|
|
4
|
+
genre: Jazz Fusion
|
|
5
|
+
format: 2xLP
|
|
6
|
+
rating: 5
|
|
7
|
+
condition: good
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Bitches Brew
|
|
11
|
+
|
|
12
|
+
Three days in August 1969. Miles put electric keyboards, electric bass, and multiple drummers in a studio and told them to play. The result blew jazz wide open and laid the groundwork for an entire genre.
|
|
13
|
+
|
|
14
|
+
## Tracklist
|
|
15
|
+
|
|
16
|
+
| # | Title | Duration |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| 1 | Pharaoh's Dance | 20:05 |
|
|
19
|
+
| 2 | Bitches Brew | 26:58 |
|
|
20
|
+
| 3 | Spanish Key | 17:32 |
|
|
21
|
+
| 4 | John McLaughlin | 4:23 |
|
|
22
|
+
| 5 | Miles Runs the Voodoo Down | 14:02 |
|
|
23
|
+
| 6 | Sanctuary | 10:56 |
|
|
24
|
+
|
|
25
|
+
## Personnel
|
|
26
|
+
|
|
27
|
+
- Miles Davis — trumpet
|
|
28
|
+
- Wayne Shorter — soprano saxophone
|
|
29
|
+
- Bennie Maupin — bass clarinet
|
|
30
|
+
- Joe Zawinul — electric piano
|
|
31
|
+
- Chick Corea — electric piano
|
|
32
|
+
- John McLaughlin — electric guitar
|
|
33
|
+
- Dave Holland — bass
|
|
34
|
+
- Harvey Brooks — electric bass
|
|
35
|
+
- Lenny White — drums
|
|
36
|
+
- Jack DeJohnette — drums
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
artist: nina-simone
|
|
3
|
+
year: 1965
|
|
4
|
+
genre: Jazz / Vocal
|
|
5
|
+
format: LP
|
|
6
|
+
rating: 5
|
|
7
|
+
condition: good
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# I Put a Spell on You
|
|
11
|
+
|
|
12
|
+
Nina Simone at the height of her powers, backed by lush orchestral arrangements from Hal Mooney. This album captures her ability to inhabit a song so completely that it becomes hers forever, regardless of who wrote it.
|
|
13
|
+
|
|
14
|
+
## Tracklist
|
|
15
|
+
|
|
16
|
+
| # | Title | Duration |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| 1 | I Put a Spell on You | 2:34 |
|
|
19
|
+
| 2 | Tomorrow Is My Turn | 2:54 |
|
|
20
|
+
| 3 | Ne Me Quitte Pas | 3:35 |
|
|
21
|
+
| 4 | Marriage Is for Old Folks | 2:13 |
|
|
22
|
+
| 5 | July Tree | 2:17 |
|
|
23
|
+
| 6 | Gimme Some | 2:47 |
|
|
24
|
+
| 7 | Feeling Good | 2:54 |
|
|
25
|
+
| 8 | One September Day | 4:57 |
|
|
26
|
+
| 9 | Blues on Purpose | 2:35 |
|
|
27
|
+
| 10 | Beautiful Land | 2:44 |
|
|
28
|
+
| 11 | You've Got to Learn | 4:42 |
|
|
29
|
+
| 12 | Take Care of Business | 3:11 |
|
|
30
|
+
|
|
31
|
+
## Personnel
|
|
32
|
+
|
|
33
|
+
- Nina Simone — vocals, piano
|
|
34
|
+
- Hal Mooney — orchestral arrangements
|
|
35
|
+
- Rudy Van Gelder — recording engineer
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
artist: radiohead
|
|
3
|
+
year: 2007
|
|
4
|
+
genre: Art Rock
|
|
5
|
+
format: LP
|
|
6
|
+
rating: 4
|
|
7
|
+
condition: mint
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# In Rainbows
|
|
11
|
+
|
|
12
|
+
After the icy electronics of Kid A and Amnesiac, Radiohead made their warmest, most human record. The songs feel lived-in, generous, and — for once — occasionally happy.
|
|
13
|
+
|
|
14
|
+
## Tracklist
|
|
15
|
+
|
|
16
|
+
| # | Title | Duration |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| 1 | 15 Step | 3:57 |
|
|
19
|
+
| 2 | Bodysnatchers | 4:02 |
|
|
20
|
+
| 3 | Nude | 4:15 |
|
|
21
|
+
| 4 | Weird Fishes/Arpeggi | 5:18 |
|
|
22
|
+
| 5 | All I Need | 3:49 |
|
|
23
|
+
| 6 | Faust Arp | 2:10 |
|
|
24
|
+
| 7 | Reckoner | 4:50 |
|
|
25
|
+
| 8 | House of Cards | 5:28 |
|
|
26
|
+
| 9 | Jigsaw Falling Into Place | 4:09 |
|
|
27
|
+
| 10 | Videotape | 4:40 |
|
|
28
|
+
|
|
29
|
+
## Personnel
|
|
30
|
+
|
|
31
|
+
- Thom Yorke — vocals, guitar, piano
|
|
32
|
+
- Jonny Greenwood — guitar, ondes Martenot, analogue synthesizers
|
|
33
|
+
- Ed O'Brien — guitar, effects
|
|
34
|
+
- Colin Greenwood — bass
|
|
35
|
+
- Phil Selway — drums
|