Skip to content

Commit 05c8f6f

Browse files
committed
refactor: hook context
1 parent 4c29662 commit 05c8f6f

File tree

5 files changed

+42
-48
lines changed

5 files changed

+42
-48
lines changed

default_hooks.ts

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Hook, PrimitiveType } from "./types.ts";
1+
import type { Hook, HookContext, PrimitiveType } from "./types.ts";
22
import { printArgs } from "./utils.ts";
33

44
const VALID_MALE_VALUES = new Set<PrimitiveType>([
@@ -16,19 +16,21 @@ const VALID_FEMALE_VALUES = new Set<PrimitiveType>([
1616
"Female",
1717
]);
1818

19+
const contextMatchedMap = new WeakMap<HookContext, string>();
20+
1921
function createGenderHook(gender: "male" | "female"): Hook {
20-
return (source, args, ctx) => {
21-
if (ctx.metadata.matched) {
22-
return ctx.out;
22+
return (ctx, args) => {
23+
if (contextMatchedMap.has(ctx)) {
24+
return contextMatchedMap.get(ctx)!;
2325
}
2426
if (
25-
gender === "male" && VALID_MALE_VALUES.has(source) ||
26-
gender === "female" && VALID_FEMALE_VALUES.has(source)
27+
gender === "male" && VALID_MALE_VALUES.has(ctx.original) ||
28+
gender === "female" && VALID_FEMALE_VALUES.has(ctx.original)
2729
) {
28-
ctx.metadata.matched = true;
29-
return printArgs(args);
30+
const result = printArgs(args);
31+
contextMatchedMap.set(ctx, result);
32+
return result;
3033
}
31-
return "";
3234
};
3335
}
3436

@@ -40,28 +42,27 @@ function getPluralRules(locale: string) {
4042
return pluralRules.get(locale)!;
4143
}
4244

43-
const symPluralRule = Symbol("pluralRule");
45+
const contextPluralMap = new WeakMap<HookContext, Intl.LDMLPluralRule>();
4446

4547
function createPluralHook(pluralRule: Intl.LDMLPluralRule): Hook {
46-
return (source, args, ctx, info) => {
47-
if (ctx.metadata.matched) {
48-
return ctx.out;
48+
return (ctx, args) => {
49+
if (contextMatchedMap.has(ctx)) {
50+
return contextMatchedMap.get(ctx)!;
4951
}
50-
let selectedPluralRule = ctx.metadata[symPluralRule] as
51-
| Intl.LDMLPluralRule
52-
| undefined;
53-
if (!ctx.metadata[symPluralRule]) {
54-
selectedPluralRule = ctx.metadata[symPluralRule] = getPluralRules(
55-
info.locale ?? "en",
56-
).select(+(source ?? 0));
52+
let selectedPluralRule = contextPluralMap.get(ctx);
53+
if (!selectedPluralRule) {
54+
selectedPluralRule = getPluralRules(ctx.locale ?? "en").select(
55+
+(ctx.original ?? 0),
56+
);
57+
contextPluralMap.set(ctx, selectedPluralRule);
5758
}
5859
if (
5960
selectedPluralRule === pluralRule
6061
) {
61-
ctx.metadata.matched = true;
62-
return printArgs(args);
62+
const result = printArgs(args);
63+
contextMatchedMap.set(ctx, result);
64+
return result;
6365
}
64-
return "";
6566
};
6667
}
6768

@@ -79,9 +80,9 @@ export const defaultHooks: Record<string, Hook> = {
7980
other: createPluralHook("other"),
8081

8182
// else
82-
else: (_, args, ctx) => {
83-
if (ctx.metadata.matched) {
84-
return ctx.out;
83+
else: (ctx, args) => {
84+
if (contextMatchedMap.has(ctx)) {
85+
return contextMatchedMap.get(ctx)!;
8586
}
8687
return printArgs(args);
8788
},

interpreter.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ Deno.test("interpreter, basic template value", () => {
3333
Deno.test("interpreter, template value with method", () => {
3434
const runtime = new Interpreter({
3535
hooks: {
36-
upper: (source, _, ctx) => `${ctx.out ?? source}`.toUpperCase(),
37-
trim: (source, _, ctx) => `${ctx.out ?? source}`.trim(),
36+
upper: (ctx) => `${ctx.current}`.toUpperCase(),
37+
trim: (ctx) => `${ctx.current}`.trim(),
3838
},
3939
});
4040

interpreter.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import type {
55
Hook,
66
HookArg,
77
HookContext,
8-
HookInfo,
98
PrimitiveType,
109
Runtime,
1110
TaggedTemplateHandler,
@@ -107,15 +106,19 @@ function getSafeMethod(
107106
return null;
108107
}
109108

110-
function createDecorator(hooks: Record<string, Hook>, info: HookInfo) {
111-
return (source: PrimitiveType) => {
109+
function createDecorator(
110+
hooks: Record<string, Hook>,
111+
baseCtx: Omit<HookContext, "original" | "current">,
112+
) {
113+
return (value: PrimitiveType) => {
112114
const ctx: HookContext = {
113-
out: null,
114-
metadata: {},
115+
original: value,
116+
current: value,
117+
...baseCtx,
115118
};
116119
const decoratedSource = new Proxy({
117120
toString() {
118-
return ctx.out ?? `${source}`;
121+
return `${ctx.current ?? ""}`;
119122
},
120123
}, {
121124
get(target, prop) {
@@ -125,8 +128,7 @@ function createDecorator(hooks: Record<string, Hook>, info: HookInfo) {
125128
if (prop in hooks) {
126129
const hook = hooks[prop as string];
127130
return (...args: HookArg[]) => {
128-
const nextOut = hook(source, args, ctx, info);
129-
ctx.out = nextOut;
131+
ctx.current = hook(ctx, args);
130132
return decoratedSource;
131133
};
132134
}

mod.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ export type {
33
Hook,
44
HookArg,
55
HookContext,
6-
HookInfo,
76
PrimitiveType,
87
Runtime,
98
} from "./types.ts";

types.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,12 @@ export interface Runtime {
1111
}
1212

1313
export interface HookContext {
14-
out: string | null;
15-
metadata: Record<string | symbol, unknown>;
16-
}
17-
18-
export interface HookInfo {
14+
original: PrimitiveType;
15+
current: PrimitiveType;
1916
locale: string | null;
2017
}
2118

22-
export type Hook = (
23-
source: PrimitiveType,
24-
args: HookArg[],
25-
ctx: HookContext,
26-
info: HookInfo,
27-
) => string | null;
19+
export type Hook = (ctx: HookContext, args: HookArg[]) => PrimitiveType;
2820

2921
export type TaggedTemplateHandler = (
3022
strings: TemplateStringsArray,

0 commit comments

Comments
 (0)