soustack 0.4.0 → 0.4.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 +4 -4
- package/dist/cli/index.js +4412 -1275
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +106 -80
- package/dist/index.d.ts +106 -80
- package/dist/index.js +4527 -1360
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4527 -1360
- package/dist/index.mjs.map +1 -1
- package/dist/scrape/index.d.mts +86 -74
- package/dist/scrape/index.d.ts +86 -74
- package/dist/scrape/index.js +91 -64
- package/dist/scrape/index.js.map +1 -1
- package/dist/scrape/index.mjs +91 -64
- package/dist/scrape/index.mjs.map +1 -1
- package/package.json +15 -6
- package/spec/.sync-meta.json +149 -0
- package/spec/SOUSTACK_SPEC_VERSION +1 -0
- package/spec/defs/common.schema.json +46 -0
- package/spec/defs/duration.schema.json +33 -0
- package/spec/defs/entities.schema.json +111 -0
- package/spec/defs/ingredientQuantified.schema.json +9 -0
- package/spec/defs/quantity.schema.json +16 -0
- package/spec/defs/scalingRule.schema.json +127 -0
- package/spec/defs/temperature.schema.json +63 -0
- package/spec/fixtures/content/illustrated-step.valid.json +24 -0
- package/spec/fixtures/invalid/equipment-unknown-reference.invalid.json +38 -0
- package/spec/fixtures/invalid/mise-en-place-unknown-equipment.invalid.json +37 -0
- package/spec/fixtures/invalid/mise-en-place-unknown-input.invalid.json +41 -0
- package/spec/fixtures/invalid/storage-leftovers-missing-method.invalid.json +31 -0
- package/spec/fixtures/invalid/storage-leftovers-wrong-type.invalid.json +23 -0
- package/spec/fixtures/level/base-full.valid.json +162 -0
- package/spec/fixtures/level/base-missing-yield.invalid.json +12 -0
- package/spec/fixtures/level/lite-min.valid.json +14 -0
- package/spec/fixtures/profile/profile-base.valid.json +20 -0
- package/spec/fixtures/profile/profile-equipped.valid.json +28 -0
- package/spec/fixtures/profile/profile-illustrated.valid.json +28 -0
- package/spec/fixtures/profile/profile-lite.valid.json +13 -0
- package/spec/fixtures/profile/profile-prepped.valid.json +31 -0
- package/spec/fixtures/profile/profile-scalable-missing-scaling.invalid.json +29 -0
- package/spec/fixtures/profile/profile-scalable.valid.json +49 -0
- package/spec/fixtures/profile/profile-timed-missing-structured.invalid.json +30 -0
- package/spec/fixtures/scaling/bakers-percent-missing-ref.invalid.json +41 -0
- package/spec/fixtures/scaling/bakers-percent.valid.json +51 -0
- package/spec/fixtures/scaling/discrete-range.invalid.json +36 -0
- package/spec/fixtures/scaling/missing-quantified.invalid.json +40 -0
- package/spec/fixtures/scaling/reject-bakersPercentage.invalid.json +50 -0
- package/spec/fixtures/stacks/compute-missing-timed.invalid.json +32 -0
- package/spec/fixtures/stacks/dietary-no-signal.invalid.json +16 -0
- package/spec/fixtures/stacks/illustrated-empty.invalid.json +13 -0
- package/spec/fixtures/stacks/quantified-string.invalid.json +22 -0
- package/spec/fixtures/stacks/referenced-missing-input.invalid.json +32 -0
- package/spec/fixtures/stacks/storage-min.valid.json +20 -0
- package/spec/fixtures/stacks/storage-no-duration.invalid.json +16 -0
- package/spec/fixtures/stacks/timed-implies-structured.valid.json +50 -0
- package/spec/fixtures/stacks/timed-range.invalid.json +33 -0
- package/spec/fixtures/valid/equipment-scaling-rules.valid.json +76 -0
- package/spec/fixtures/valid/equipment-strings.valid.json +31 -0
- package/spec/fixtures/valid/equipment-structured-uses.valid.json +47 -0
- package/spec/fixtures/valid/mise-en-place-basic.valid.json +31 -0
- package/spec/fixtures/valid/mise-en-place-referenced-equipment.valid.json +51 -0
- package/spec/fixtures/valid/prep-ingredient-strings.valid.json +48 -0
- package/spec/fixtures/valid/prep-ingredient-structured.valid.json +45 -0
- package/spec/fixtures/valid/profile-equipped.valid.json +29 -0
- package/spec/fixtures/valid/profile-prepped.valid.json +32 -0
- package/spec/fixtures/valid/quantified-nested-ingredient-sections.valid.json +61 -0
- package/spec/fixtures/valid/referenced-scaling.valid.json +67 -0
- package/spec/fixtures/valid/storage-leftovers-simple.valid.json +27 -0
- package/spec/fixtures/valid/storage-leftovers-structured.valid.json +43 -0
- package/spec/fixtures/valid/structured-nested-step-sections.valid.json +84 -0
- package/spec/schemas/stacks-registry.schema.json +108 -0
- package/spec/soustack.schema.json +2379 -0
- package/spec/stacks/compute.schema.json +7 -0
- package/spec/stacks/compute@1.md +22 -0
- package/spec/stacks/dietary.schema.json +45 -0
- package/spec/stacks/dietary@1.md +24 -0
- package/spec/stacks/equipment.schema.json +98 -0
- package/spec/stacks/equipment@1.md +244 -0
- package/spec/stacks/illustrated.schema.json +54 -0
- package/spec/stacks/illustrated@1.md +24 -0
- package/spec/stacks/prep.schema.json +76 -0
- package/spec/stacks/prep@1.md +276 -0
- package/spec/stacks/quantified.schema.json +74 -0
- package/spec/stacks/quantified@1.md +24 -0
- package/spec/stacks/referenced.schema.json +96 -0
- package/spec/stacks/referenced@1.md +23 -0
- package/spec/stacks/registry.json +112 -0
- package/spec/stacks/scaling.schema.json +99 -0
- package/spec/stacks/scaling@1.md +238 -0
- package/spec/stacks/storage.schema.json +132 -0
- package/spec/stacks/storage@1.md +256 -0
- package/spec/stacks/structured.schema.json +48 -0
- package/spec/stacks/structured@1.md +24 -0
- package/spec/stacks/substitutions.schema.json +43 -0
- package/spec/stacks/substitutions@1.md +24 -0
- package/spec/stacks/techniques.schema.json +28 -0
- package/spec/stacks/techniques@1.md +23 -0
- package/spec/stacks/timed.schema.json +60 -0
- package/spec/stacks/timed@1.md +23 -0
- package/src/defs/common.schema.json +46 -0
- package/src/defs/duration.schema.json +33 -0
- package/src/defs/entities.schema.json +111 -0
- package/src/defs/ingredientQuantified.schema.json +9 -0
- package/src/defs/quantity.schema.json +16 -0
- package/src/defs/scalingRule.schema.json +127 -0
- package/src/defs/temperature.schema.json +63 -0
- package/src/profiles/base.schema.json +2 -2
- package/src/profiles/equipped.schema.json +10 -0
- package/src/profiles/illustrated.schema.json +4 -4
- package/src/profiles/lite.schema.json +10 -0
- package/src/profiles/prepped.schema.json +10 -0
- package/src/profiles/scalable.schema.json +6 -6
- package/src/profiles/timed.schema.json +10 -0
- package/src/schema.json +2271 -248
- package/src/schemas/stacks-registry.schema.json +108 -0
- package/src/soustack.schema.json +2271 -248
- package/src/stacks/compute.schema.json +7 -0
- package/src/stacks/compute@1.md +22 -0
- package/src/stacks/dietary.schema.json +45 -0
- package/src/stacks/dietary@1.md +24 -0
- package/src/stacks/equipment.schema.json +98 -0
- package/src/stacks/equipment@1.md +244 -0
- package/src/stacks/illustrated.schema.json +54 -0
- package/src/stacks/illustrated@1.md +24 -0
- package/src/stacks/prep.schema.json +76 -0
- package/src/stacks/prep@1.md +276 -0
- package/src/stacks/quantified.schema.json +74 -0
- package/src/stacks/quantified@1.md +24 -0
- package/src/stacks/referenced.schema.json +96 -0
- package/src/stacks/referenced@1.md +23 -0
- package/src/stacks/registry.json +112 -0
- package/src/stacks/scaling.schema.json +99 -0
- package/src/stacks/scaling@1.md +238 -0
- package/src/stacks/storage.schema.json +132 -0
- package/src/stacks/storage@1.md +256 -0
- package/src/stacks/structured.schema.json +48 -0
- package/src/stacks/structured@1.md +24 -0
- package/src/stacks/substitutions.schema.json +43 -0
- package/src/stacks/substitutions@1.md +24 -0
- package/src/stacks/techniques.schema.json +28 -0
- package/src/stacks/techniques@1.md +23 -0
- package/src/stacks/timed.schema.json +60 -0
- package/src/stacks/timed@1.md +23 -0
- package/src/profiles/cookable.schema.json +0 -18
- package/src/profiles/quantified.schema.json +0 -43
- package/src/profiles/schedulable.schema.json +0 -43
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://soustack.spec/stacks/scaling.schema.json",
|
|
4
|
+
"title": "Scaling Stack",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"ingredients": {
|
|
8
|
+
"type": "array",
|
|
9
|
+
"items": {
|
|
10
|
+
"anyOf": [
|
|
11
|
+
{ "$ref": "#/$defs/ingredient" },
|
|
12
|
+
{ "$ref": "#/$defs/ingredientSection" }
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"scaling": {
|
|
17
|
+
"type": "object",
|
|
18
|
+
"properties": {
|
|
19
|
+
"discrete": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"properties": {
|
|
22
|
+
"min": { "type": "integer", "minimum": 1 },
|
|
23
|
+
"max": { "type": "integer", "minimum": 1 },
|
|
24
|
+
"step": { "type": "integer", "minimum": 1 },
|
|
25
|
+
"metadata": { "type": "object", "additionalProperties": true }
|
|
26
|
+
},
|
|
27
|
+
"required": ["min", "max"],
|
|
28
|
+
"additionalProperties": false,
|
|
29
|
+
"patternProperties": {
|
|
30
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"metadata": { "type": "object", "additionalProperties": true }
|
|
34
|
+
},
|
|
35
|
+
"required": ["discrete"],
|
|
36
|
+
"additionalProperties": false,
|
|
37
|
+
"patternProperties": {
|
|
38
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"required": ["ingredients", "scaling"],
|
|
43
|
+
"$defs": {
|
|
44
|
+
"ingredient": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"properties": {
|
|
47
|
+
"id": { "type": "string" },
|
|
48
|
+
"name": { "type": "string" },
|
|
49
|
+
"quantity": { "$ref": "../defs/quantity.schema.json" },
|
|
50
|
+
"temperature": { "$ref": "../defs/temperature.schema.json" },
|
|
51
|
+
"notes": { "type": "string" },
|
|
52
|
+
"prep": {
|
|
53
|
+
"oneOf": [
|
|
54
|
+
{ "type": "string", "minLength": 1 },
|
|
55
|
+
{
|
|
56
|
+
"type": "array",
|
|
57
|
+
"minItems": 1,
|
|
58
|
+
"items": {
|
|
59
|
+
"anyOf": [
|
|
60
|
+
{ "type": "string", "minLength": 1 },
|
|
61
|
+
{ "$ref": "../stacks/prep.schema.json#/$defs/prepItem" }
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
"metadata": { "type": "object", "additionalProperties": true },
|
|
68
|
+
"scaling": { "$ref": "../defs/scalingRule.schema.json" }
|
|
69
|
+
},
|
|
70
|
+
"required": ["id", "name", "quantity"],
|
|
71
|
+
"additionalProperties": false,
|
|
72
|
+
"patternProperties": {
|
|
73
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"ingredientSection": {
|
|
77
|
+
"type": "object",
|
|
78
|
+
"properties": {
|
|
79
|
+
"section": { "type": "string" },
|
|
80
|
+
"ingredients": {
|
|
81
|
+
"type": "array",
|
|
82
|
+
"items": {
|
|
83
|
+
"anyOf": [
|
|
84
|
+
{ "$ref": "#/$defs/ingredient" },
|
|
85
|
+
{ "$ref": "#/$defs/ingredientSection" }
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"metadata": { "type": "object", "additionalProperties": true }
|
|
90
|
+
},
|
|
91
|
+
"required": ["section", "ingredients"],
|
|
92
|
+
"additionalProperties": false,
|
|
93
|
+
"patternProperties": {
|
|
94
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"additionalProperties": false
|
|
99
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#scaling@1
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
The `scaling@1` stack standardizes how ingredient quantities change when a recipe is scaled, so independent implementations produce consistent results.
|
|
8
|
+
|
|
9
|
+
This stack is intended to support the **Scalable** profile.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
A document that declares `scaling@1`:
|
|
16
|
+
|
|
17
|
+
• MUST declare `quantified@1`.
|
|
18
|
+
• SHOULD declare `structured@1` (recommended for stable ingredient IDs).
|
|
19
|
+
• MUST satisfy all structural rules enabled by this stack.
|
|
20
|
+
• MUST satisfy the semantic rules described below.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Data Model
|
|
25
|
+
|
|
26
|
+
When `scaling@1` is declared, quantified ingredients MAY include an optional `scaling` field.
|
|
27
|
+
|
|
28
|
+
Field
|
|
29
|
+
ingredient.scaling : ScalingRule
|
|
30
|
+
|
|
31
|
+
ScalingRule is defined in `defs/scalingRule.schema.json` and is a closed object with a required `mode`.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Scaling Modes
|
|
36
|
+
|
|
37
|
+
### linear
|
|
38
|
+
|
|
39
|
+
Multiply the ingredient quantity by the scale factor.
|
|
40
|
+
|
|
41
|
+
mode = "linear"
|
|
42
|
+
|
|
43
|
+
If `scaling` is omitted, implementations MUST treat the ingredient as linear by default.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
### fixed
|
|
48
|
+
|
|
49
|
+
Do not scale this ingredient quantity.
|
|
50
|
+
|
|
51
|
+
Examples:
|
|
52
|
+
• 1 bay leaf
|
|
53
|
+
• 1 cinnamon stick
|
|
54
|
+
• 1 pan
|
|
55
|
+
|
|
56
|
+
mode = "fixed"
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
### discrete
|
|
61
|
+
|
|
62
|
+
Scale using discrete increments (for example, whole eggs), with optional rounding and bounds.
|
|
63
|
+
|
|
64
|
+
Fields
|
|
65
|
+
• mode = "discrete"
|
|
66
|
+
• step (optional, > 0): discrete increment size
|
|
67
|
+
• rounding (optional): nearest | ceil | floor
|
|
68
|
+
• min (optional): minimum allowed result
|
|
69
|
+
• max (optional): maximum allowed result
|
|
70
|
+
|
|
71
|
+
Semantic defaults
|
|
72
|
+
• If step is not present, default is 1
|
|
73
|
+
• If rounding is not present, default is nearest
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### toTaste
|
|
78
|
+
|
|
79
|
+
Quantity is informational and MUST NOT be mechanically scaled.
|
|
80
|
+
|
|
81
|
+
Examples:
|
|
82
|
+
• salt to taste
|
|
83
|
+
• pepper to taste
|
|
84
|
+
|
|
85
|
+
mode = "toTaste"
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
### bakersPercent
|
|
90
|
+
|
|
91
|
+
Represents the ingredient quantity as a baker’s percentage of a base ingredient (typically flour).
|
|
92
|
+
|
|
93
|
+
Fields
|
|
94
|
+
• mode = "bakersPercent"
|
|
95
|
+
• percent (> 0): percentage value (for example, 70 for 70%)
|
|
96
|
+
• of (string): ingredient id of the base ingredient
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Scale Factor
|
|
101
|
+
|
|
102
|
+
Scaling is applied using a scale factor F.
|
|
103
|
+
|
|
104
|
+
How F is selected depends on the consumer implementation:
|
|
105
|
+
|
|
106
|
+
• Some consumers may accept an explicit factor (for example, “2x”).
|
|
107
|
+
• Some consumers may compute F from yield changes (for example, “scale from 4 servings to 6 servings”).
|
|
108
|
+
|
|
109
|
+
This stack standardizes how ingredient rules respond to F, not how F is chosen.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Semantic Validation Rules (Normative)
|
|
114
|
+
|
|
115
|
+
Validators MUST enforce the following rules:
|
|
116
|
+
|
|
117
|
+
1. Prerequisite
|
|
118
|
+
If `scaling@1` is declared, `quantified@1` MUST also be declared.
|
|
119
|
+
|
|
120
|
+
2. Baker’s percent reference
|
|
121
|
+
For mode = "bakersPercent", the `of` field MUST resolve to an existing ingredient id.
|
|
122
|
+
|
|
123
|
+
3. Discrete sanity
|
|
124
|
+
For mode = "discrete", if both `min` and `max` are present, min MUST be less than or equal to max.
|
|
125
|
+
|
|
126
|
+
4. Closed rule objects
|
|
127
|
+
ScalingRule MUST NOT contain unspecified fields. This is enforced by schema.
|
|
128
|
+
|
|
129
|
+
Consumers MUST apply the following semantic defaults:
|
|
130
|
+
|
|
131
|
+
• Missing `scaling` ⇒ treat as linear
|
|
132
|
+
• discrete.step default = 1
|
|
133
|
+
• discrete.rounding default = nearest
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Scaling Behavior (Normative)
|
|
138
|
+
|
|
139
|
+
Given an ingredient with base quantity amount A and scale factor F:
|
|
140
|
+
|
|
141
|
+
• linear
|
|
142
|
+
scaled amount = A × F
|
|
143
|
+
|
|
144
|
+
• fixed
|
|
145
|
+
scaled amount = A
|
|
146
|
+
|
|
147
|
+
• toTaste
|
|
148
|
+
scaled amount = A (informational only)
|
|
149
|
+
Consumers MAY hide numeric scaling UI for this item.
|
|
150
|
+
|
|
151
|
+
• discrete
|
|
152
|
+
|
|
153
|
+
1. raw = A × F
|
|
154
|
+
2. if step is present, units = raw ÷ step
|
|
155
|
+
3. apply rounding to units
|
|
156
|
+
4. scaled = units × step
|
|
157
|
+
5. clamp to min / max if present
|
|
158
|
+
|
|
159
|
+
• bakersPercent
|
|
160
|
+
|
|
161
|
+
1. let B be the amount of the ingredient referenced by `of`
|
|
162
|
+
2. scaled amount = B × (percent ÷ 100)
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Examples
|
|
167
|
+
|
|
168
|
+
Linear (default)
|
|
169
|
+
|
|
170
|
+
Ingredient
|
|
171
|
+
id: i_sugar
|
|
172
|
+
name: Sugar
|
|
173
|
+
quantity: 100 g
|
|
174
|
+
(no scaling field → treated as linear)
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
Fixed
|
|
179
|
+
|
|
180
|
+
Ingredient
|
|
181
|
+
id: i_bayleaf
|
|
182
|
+
name: Bay leaf
|
|
183
|
+
quantity: 1 leaf
|
|
184
|
+
scaling: mode = fixed
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
Discrete (eggs)
|
|
189
|
+
|
|
190
|
+
Ingredient
|
|
191
|
+
id: i_eggs
|
|
192
|
+
name: Eggs
|
|
193
|
+
quantity: 2 egg
|
|
194
|
+
scaling: mode = discrete, rounding = ceil
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
To taste
|
|
199
|
+
|
|
200
|
+
Ingredient
|
|
201
|
+
id: i_salt
|
|
202
|
+
name: Salt
|
|
203
|
+
quantity: 1 tsp
|
|
204
|
+
scaling: mode = toTaste
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
Baker’s percent
|
|
209
|
+
|
|
210
|
+
Ingredient A
|
|
211
|
+
id: i_flour
|
|
212
|
+
name: Flour
|
|
213
|
+
quantity: 500 g
|
|
214
|
+
|
|
215
|
+
Ingredient B
|
|
216
|
+
id: i_water
|
|
217
|
+
name: Water
|
|
218
|
+
quantity: 350 g
|
|
219
|
+
scaling: mode = bakersPercent, percent = 70, of = i_flour
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Fixtures
|
|
224
|
+
|
|
225
|
+
Implementations SHOULD include fixtures covering:
|
|
226
|
+
|
|
227
|
+
Valid cases
|
|
228
|
+
• linear default (no scaling rule)
|
|
229
|
+
• discrete with rounding
|
|
230
|
+
• fixed
|
|
231
|
+
• toTaste
|
|
232
|
+
• bakersPercent with resolvable `of`
|
|
233
|
+
|
|
234
|
+
Invalid cases
|
|
235
|
+
• scaling declared without quantified
|
|
236
|
+
• bakersPercent with missing or invalid `of`
|
|
237
|
+
• invalid rounding value
|
|
238
|
+
• discrete with min greater than max
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://soustack.spec/stacks/storage.schema.json",
|
|
4
|
+
"title": "Storage Stack",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"storage": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"roomTemp": { "$ref": "#/$defs/storageMethod" },
|
|
11
|
+
"refrigerated": { "$ref": "#/$defs/storageMethod" },
|
|
12
|
+
"frozen": { "$ref": "#/$defs/storageMethod" },
|
|
13
|
+
"leftovers": { "$ref": "#/$defs/leftovers" },
|
|
14
|
+
"metadata": { "type": "object", "additionalProperties": true }
|
|
15
|
+
},
|
|
16
|
+
"anyOf": [
|
|
17
|
+
{ "required": ["roomTemp"] },
|
|
18
|
+
{ "required": ["refrigerated"] },
|
|
19
|
+
{ "required": ["frozen"] }
|
|
20
|
+
],
|
|
21
|
+
"additionalProperties": false,
|
|
22
|
+
"patternProperties": {
|
|
23
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"required": ["storage"],
|
|
28
|
+
"$defs": {
|
|
29
|
+
"storageMethod": {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"properties": {
|
|
32
|
+
"duration": { "$ref": "../defs/duration.schema.json#/properties/StorageDuration" },
|
|
33
|
+
"notes": { "type": "string" },
|
|
34
|
+
"metadata": { "type": "object", "additionalProperties": true }
|
|
35
|
+
},
|
|
36
|
+
"required": ["duration"],
|
|
37
|
+
"additionalProperties": false,
|
|
38
|
+
"patternProperties": {
|
|
39
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"reheatDuration": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"properties": {
|
|
45
|
+
"minMinutes": { "type": "integer", "minimum": 0 },
|
|
46
|
+
"maxMinutes": { "type": "integer", "minimum": 0 }
|
|
47
|
+
},
|
|
48
|
+
"anyOf": [
|
|
49
|
+
{ "required": ["minMinutes"] },
|
|
50
|
+
{ "required": ["maxMinutes"] }
|
|
51
|
+
],
|
|
52
|
+
"additionalProperties": false,
|
|
53
|
+
"patternProperties": {
|
|
54
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"reheatInstruction": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"properties": {
|
|
60
|
+
"method": { "type": "string", "minLength": 1 },
|
|
61
|
+
"temp": {
|
|
62
|
+
"type": "object",
|
|
63
|
+
"properties": {
|
|
64
|
+
"value": { "type": "number" },
|
|
65
|
+
"unit": { "type": "string", "enum": ["F", "C"] }
|
|
66
|
+
},
|
|
67
|
+
"required": ["value", "unit"],
|
|
68
|
+
"additionalProperties": false,
|
|
69
|
+
"patternProperties": {
|
|
70
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"duration": { "$ref": "#/$defs/reheatDuration" },
|
|
74
|
+
"notes": { "type": "string" }
|
|
75
|
+
},
|
|
76
|
+
"required": ["method"],
|
|
77
|
+
"additionalProperties": false,
|
|
78
|
+
"patternProperties": {
|
|
79
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"portioning": {
|
|
83
|
+
"type": "object",
|
|
84
|
+
"properties": {
|
|
85
|
+
"notes": { "type": "string" },
|
|
86
|
+
"recommendedPortion": {
|
|
87
|
+
"type": "object",
|
|
88
|
+
"properties": {
|
|
89
|
+
"quantity": { "type": "number" },
|
|
90
|
+
"unit": { "type": "string" }
|
|
91
|
+
},
|
|
92
|
+
"required": ["quantity", "unit"],
|
|
93
|
+
"additionalProperties": false,
|
|
94
|
+
"patternProperties": {
|
|
95
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"required": ["notes"],
|
|
100
|
+
"additionalProperties": false,
|
|
101
|
+
"patternProperties": {
|
|
102
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"leftovers": {
|
|
106
|
+
"type": "object",
|
|
107
|
+
"properties": {
|
|
108
|
+
"notes": { "type": "string" },
|
|
109
|
+
"reheat": {
|
|
110
|
+
"oneOf": [
|
|
111
|
+
{
|
|
112
|
+
"type": "array",
|
|
113
|
+
"items": { "type": "string" },
|
|
114
|
+
"minItems": 1
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"type": "array",
|
|
118
|
+
"items": { "$ref": "#/$defs/reheatInstruction" },
|
|
119
|
+
"minItems": 1
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
"portioning": { "$ref": "#/$defs/portioning" }
|
|
124
|
+
},
|
|
125
|
+
"additionalProperties": false,
|
|
126
|
+
"patternProperties": {
|
|
127
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
"additionalProperties": false
|
|
132
|
+
}
|