Skip to content

Commit 09287da

Browse files
committed
Fail the build when a prepare target's variables don't match its run query
Add check.js, which Shopify CLI runs before building a JavaScript function when this package has it (Shopify/cli#8829). It exits non-zero, failing the build, when a prepare target returns variables its run query doesn't accept, and warns about variables it can't check. The check is moved here from Shopify/cli#8829: it follows what the prepare export returns, ignoring type annotations and casts, and validates it against the run query's variable definitions. Values it can't follow, such as parsed JSON, are warnings rather than errors, so valid code still builds.
1 parent 3a01dde commit 09287da

5 files changed

Lines changed: 780 additions & 0 deletions

File tree

‎.changeset/prepare-variables.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@shopify/shopify_function": minor
3+
---
4+
5+
Fail the build when a JavaScript function's prepare target returns variables its run query doesn't accept, and warn about variables it can't check. Needs a Shopify CLI that runs this package's `check.js`.

‎check.js‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/usr/bin/env node
2+
// Shopify CLI runs this, when the package has it, before bundling a JavaScript function:
3+
//
4+
// node check.js --function <function JSON>
5+
//
6+
// The function JSON is {handle, directory, entry, schema, targets: [{target, export, inputQuery}]}, where `export` is
7+
// the JavaScript function the CLI bundles. It exits non-zero, failing the build, when a prepare target returns
8+
// variables its run query doesn't accept, and warns about variables it can't check.
9+
const fs = require("node:fs");
10+
const { parseArgs } = require("node:util");
11+
const { prepareVariablesProblems } = require("./prepare-variables.js");
12+
13+
try {
14+
const { values } = parseArgs({ options: { function: { type: "string" } } });
15+
if (!values.function) throw new Error("Usage: check.js --function <function JSON>");
16+
const fn = { schema: "schema.graphql", targets: [], ...JSON.parse(fs.readFileSync(values.function, "utf8")) };
17+
const name = fn.handle ? `The function extension "${fn.handle}"` : "The function";
18+
let problems;
19+
try {
20+
problems = prepareVariablesProblems(fn);
21+
} catch (error) {
22+
// A problem in the check itself shouldn't stop the build
23+
console.warn(`${name}'s prepare variables couldn't be checked: ${error.message}`);
24+
problems = [];
25+
}
26+
const list = (warning) => problems.filter((problem) => problem.warning === warning).map((problem) => problem.message);
27+
28+
const warnings = list(true);
29+
if (warnings.length > 0) {
30+
console.warn(`${name} returns prepare variables that can't be checked against its run query\n${warnings.join("\n")}`);
31+
}
32+
const errors = list(false);
33+
if (errors.length > 0) {
34+
throw new Error(`${name} returns prepare variables its run query doesn't accept\n${errors.join("\n")}`);
35+
}
36+
} catch (error) {
37+
console.error(error.message);
38+
process.exitCode = 1;
39+
}

0 commit comments

Comments
 (0)