Skip to content

Commit 4aed1e5

Browse files
committed
Simplify definition of HOOKS entries
1 parent 32c3995 commit 4aed1e5

File tree

1 file changed

+62
-63
lines changed

1 file changed

+62
-63
lines changed

entry.ts

Lines changed: 62 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -125,27 +125,9 @@ interface Hook {
125125
runAfter?: HookName[];
126126
}
127127

128-
interface LockableHook extends Hook {
129-
/** Upon resolution, indicates that this hook has completed */
130-
lock: Promise<unknown>;
131-
/** Promise that must resolve before this hook begins execution */
132-
locksToWaitFor?: Promise<unknown>;
133-
/** Marks this hook as complete */
134-
unlock: () => void;
135-
}
136-
137-
/** Wraps a non-lockable hook to add properties used for locking */
138-
const createLockableHook = (hook: Hook): LockableHook => {
139-
let unlock = () => undefined as void;
140-
const lock = new Promise<void>(resolve => {
141-
unlock = resolve;
142-
});
143-
return { ...hook, lock, unlock };
144-
};
145-
146128
/** Hooks expressed in a format similar to .pre-commit-config.yaml */
147-
const HOOKS: Record<HookName, LockableHook> = {
148-
[HookName.Autoflake]: createLockableHook({
129+
const HOOKS: Record<HookName, Hook> = {
130+
[HookName.Autoflake]: {
149131
action: sources =>
150132
run(
151133
"autoflake",
@@ -158,8 +140,8 @@ const HOOKS: Record<HookName, LockableHook> = {
158140
),
159141
include: /\.py$/,
160142
runAfter: [HookName.Sed],
161-
}),
162-
[HookName.Black]: createLockableHook({
143+
},
144+
[HookName.Black]: {
163145
action: async (sources, args) =>
164146
args["python-version"]?.startsWith("2") &&
165147
run(
@@ -180,8 +162,8 @@ const HOOKS: Record<HookName, LockableHook> = {
180162
),
181163
include: /\.py$/,
182164
runAfter: [HookName.Isort],
183-
}),
184-
[HookName.ClangFormat]: createLockableHook({
165+
},
166+
[HookName.ClangFormat]: {
185167
action: sources =>
186168
run(
187169
"/clang-format",
@@ -191,8 +173,8 @@ const HOOKS: Record<HookName, LockableHook> = {
191173
),
192174
include: /\.(cpp|proto$)/,
193175
runAfter: [HookName.Sed],
194-
}),
195-
[HookName.EsLint]: createLockableHook({
176+
},
177+
[HookName.EsLint]: {
196178
action: async sources => {
197179
try {
198180
await run(
@@ -210,25 +192,25 @@ const HOOKS: Record<HookName, LockableHook> = {
210192
exclude: MINIFIED_JS_REGEX,
211193
include: /\.[jt]sx?$/,
212194
runAfter: [HookName.Sed],
213-
}),
214-
[HookName.Gofmt]: createLockableHook({
195+
},
196+
[HookName.Gofmt]: {
215197
action: sources => run("/gofmt", "-s", "-w", ...sources),
216198
include: /\.go$/,
217199
runAfter: [HookName.Sed],
218-
}),
219-
[HookName.GoogleJavaFormat]: createLockableHook({
200+
},
201+
[HookName.GoogleJavaFormat]: {
220202
action: sources =>
221203
run("java", "-jar", "/google-java-format", "--replace", ...sources),
222204
include: /\.java$/,
223205
runAfter: [HookName.Sed],
224-
}),
225-
[HookName.GradleDependenciesSorter]: createLockableHook({
206+
},
207+
[HookName.GradleDependenciesSorter]: {
226208
action: sources =>
227209
run("java", "-jar", "/gradle-dependencies-sorter", ...sources),
228210
include: /build\.gradle(\.kts)?$/,
229211
runAfter: [HookName.Sed],
230-
}),
231-
[HookName.Isort]: createLockableHook({
212+
},
213+
[HookName.Isort]: {
232214
// isort's automatic config file detection is broken
233215
// https://github.com/PyCQA/isort/issues/1907
234216
// https://github.com/samueljsb/qaz/pull/104
@@ -237,8 +219,8 @@ const HOOKS: Record<HookName, LockableHook> = {
237219
run("isort", "--settings", "/.editorconfig", ...sources),
238220
include: /\.py$/,
239221
runAfter: [HookName.Autoflake],
240-
}),
241-
[HookName.Ktfmt]: createLockableHook({
222+
},
223+
[HookName.Ktfmt]: {
242224
action: async sources => {
243225
/** Try to avoid ktfmt OOMs presumably caused by too many input files */
244226
const MAX_FILES_PER_PROCESS = 200;
@@ -261,13 +243,13 @@ const HOOKS: Record<HookName, LockableHook> = {
261243
},
262244
include: /\.kts?$/,
263245
runAfter: [HookName.Sed],
264-
}),
265-
[HookName.PackerFmt]: createLockableHook({
246+
},
247+
[HookName.PackerFmt]: {
266248
action: sources => run("/packer", "fmt", ...sources),
267249
include: /\.pkr\.hcl$/,
268250
runAfter: [HookName.Sed],
269-
}),
270-
[HookName.PrettierJs]: createLockableHook({
251+
},
252+
[HookName.PrettierJs]: {
271253
action: sources =>
272254
run(
273255
"prettier",
@@ -279,8 +261,8 @@ const HOOKS: Record<HookName, LockableHook> = {
279261
exclude: MINIFIED_JS_REGEX,
280262
include: /\.jsx?$/,
281263
runAfter: [HookName.Sed, HookName.EsLint],
282-
}),
283-
[HookName.PrettierNonJs]: createLockableHook({
264+
},
265+
[HookName.PrettierNonJs]: {
284266
action: sources =>
285267
run(
286268
"prettier",
@@ -292,8 +274,8 @@ const HOOKS: Record<HookName, LockableHook> = {
292274
),
293275
include: /\.(css|html?|markdown|md|scss|tsx?|xml|ya?ml)$/,
294276
runAfter: [HookName.Sed, HookName.Xsltproc, HookName.EsLint],
295-
}),
296-
[HookName.Ruff]: createLockableHook({
277+
},
278+
[HookName.Ruff]: {
297279
action: async (sources, args) => {
298280
if (args["python-version"]?.startsWith("2")) {
299281
return;
@@ -306,8 +288,8 @@ const HOOKS: Record<HookName, LockableHook> = {
306288
},
307289
include: /\.py$/,
308290
runAfter: [HookName.Autoflake],
309-
}),
310-
[HookName.Scalafmt]: createLockableHook({
291+
},
292+
[HookName.Scalafmt]: {
311293
action: async (sources, args) =>
312294
run(
313295
"/scalafmt",
@@ -330,12 +312,12 @@ const HOOKS: Record<HookName, LockableHook> = {
330312
),
331313
include: /\.(scala|sbt|sc)$/,
332314
runAfter: [HookName.Sed],
333-
}),
315+
},
334316
// Mimic sed by applying arbitrary regex transformations. Before proposing a
335317
// new transformation, please make sure that it's both (1) safe and (2) likely
336318
// to ever actually be needed. At Duolingo, we determine the latter criterion
337319
// empirically by seeing how many existing violations our codebase contains
338-
[HookName.Sed]: createLockableHook({
320+
[HookName.Sed]: {
339321
action: (sources, args) =>
340322
Promise.all(
341323
sources.map(source =>
@@ -391,8 +373,8 @@ const HOOKS: Record<HookName, LockableHook> = {
391373
),
392374
),
393375
include: /./,
394-
}),
395-
[HookName.Shfmt]: createLockableHook({
376+
},
377+
[HookName.Shfmt]: {
396378
action: async sources => {
397379
// Find source files that are Shell files. shfmt has a `-f` flag that
398380
// does this, but it sometimes returns false positives
@@ -442,13 +424,13 @@ const HOOKS: Record<HookName, LockableHook> = {
442424
exclude: /\.proto$/,
443425
include: /./,
444426
runAfter: [HookName.Sed],
445-
}),
446-
[HookName.Svgo]: createLockableHook({
427+
},
428+
[HookName.Svgo]: {
447429
action: sources => run("svgo", "--config", "/svgo.config.js", ...sources),
448430
include: /\.svg$/,
449431
runAfter: [HookName.Sed],
450-
}),
451-
[HookName.Taplo]: createLockableHook({
432+
},
433+
[HookName.Taplo]: {
452434
action: sources =>
453435
run(
454436
"/taplo",
@@ -467,8 +449,8 @@ const HOOKS: Record<HookName, LockableHook> = {
467449
),
468450
include: /\.toml$/,
469451
runAfter: [HookName.Sed],
470-
}),
471-
[HookName.TerraformFmt]: createLockableHook({
452+
},
453+
[HookName.TerraformFmt]: {
472454
action: sources =>
473455
Promise.all(
474456
// Officially `terraform fmt` only accepts a directory to recurse
@@ -484,8 +466,8 @@ const HOOKS: Record<HookName, LockableHook> = {
484466
),
485467
include: /\.tf$/,
486468
runAfter: [HookName.Sed],
487-
}),
488-
[HookName.Xsltproc]: createLockableHook({
469+
},
470+
[HookName.Xsltproc]: {
489471
action: sources =>
490472
Promise.all(
491473
sources.map(source =>
@@ -494,7 +476,7 @@ const HOOKS: Record<HookName, LockableHook> = {
494476
),
495477
include: /\.xml$/,
496478
runAfter: [HookName.Sed],
497-
}),
479+
},
498480
};
499481

500482
/** Files that match this pattern should never be processed */
@@ -550,19 +532,36 @@ const prefixLines = (() => {
550532
}
551533
}
552534

553-
// Set up hook locks
554-
Object.values(HOOKS).forEach(hook => {
535+
// Augment hook definitions to make them lockable
536+
interface LockableHook extends Hook {
537+
/** Upon resolution, indicates that this hook has completed */
538+
lock: Promise<unknown>;
539+
/** Promise that must resolve before this hook begins execution */
540+
locksToWaitFor?: Promise<unknown>;
541+
/** Marks this hook as complete */
542+
unlock: () => void;
543+
}
544+
const lockableHooks = Object.fromEntries(
545+
Object.entries(HOOKS).map(([name, hook]) => {
546+
let unlock = () => undefined as void;
547+
const lock = new Promise<void>(resolve => {
548+
unlock = resolve;
549+
});
550+
return [name, { ...hook, lock, unlock }];
551+
}),
552+
) as Record<HookName, LockableHook>;
553+
Object.values(lockableHooks).forEach(hook => {
555554
if (hook.runAfter) {
556555
hook.locksToWaitFor = Promise.all(
557-
hook.runAfter.map(hookName => HOOKS[hookName].lock),
556+
hook.runAfter.map(hookName => lockableHooks[hookName].lock),
558557
);
559558
}
560559
});
561560

562561
// Run all hooks in parallel
563562
let success = true;
564563
await Promise.all(
565-
Object.entries(HOOKS).map(
564+
Object.entries(lockableHooks).map(
566565
async ([name, { action, exclude, include, locksToWaitFor, unlock }]) => {
567566
// Wait until necessary hooks have completed
568567
await locksToWaitFor;

0 commit comments

Comments
 (0)