fix(tools): stage course cards from M5, audit noun words without flagging identifiers, Node<24.2 main guard, rename-proof expansion-check, safe check-links
- cardDirs: course/cards only from Module 5 (spec 6.2a); fixture modules 04/05 and tests - coupling-audit: noun words match as UPPERCASE, PascalCase or a whole string literal; lowercase identifiers like key/flag pass; card names keep every variant - isMain() argv guard replaces import.meta.main in coupling-audit and verify-references; engines.node >=22 - expansion-check: git diff --no-renames so moving engine code into content fails - start-module and other tools: clear error when .course.json is missing - check-links: malformed URLs reported as invalid URL instead of throwing Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0700cac492
commit
ad0701395d
26 files changed
+213
-47
No files matched your search
@@ -14,9 +14,23 @@ test("start_module_copies_tests", () => {
|
||||
assert.match(r.out, /newGame, summon, play/);
|
||||
});
|
||||
|
||||
test("start_module_copies_course_cards", () => {
|
||||
test("start_module_copies_course_cards_from_module_5", () => {
|
||||
// Spec §6.2a: Modules 1-4 keep their cards in the learner's code; course/cards
|
||||
// (with the M3/M4 drop answers and the M5 data format) arrives with Module 5.
|
||||
for (const [num, prev] of [["01", null], ["04", "m03.rs"]]) {
|
||||
const ws = copyFixture("ws-start");
|
||||
if (prev) {
|
||||
mkdirSync(join(ws, "tests"), { recursive: true });
|
||||
writeFileSync(join(ws, "tests", prev), "");
|
||||
}
|
||||
const r = run("start-module.mjs", [num, ws], env);
|
||||
assert.equal(r.code, 0, r.out);
|
||||
assert.ok(!existsSync(join(ws, "cards/test-fixture.json")), `module ${num} gets no course cards`);
|
||||
}
|
||||
const ws = copyFixture("ws-start");
|
||||
const r = run("start-module.mjs", ["01", ws], env);
|
||||
mkdirSync(join(ws, "tests"), { recursive: true });
|
||||
writeFileSync(join(ws, "tests/m04.rs"), "");
|
||||
const r = run("start-module.mjs", ["05", ws], env);
|
||||
assert.equal(r.code, 0, r.out);
|
||||
assert.ok(existsSync(join(ws, "cards/test-fixture.json")));
|
||||
});
|
||||
@@ -24,17 +38,25 @@ test("start_module_copies_course_cards", () => {
|
||||
test("start_module_copies_module_cards_up_to_the_module", () => {
|
||||
const early = copyFixture("ws-start");
|
||||
assert.equal(run("start-module.mjs", ["01", early], env).code, 0);
|
||||
assert.ok(existsSync(join(early, "cards/test-fixture.json")));
|
||||
assert.ok(!existsSync(join(early, "cards/module-fixture.json")));
|
||||
const later = copyFixture("ws-start");
|
||||
mkdirSync(join(later, "tests"), { recursive: true });
|
||||
writeFileSync(join(later, "tests/m02.rs"), "");
|
||||
const r = run("start-module.mjs", ["03", later], env);
|
||||
assert.equal(r.code, 0, r.out);
|
||||
assert.ok(existsSync(join(later, "cards/test-fixture.json")));
|
||||
assert.ok(!existsSync(join(later, "cards/test-fixture.json")));
|
||||
assert.ok(existsSync(join(later, "cards/module-fixture.json")));
|
||||
});
|
||||
|
||||
test("start_module_explains_missing_course_json", () => {
|
||||
const ws = copyFixture("ws-content-only");
|
||||
const r = run("start-module.mjs", ["01", join(ws, "no-such-dir")], env);
|
||||
assert.equal(r.code, 1);
|
||||
assert.match(r.out, /No \.course\.json/);
|
||||
assert.match(r.out, /workspace-template/);
|
||||
assert.doesNotMatch(r.out, /ENOENT|at .*\.mjs:\d+/);
|
||||
});
|
||||
|
||||
test("start_module_copies_module_levels", () => {
|
||||
const ws = copyFixture("ws-start");
|
||||
mkdirSync(join(ws, "tests"), { recursive: true });
|
||||
|
||||
Reference in new issue
Block a user