Skip to content

Commit ad6e6df

Browse files
committed
bug #31 [Stimulus] Report a clear error for a missing or malformed controllers.json (Kocal)
This PR was merged into the main branch. Discussion ---------- [Stimulus] Report a clear error for a missing or malformed controllers.json | Q | A | -------------- | --- | Bug fix? | yes | New feature? | no | Deprecations? | no | Documentation? | no | Issues | - | License | MIT When the `stimulus` option pointed at a `controllers.json` that was missing or contained invalid JSON, `generateControllersModule` threw a raw Node error (`ENOENT`, or a bare `SyntaxError`) instead of the clear ``@symfony`/reprise:`-prefixed message the rest of that module already uses for every other failure (package not installed, controller not declared, etc.). This PR wraps the read and parse so a missing file and malformed JSON each produce an actionable ``@symfony`/reprise:` error naming the file, consistent with the module's other error paths. Adds tests for both cases, plus a malformed JSON fixture. It's a pure core change, so it covers both bundlers through the shared `generateControllersModule`. Commits ------- 8690952 [Stimulus] Report a clear error for a missing or malformed controllers.json
2 parents 78eb440 + 8690952 commit ad6e6df

3 files changed

Lines changed: 47 additions & 1 deletion

File tree

assets/src/core/stimulus.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,37 @@ const LAZY_COMMENT_RE =
4848
/(?:\/\*!?\s*stimulusFetch:\s*['"]lazy['"]\s*\*\/|\/\/\s*stimulusFetch:\s*['"]lazy['"])\s*(?:export\s+(?:default\s+)?)?(?:abstract\s+)?class\b/i;
4949
const LOCAL_CONTROLLER_RE = /[-_]controller\.[jt]s$/;
5050

51+
// Every other failure in this module reports a `@symfony/reprise:` error; a missing or malformed
52+
// controllers.json must not slip through as a raw Node ENOENT/SyntaxError.
53+
function readControllersJson(controllersJson: string): ControllersJson {
54+
let raw: string;
55+
try {
56+
raw = readFileSync(controllersJson, 'utf8');
57+
} catch (err) {
58+
if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
59+
throw new Error(
60+
`@symfony/reprise: cannot read the Stimulus controllers file "${controllersJson}". ` +
61+
'Create it, or point the "stimulus" option at the right path.'
62+
);
63+
}
64+
throw err;
65+
}
66+
try {
67+
return JSON.parse(raw) as ControllersJson;
68+
} catch (err) {
69+
throw new Error(
70+
`@symfony/reprise: the Stimulus controllers file "${controllersJson}" is not valid JSON` +
71+
`${err instanceof Error ? ` (${err.message})` : ''}.`
72+
);
73+
}
74+
}
75+
5176
export function generateControllersModule(opts: ResolvedStimulusOptions, root: string, isDev: boolean): string {
5277
// Keyed by identifier; local added after third-party so a local override wins (last write wins).
5378
const controllers = new Map<string, ResolvedController>();
5479

5580
const require = createRequire(path.join(root, 'noop.js'));
56-
const json = JSON.parse(readFileSync(opts.controllersJson, 'utf8')) as ControllersJson;
81+
const json = readControllersJson(opts.controllersJson);
5782

5883
for (const packageName of Object.keys(json.controllers ?? {})) {
5984
let pkg: { symfony?: { controllers?: Record<string, PackageControllerConfig> } };

assets/test/core/stimulus.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,26 @@ describe('generateControllersModule — third-party', () => {
3838
});
3939
});
4040

41+
describe('generateControllersModule — controllers.json errors', () => {
42+
it('throws a clear error when the controllers.json file is missing', () => {
43+
const missing = {
44+
controllersJson: join(root, 'no-such-controllers.json'),
45+
controllersDir: opts.controllersDir,
46+
};
47+
expect(() => generateControllersModule(missing, root, false)).toThrow(
48+
/@symfony\/reprise: cannot read the Stimulus controllers file/
49+
);
50+
});
51+
52+
it('throws a clear error when the controllers.json file is not valid JSON', () => {
53+
const malformed = {
54+
controllersJson: join(root, 'malformed-controllers.json'),
55+
controllersDir: opts.controllersDir,
56+
};
57+
expect(() => generateControllersModule(malformed, root, false)).toThrow(/is not valid JSON/);
58+
});
59+
});
60+
4161
describe('generateControllersModule — local', () => {
4262
const localOpts = { controllersJson: join(root, 'controllers.json'), controllersDir: join(root, 'controllers') };
4363

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{ "controllers": { this is not valid json }

0 commit comments

Comments
 (0)