Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature-Request: Allow inject to replace #106

Open
hco opened this issue Mar 6, 2019 · 5 comments
Open

Feature-Request: Allow inject to replace #106

hco opened this issue Mar 6, 2019 · 5 comments

Comments

@hco
Copy link

hco commented Mar 6, 2019

I thought about something similar to #84, but I think it's a bit different.

In my case there's a part in my .js files, that should be regeneratered.
I have a simplified example:

const Foobar = () => {
  /* lot's of code */
};

Foobar.propTypes = {
  meta: PropTypes.object.isRequired,
  payload: PropTypes.object.isRequired,
}

/* some more code */

And I want to be able to "update" the lines with meta and payload with a hygen generator.
Not really sure how we could detect the end of the propTypes part yet, but maybe let's discuss the replacing part first :-)

@anithri
Copy link
Contributor

anithri commented Apr 3, 2019

I think writing code to change or replace lines in a file is going to be very specific to the task at hand. A generic solution is going to be kind of nightmarish to write.

One way to approach it might be

import foobarProps from './foobarProps'
const Foobar = () => {
  /* lot's of code */
};

And then have your generator overwrite the foobarProps.js file.

Another approach would be to use a shell command to run an appropriate script.

@TroyAlford
Copy link

TroyAlford commented Jan 12, 2021

I landed here, today, looking for the same kind of code-mod functionality, and wondered what the group might think about something like:

replace:
  from: "\n<%= componentName %>.propTypes = {\n"
  to: "\n};\n"

In essence, you define make a RegEx-y pair of matchers, and then inject the content between them. The replacement would only work if:

  • from is found
  • to is found after from

An alternative semantic might be to expand upon the after frontmatter, allowing the user to provide both a before and an after, with the same overall logic. This has the added benefit of not requiring the user to have to use indentation syntax in the yml block, which could be confusing to people.

The above would then become:

after: "\n<%= componentName %>.propTypes = {\n"
before: "\n};\n"

The supposition is that after will still match the last instance of whatever after matches, and before will now match the next instance it matches, following after.

If there is no after, only a before, we could simply allow the injection to occur prior to the first occurrence of before.

One limitation, here, is that these semantics don't allow you to replace/remove Foobar.propTypes entirely - they would only allow you to find it and replace its contents. This, to me, is an argument the replace semantics - which could replace what it matches, as well.

Perhaps both syntax additions would be nice, to give you more granular control over injection/replacement?

If these suggestions sound reasonable, I would be happy to try and submit a PR for the features.

@akosarek
Copy link

akosarek commented Oct 14, 2021

I created a helper function that can remove lines from a file. While it's not an integrated option, I thought it might help others if I shared it.

Template file:

---
to: filename.js
---
<%= h.removeLines("filename.js", 7, 20) %>

.hygen.js file

const fs = require('fs');

const removeLines = (data, to, from) => {
    const lines = Array.from({length: ((from +1) - to)}, (_, i) => i + to - 1);

    let d = data.split('\n')

    for (let i = lines.length -1; i >= 0; i--) {
        d.splice(lines[i],1);
    }

    return d.join('\n');
}

module.exports = {
    helpers: {
        removeLines: (fileName, t, f) => {
            fs.readFile(fileName, 'utf8', (err, data) => {
                if (err) throw err;
                const content = removeLines(data, t, f);
                fs.writeFile(fileName, content, err => {
                    if (err) throw err;
                });
            })
        }
    }
}

@lindboe
Copy link

lindboe commented May 12, 2022

I have a use-case in React Native recently for this.

To configure an app from RN 0.68+ template to use the New Architecture, you have to change a few lines of code. For example, for the Android configuration we want to set newArchEnabled=false in android/gradle.properties to true, as well as configuring enableHermes: false, in android/app/build.gradle to true. There are several other useful tweaks to make as well. I've been spinning up a lot of new projects to test new things and having the ability to quickly change this with hygen would be super useful.

I'd also love to use this for the ability to quickly change other configuration values in projects.

@c-vetter
Copy link

From what I see, the proposal to just allow using after and before together to declare a range for replacement seems the most straightforward path, and something that may be found by just trying it, which I think is a nice feature.

One limitation, here, is that these semantics don't allow you to replace/remove Foobar.propTypes entirely - they would only allow you to find it and replace its contents. This, to me, is an argument the replace semantics - which could replace what it matches, as well.
This is actually no practical limitation, given that we are using regular expressions, just use look-ahead and look-behind:

---
to: src/index.ts
inject: true
after: (?=\n<%= componentName %>.propTypes = {\n)
before: (?<=\n};\n)
---
…replacement…

I'd like to pile on adding the at property that actually replaces a single line with the template's content. That would make it unnecessary to repeat the same regex for this purpose.

This will also automatically allow deletion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants