soustack 0.3.0 → 0.4.0
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 +41 -24
- package/dist/cli/index.js +1703 -607
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +65 -19
- package/dist/index.d.ts +65 -19
- package/dist/index.js +1490 -587
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1489 -587
- package/dist/index.mjs.map +1 -1
- package/dist/{scrape.d.mts → scrape/index.d.mts} +8 -6
- package/dist/{scrape.d.ts → scrape/index.d.ts} +8 -6
- package/dist/{scrape.js → scrape/index.js} +170 -66
- package/dist/scrape/index.js.map +1 -0
- package/dist/{scrape.mjs → scrape/index.mjs} +170 -66
- package/dist/scrape/index.mjs.map +1 -0
- package/package.json +9 -6
- package/dist/scrape.js.map +0 -1
- package/dist/scrape.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ npm install soustack
|
|
|
37
37
|
|
|
38
38
|
## What's Included
|
|
39
39
|
|
|
40
|
-
- **Validation**: `validateRecipe()` validates Soustack JSON against the bundled schema.
|
|
40
|
+
- **Validation**: `validateRecipe()` validates Soustack JSON against the bundled schema and optional conformance checks.
|
|
41
41
|
- **Scaling & Computation**: `scaleRecipe()` scales a recipe while honoring per-ingredient scaling rules and instruction timing.
|
|
42
42
|
- **Schema.org Conversion**:
|
|
43
43
|
- `fromSchemaOrg()` (Schema.org JSON-LD → Soustack)
|
|
@@ -54,15 +54,21 @@ Validate and scale a recipe in just a few lines:
|
|
|
54
54
|
```ts
|
|
55
55
|
import { validateRecipe, scaleRecipe } from 'soustack';
|
|
56
56
|
|
|
57
|
-
// Validate against the bundled Soustack schema
|
|
58
|
-
const {
|
|
59
|
-
if (!
|
|
60
|
-
throw new Error(JSON.stringify(
|
|
57
|
+
// Validate against the bundled Soustack schema + conformance rules
|
|
58
|
+
const { ok, schemaErrors, conformanceIssues, warnings } = validateRecipe(recipe);
|
|
59
|
+
if (!ok) {
|
|
60
|
+
throw new Error(JSON.stringify({ schemaErrors, conformanceIssues }, null, 2));
|
|
61
61
|
}
|
|
62
62
|
if (warnings?.length) {
|
|
63
63
|
console.warn('Non-blocking warnings', warnings);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
// Schema-only validation (skip conformance checks)
|
|
67
|
+
const schemaOnly = validateRecipe(recipe, { mode: 'schema' });
|
|
68
|
+
if (!schemaOnly.ok) {
|
|
69
|
+
console.error(schemaOnly.schemaErrors);
|
|
70
|
+
}
|
|
71
|
+
|
|
66
72
|
// Scale to a new yield (multiplier, target yield, or servings)
|
|
67
73
|
const scaled = scaleRecipe(recipe, { multiplier: 2 });
|
|
68
74
|
```
|
|
@@ -70,24 +76,29 @@ const scaled = scaleRecipe(recipe, { multiplier: 2 });
|
|
|
70
76
|
### Profile-aware validation
|
|
71
77
|
|
|
72
78
|
Use profiles to enforce integration contracts. Available profiles:
|
|
73
|
-
- **
|
|
74
|
-
- **
|
|
79
|
+
- **base**
|
|
80
|
+
- **equipped**
|
|
81
|
+
- **illustrated**
|
|
82
|
+
- **lite**
|
|
83
|
+
- **prepped**
|
|
84
|
+
- **scalable**
|
|
85
|
+
- **timed**
|
|
75
86
|
|
|
76
87
|
```ts
|
|
77
88
|
import { detectProfiles, validateRecipe } from 'soustack';
|
|
78
89
|
|
|
79
90
|
// Discover which profiles a recipe already satisfies
|
|
80
|
-
const profiles = detectProfiles(recipe);
|
|
91
|
+
const profiles = detectProfiles(recipe);
|
|
81
92
|
|
|
82
|
-
// Validate with a specific profile
|
|
83
|
-
const result = validateRecipe(recipe, { profile: '
|
|
84
|
-
if (!result.
|
|
85
|
-
console.error('Profile validation failed', result.
|
|
93
|
+
// Validate with a specific profile
|
|
94
|
+
const result = validateRecipe(recipe, { profile: 'base' });
|
|
95
|
+
if (!result.ok) {
|
|
96
|
+
console.error('Profile validation failed', result.schemaErrors);
|
|
86
97
|
}
|
|
87
98
|
|
|
88
99
|
// Validate with modules
|
|
89
100
|
const recipeWithModules = {
|
|
90
|
-
profile: '
|
|
101
|
+
profile: 'base',
|
|
91
102
|
modules: ['nutrition@1', 'times@1'],
|
|
92
103
|
name: 'Test Recipe',
|
|
93
104
|
ingredients: ['1 cup flour'],
|
|
@@ -96,7 +107,7 @@ const recipeWithModules = {
|
|
|
96
107
|
times: { prepMinutes: 10, cookMinutes: 20, totalMinutes: 30 }, // v0.3: uses *Minutes fields
|
|
97
108
|
};
|
|
98
109
|
const result2 = validateRecipe(recipeWithModules);
|
|
99
|
-
// Validates using: base +
|
|
110
|
+
// Validates using: base + profile + nutrition@1 module + times@1 module
|
|
100
111
|
// Module contract: if module is declared, payload must exist (and vice versa)
|
|
101
112
|
```
|
|
102
113
|
|
|
@@ -154,11 +165,11 @@ Soustack v0.3.0 uses a **composed validation model** where recipes are validated
|
|
|
154
165
|
|
|
155
166
|
The validator:
|
|
156
167
|
- **Base schema**: Defines the core recipe structure (`@type`, `name`, `ingredients`, `instructions`, `profile`, `modules`)
|
|
157
|
-
- **Profile overlay**: Adds profile-specific requirements (e.g., `
|
|
168
|
+
- **Profile overlay**: Adds profile-specific requirements (e.g., `base` or `lite`)
|
|
158
169
|
- **Module overlays**: Each declared module adds its own validation rules
|
|
159
170
|
|
|
160
171
|
**Defaults:**
|
|
161
|
-
- If `profile` is missing, it defaults to
|
|
172
|
+
- If `profile` is missing, it defaults to the schema bundle's configured default
|
|
162
173
|
- If `modules` is missing, it defaults to `[]`
|
|
163
174
|
|
|
164
175
|
**Module Contract:** Modules enforce a symmetric contract:
|
|
@@ -177,7 +188,7 @@ Modules are resolved to schema references using the pattern:
|
|
|
177
188
|
The module registry (`schemas/registry/modules.json`) defines which modules are available and their properties, including:
|
|
178
189
|
- `schemaOrgMappable`: Whether the module can be converted to Schema.org format
|
|
179
190
|
- `minProfile`: Minimum profile required to use the module
|
|
180
|
-
- `
|
|
191
|
+
- `allowedOnLite`: Whether the module can be used with the lite profile
|
|
181
192
|
|
|
182
193
|
**Available Modules (v0.3.0):**
|
|
183
194
|
- `attribution@1`: Source attribution (url, author, datePublished)
|
|
@@ -185,7 +196,7 @@ The module registry (`schemas/registry/modules.json`) defines which modules are
|
|
|
185
196
|
- `media@1`: Images and videos (images, videos arrays)
|
|
186
197
|
- `times@1`: Timing information (prepMinutes, cookMinutes, totalMinutes)
|
|
187
198
|
- `nutrition@1`: Nutritional data (calories, protein_g as numbers)
|
|
188
|
-
- `schedule@1`: Task scheduling (requires
|
|
199
|
+
- `schedule@1`: Task scheduling (requires timed profile, includes instruction dependencies)
|
|
189
200
|
|
|
190
201
|
## Programmatic Usage
|
|
191
202
|
|
|
@@ -204,9 +215,9 @@ import {
|
|
|
204
215
|
} from 'soustack/scrape';
|
|
205
216
|
|
|
206
217
|
// Validate a Soustack recipe JSON object with profile enforcement
|
|
207
|
-
const validation = validateRecipe(recipe, { profile: '
|
|
208
|
-
if (!validation.
|
|
209
|
-
console.error(validation.
|
|
218
|
+
const validation = validateRecipe(recipe, { profile: 'base' });
|
|
219
|
+
if (!validation.ok) {
|
|
220
|
+
console.error({ schemaErrors: validation.schemaErrors, conformanceIssues: validation.conformanceIssues });
|
|
210
221
|
}
|
|
211
222
|
|
|
212
223
|
// Scale a recipe to a target yield amount (returns a "computed recipe")
|
|
@@ -258,7 +269,7 @@ async function convert(url: string) {
|
|
|
258
269
|
|
|
259
270
|
Use the helpers to move between Schema.org JSON-LD and Soustack's structured recipe format. The conversion automatically handles image normalization, supporting multiple image formats from Schema.org.
|
|
260
271
|
|
|
261
|
-
**BREAKING CHANGE in v0.3.0:** `toSchemaOrg()` now targets the **
|
|
272
|
+
**BREAKING CHANGE in v0.3.0:** `toSchemaOrg()` now targets the **lite profile** and only includes modules that are marked as `schemaOrgMappable` in the modules registry. Non-mappable modules (e.g., `nutrition@1`, `schedule@1`) are excluded from the conversion.
|
|
262
273
|
|
|
263
274
|
```ts
|
|
264
275
|
import { fromSchemaOrg, toSchemaOrg, normalizeImage } from 'soustack';
|
|
@@ -361,10 +372,16 @@ const parsed = extractRecipeFromHTML(html);
|
|
|
361
372
|
|
|
362
373
|
```bash
|
|
363
374
|
# Validate with profiles (JSON output for pipelines)
|
|
364
|
-
npx soustack validate recipe.soustack.json --profile
|
|
375
|
+
npx soustack validate recipe.soustack.json --profile base --strict --json
|
|
376
|
+
|
|
377
|
+
# Schema-only validation (skip semantic conformance checks)
|
|
378
|
+
npx soustack validate recipe.soustack.json --schema-only
|
|
379
|
+
|
|
380
|
+
# Stable JSON conformance report for CI
|
|
381
|
+
npx soustack check recipe.soustack.json --json
|
|
365
382
|
|
|
366
383
|
# Repo-wide test run (validates every *.soustack.json)
|
|
367
|
-
npx soustack test --profile
|
|
384
|
+
npx soustack test --profile base
|
|
368
385
|
|
|
369
386
|
# Convert Schema.org ↔ Soustack
|
|
370
387
|
npx soustack convert --from schemaorg --to soustack recipe.jsonld -o recipe.soustack.json
|