diff --git a/README.md b/README.md index 7dd51eb..34491de 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ render("./output", { |---|---| | `<@if(context.x)>` | Conditional block — boolean check (must end with `<@endif>`) | | `<@if(eq(context.x,"value"))>` | Conditional block — string equality check | +| `<@if(neq(context.x,"value"))>` | Conditional block — string inequality check | | `<@elseif(context.y)>` | Else-if branch (same forms as `@if`) | | `<@else>` | Else branch | | `<@endif>` | End conditional block | @@ -72,6 +73,7 @@ render("./output", { |---|---| | `<@if(context.x)>dirname` | Conditionally include directory/file (boolean check) | | `<@if(eq(context.x,"value"))>dirname` | Conditionally include by string equality | +| `<@if(neq(context.x,"value"))>dirname` | Conditionally include by string inequality | | `<@var(context.x)>` | Dynamic directory/file name | These can be combined: `<@if(context.web.create)><@var(context.web.dir)>` creates a directory named by `context.web.dir` only if `context.web.create` is true. diff --git a/index.test.ts b/index.test.ts index 75de98c..fd95a70 100644 --- a/index.test.ts +++ b/index.test.ts @@ -568,3 +568,25 @@ test("if eq in path", () => { render(tmp,{test:"foo"}) expect(existsSync(join(tmp,"test"))).toBe(false) }) + +test("if neq in file", () => { + const createRenderer = initRenderer("./testdata/neq_in_file") + expect(() => createRenderer(z.object({test: z.boolean()}))).toThrow(SchemaMismatchError) + const render = createRenderer(z.object({test: z.string()})) + + render(tmp,{test:"foo"}) + expect(readFileSync(join(tmp,"test.txt"), "utf-8")).toContain("not-test") + + render(tmp,{test:"test"}) + expect(readFileSync(join(tmp,"test.txt"), "utf-8")).toContain("test") + expect(readFileSync(join(tmp,"test.txt"), "utf-8")).not.toContain("not-test") +}) + +test("if neq in path", () => { + const createRenderer = initRenderer("./testdata/neq_in_path") + const render = createRenderer(z.object({test: z.string()})) + render(tmp,{test:"foo"}) + expect(existsSync(join(tmp,"not-test"))).toBe(true) + render(tmp,{test:"test"}) + expect(existsSync(join(tmp,"not-test"))).toBe(false) +}) diff --git a/package.json b/package.json index 25cb3dd..fe39bcf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@gregorlohaus/tdir", - "version": "0.1.7", + "version": "0.1.8", "license": "MIT", "type": "module", "main": "./dist/index.js", diff --git a/parser.ts b/parser.ts index 8856cd9..3a2f25a 100644 --- a/parser.ts +++ b/parser.ts @@ -10,14 +10,14 @@ export type TemplateVariable = { const IF_RE = /<@(?:if|elseif)\((.+?)\)>/g const VAR_RE = /<@var\(context\.(.+?)(?::(\w+))?\)>/g const DIRECTIVE_RE = /<@(if|elseif|else|endif)(?:\((.+?)\))?>/g -const EQ_RE = /^eq\(context\.(.+?),\s*"(.*)"\)$/ +const STRING_COMPARE_RE = /^(?:eq|neq)\(context\.(.+?),\s*"(.*)"\)$/ const PATH_RE = /^context\.(.+)$/ function extractCondition(expr: string | undefined, vars: TemplateVariable[]) { if (!expr) throw new Error("Missing condition expression") - const eqMatch = expr.match(EQ_RE) - if (eqMatch) { - vars.push({ path: eqMatch[1]!, type: "string" }) + const stringCompareMatch = expr.match(STRING_COMPARE_RE) + if (stringCompareMatch) { + vars.push({ path: stringCompareMatch[1]!, type: "string" }) return } const pathMatch = expr.match(PATH_RE) diff --git a/render.ts b/render.ts index d032263..12cbec5 100644 --- a/render.ts +++ b/render.ts @@ -14,7 +14,7 @@ import { TextDecoder } from "node:util" const IF_PATH_RE = /^<@if\((.+?)\)>(.*)$/ const VAR_RE = /<@var\(context\.(.+?)(?::(\w+))?\)>/g const DIRECTIVE_RE = /<@(if|elseif|else|endif)(?:\((.+?)\))?>/g -const EQ_RE = /^eq\(context\.(.+?),\s*"(.*)"\)$/ +const STRING_COMPARE_RE = /^(eq|neq)\(context\.(.+?),\s*"(.*)"\)$/ const PATH_RE = /^context\.(.+)$/ export type ReverseMapToken = { @@ -68,9 +68,10 @@ type RenderState = { function evalCondition(expr: string | undefined, context: Record): boolean { if (!expr) throw new Error("Missing condition expression") - const eqMatch = expr.match(EQ_RE) - if (eqMatch) { - return resolveContext(context, eqMatch[1]!) === eqMatch[2] + const stringCompareMatch = expr.match(STRING_COMPARE_RE) + if (stringCompareMatch) { + const result = resolveContext(context, stringCompareMatch[2]!) === stringCompareMatch[3] + return stringCompareMatch[1] === "eq" ? result : !result } const pathMatch = expr.match(PATH_RE) if (pathMatch) { diff --git a/testdata/neq_in_file/test.txt b/testdata/neq_in_file/test.txt new file mode 100644 index 0000000..fab8ca8 --- /dev/null +++ b/testdata/neq_in_file/test.txt @@ -0,0 +1 @@ +<@if(neq(context.test,"test"))>not-test<@else>test<@endif> diff --git "a/testdata/neq_in_path/<@if(neq(context.test,\"test\"))>not-test" "b/testdata/neq_in_path/<@if(neq(context.test,\"test\"))>not-test" new file mode 100644 index 0000000..21b652d --- /dev/null +++ "b/testdata/neq_in_path/<@if(neq(context.test,\"test\"))>not-test" @@ -0,0 +1 @@ +not test