Add oxlint for type-aware linting that Biome cannot cover
Install oxlint with tsgolint for TypeScript type information. Enable rules for unnecessary type assertions, deprecated API usage, preferring replaceAll over replace with global regex, and String.raw for escaped backslashes. Fix all violations: remove redundant as-casts, replace deprecated FormEvent with SubmitEvent, convert replace(/g) to replaceAll, and use String.raw in escapeRegExp. Add oxlint to the pnpm check gate alongside Biome. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -30,11 +30,11 @@ describe("stripTags", () => {
|
||||
expect(stripTags("{@hit 5}")).toBe("+5");
|
||||
});
|
||||
|
||||
it("strips {@h} to Hit: ", () => {
|
||||
it("strips {@h} to Hit:", () => {
|
||||
expect(stripTags("{@h}")).toBe("Hit: ");
|
||||
});
|
||||
|
||||
it("strips {@hom} to Hit or Miss: ", () => {
|
||||
it("strips {@hom} to Hit or Miss:", () => {
|
||||
expect(stripTags("{@hom}")).toBe("Hit or Miss: ");
|
||||
});
|
||||
|
||||
|
||||
@@ -373,8 +373,8 @@ function extractCr(cr: string | { cr: string } | undefined): string {
|
||||
function makeCreatureId(source: string, name: string): CreatureId {
|
||||
const slug = name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/(^-|-$)/g, "");
|
||||
.replaceAll(/[^a-z0-9]+/g, "-")
|
||||
.replaceAll(/(^-|-$)/g, "");
|
||||
return creatureId(`${source.toLowerCase()}:${slug}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,55 +25,58 @@ export function stripTags(text: string): string {
|
||||
let result = text;
|
||||
|
||||
// {@h} → "Hit: "
|
||||
result = result.replace(/\{@h\}/g, "Hit: ");
|
||||
result = result.replaceAll("{@h}", "Hit: ");
|
||||
|
||||
// {@hom} → "Hit or Miss: "
|
||||
result = result.replace(/\{@hom\}/g, "Hit or Miss: ");
|
||||
result = result.replaceAll("{@hom}", "Hit or Miss: ");
|
||||
|
||||
// {@actTrigger} → "Trigger:"
|
||||
result = result.replace(/\{@actTrigger\}/g, "Trigger:");
|
||||
result = result.replaceAll("{@actTrigger}", "Trigger:");
|
||||
|
||||
// {@actResponse} → "Response:"
|
||||
result = result.replace(/\{@actResponse\}/g, "Response:");
|
||||
result = result.replaceAll("{@actResponse}", "Response:");
|
||||
|
||||
// {@actSaveSuccess} → "Success:"
|
||||
result = result.replace(/\{@actSaveSuccess\}/g, "Success:");
|
||||
result = result.replaceAll("{@actSaveSuccess}", "Success:");
|
||||
|
||||
// {@actSaveSuccessOrFail} → handled below as parameterized
|
||||
|
||||
// {@recharge 5} → "(Recharge 5-6)", {@recharge} → "(Recharge 6)"
|
||||
result = result.replace(/\{@recharge\s+(\d)\}/g, "(Recharge $1-6)");
|
||||
result = result.replace(/\{@recharge\}/g, "(Recharge 6)");
|
||||
result = result.replaceAll(/\{@recharge\s+(\d)\}/g, "(Recharge $1-6)");
|
||||
result = result.replaceAll("{@recharge}", "(Recharge 6)");
|
||||
|
||||
// {@dc N} → "DC N"
|
||||
result = result.replace(/\{@dc\s+(\d+)\}/g, "DC $1");
|
||||
result = result.replaceAll(/\{@dc\s+(\d+)\}/g, "DC $1");
|
||||
|
||||
// {@hit N} → "+N"
|
||||
result = result.replace(/\{@hit\s+(\d+)\}/g, "+$1");
|
||||
result = result.replaceAll(/\{@hit\s+(\d+)\}/g, "+$1");
|
||||
|
||||
// {@atkr type} → mapped attack roll text
|
||||
result = result.replace(/\{@atkr\s+([^}]+)\}/g, (_, type: string) => {
|
||||
result = result.replaceAll(/\{@atkr\s+([^}]+)\}/g, (_, type: string) => {
|
||||
return ATKR_MAP[type.trim()] ?? "Attack Roll:";
|
||||
});
|
||||
|
||||
// {@actSave ability} → "Ability saving throw"
|
||||
result = result.replace(/\{@actSave\s+([^}]+)\}/g, (_, ability: string) => {
|
||||
const name = ABILITY_MAP[ability.trim().toLowerCase()];
|
||||
return name ? `${name} saving throw` : `${ability} saving throw`;
|
||||
});
|
||||
result = result.replaceAll(
|
||||
/\{@actSave\s+([^}]+)\}/g,
|
||||
(_, ability: string) => {
|
||||
const name = ABILITY_MAP[ability.trim().toLowerCase()];
|
||||
return name ? `${name} saving throw` : `${ability} saving throw`;
|
||||
},
|
||||
);
|
||||
|
||||
// {@actSaveFail} → "Failure:" or {@actSaveFail N} → "Failure by N or More:"
|
||||
result = result.replace(
|
||||
result = result.replaceAll(
|
||||
/\{@actSaveFail\s+(\d+)\}/g,
|
||||
"Failure by $1 or More:",
|
||||
);
|
||||
result = result.replace(/\{@actSaveFail\}/g, "Failure:");
|
||||
result = result.replaceAll("{@actSaveFail}", "Failure:");
|
||||
|
||||
// {@actSaveSuccessOrFail} → keep as-is label
|
||||
result = result.replace(/\{@actSaveSuccessOrFail\}/g, "Success or Failure:");
|
||||
result = result.replaceAll("{@actSaveSuccessOrFail}", "Success or Failure:");
|
||||
|
||||
// {@actSaveFailBy N} → "Failure by N or More:"
|
||||
result = result.replace(
|
||||
result = result.replaceAll(
|
||||
/\{@actSaveFailBy\s+(\d+)\}/g,
|
||||
"Failure by $1 or More:",
|
||||
);
|
||||
@@ -81,7 +84,7 @@ export function stripTags(text: string): string {
|
||||
// Generic tags: {@tag Display|Source|...} → Display (first segment before |)
|
||||
// Covers: spell, condition, damage, dice, variantrule, action, skill,
|
||||
// creature, hazard, status, plus any unknown tags
|
||||
result = result.replace(
|
||||
result = result.replaceAll(
|
||||
/\{@(\w+)\s+([^}]+)\}/g,
|
||||
(_, tag: string, content: string) => {
|
||||
// For tags with Display|Source format, extract first segment
|
||||
|
||||
Reference in New Issue
Block a user