question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add hook after all files have been processed?

See original GitHub issue

For typecheck.macro, I am trying to support the following feature:

file1.ts:

import { register } from 'typecheck.macro'
export interface Example {}
register('Example')

file2.ts:

import createValidator from 'typecheck.macro'
import type { Example } from "./file1.ts"
createValidator<Example>()

What’s going on here is that the register macro is being called to “register” the Example type. Then when createValidator is called inside “file2.ts”, it looks up the registered type and generates the validator.

This utilizes the fact that macros can have global inter-file state, like so:

let numberOfFiles = 0;

function macroHandler({ references, state, babel}) {
     numberOfFiles++;
     console.log(numberOfFiles)
}

export default createMacro(macroHandler)

Problem description:

The issue is that I need to wait until all files have been macro-ed. Then I can process all register paths at once (to generate a global map of all the types), and then I can process all instances of createValidator.

This would require a hook that is called once after all files have been processed. The hook wouldn’t have to have any parameters or anything complicated.

Suggested solution:

The api could like this:

let numberOfFiles = 0;

function macroHandler({ references, state, babel}) {
     numberOfFiles++;
     console.log(numberOfFiles)
}

function afterAllFilesHaveBeenProcessed() {
 // do something with numberOfFiles
// because we now know that all macro paths have been processed/encountered
}

export {afterAllFilesHaveBeenProcessed as hook}
export default createMacro(macroHandler)

I would be very willing to make a PR and implement this feature because it’s pretty crucial to typecheck.macro/I’m pretty sure typecheck.macro is only useful if it is a macro.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
heyheyhellocommented, Jul 13, 2020

Thought I’d mention you can actually get around this by leveraging the process.on('exit') hook of Node since everything runs in one process. It might be “dirty” but hey - works.

import { createMacro } from 'babel-plugin-macros';
import * as fs from 'fs';
import type { MacroHandler } from 'babel-plugin-macros';

const thingsFromAllFiles = [];

// Replaced each time the macro is run, so process.exit only runs _once_
let processExitHook = () => {};
process.on('exit', () => processExitHook());

const yourMacro: MacroHandler = ({ references, state }) => {
  references.default.forEach(referencePath => {
    // Here's where you'd do work. Maybe extract a string from the AST
    thingsFromAllFiles.push("...");
  });
  // Replace. Not set! Else you'll stack exit hooks
  processExitHook = () => {
    console.log(`Found ${thingsFromAllFiles.length} things in all files`);
    fs.writeFileSync("output.txt", thingsFromAllFiles.join('\n'));
  };
};

export default createMacro(yourMacro);

A real example is here in my repo: https://github.com/heyheyhello/stayknit/blob/fbc56a9d1f9ca15e4078af1b320b9d130bcc3190/contrib/babel-style-takeout/style-takeout.macro.ts I pull out CSS-in-JS to its own CSS file and replace the node with a generated CSS classname

Works OK. The only trouble is babel --watch doesn’t work because the process never exits 😅 Maybe I’ll think of something… I’m hoping to not just need to debounce() it…

0reactions
vedantroycommented, May 22, 2020

Yeah, this isn’t possible, which is unfortunate but inevitable due to the way Babel works.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Babel hook that runs after all files are processed?
The short answer is that Babel does not provide a hook like this because Babel's core transformation system runs one file at a...
Read more >
Hook that fires any time ANY file is opened?
The buffer's local variables (if any) will have been processed before the functions are called.
Read more >
Git Hooks - Git SCM
The hooks are all stored in the hooks subdirectory of the Git directory. ... After the entire commit process is completed, the post-commit...
Read more >
register_activation_hook() | Function
When the plugin consists of only one file and is (as by default) located at wp-content/plugins/sample.php the name of this hook will be...
Read more >
Git Hooks | Atlassian Git Tutorial
To “install” a hook, all you have to do is remove the .sample extension. Or, if you're writing a new script from scratch,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found