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

getStructure #346

Merged
merged 112 commits into from
Sep 15, 2018
Merged

getStructure #346

merged 112 commits into from
Sep 15, 2018

Conversation

cancerberoSgx
Copy link
Contributor

@cancerberoSgx cancerberoSgx commented Jun 12, 2018

I think this is ready:

  • scripts/ensureForEachStructureClassImplementsGetStructureMethod.ts to ensure for every structure its corresponding node kind implements getStruture method
  • for each node kind implementing getStructure there is a test (more or less exhaustively)
  • master merged
  • most of your review comments fixed (still checking one by one to make sure I'm not missing anything)
  • npm i && lint && build && test passing from scratch

@coveralls
Copy link

coveralls commented Jun 12, 2018

Coverage Status

Coverage decreased (-0.04%) to 94.729% when pulling 6553967 on cancerberoSgx:structure into a7c79c1 on dsherret:dev.

Copy link
Owner

@dsherret dsherret left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @cancerberoSgx, looks great overall! Thanks a lot! I made a lot of comments because there's still a bit of work to do here, but hopefully it will help out. I think you're on the right track.

By the way, if at any time you want to merge this I can merge it into a branch and then I'll pick up the work to finish it off.

@@ -16,7 +16,7 @@
"@mrmlnc/readdir-enhanced": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
"integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==",
"integrity": "sha1-UkryQNGjYFJ7cwR17PoTRKpUDd4=",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you revert this file? I think it's using an old version of npm which uses sha1 https://stackoverflow.com/a/47834854/188246

@@ -49,5 +50,16 @@ export function BodiedNode<T extends Constructor<BodiedNodeExtensionType>>(Base:

return this;
}

getStructure() {
let bodyText = this.getBody().getText().trim();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll have to improve this because right now this includes the indentation. If someone sets the body with this text it will be indented double the amount and might include a leading newline.

Probably instead get the statements within the body and then get the text within the source file from statements[0].getNonWhitespaceStart() to statements[statements.length - 1].getTrailingTriviaEnd(). Once that text is found, we'll have to remove the leading spaces from every line (so remove statements[0].getIndentationText() from every line).

@@ -105,5 +106,28 @@ export function BodyableNode<T extends Constructor<BodyableNodeExtensionType>>(B

return this;
}

getStructure() {
// TODO: This complication is because we need to remove body text wrapping braces.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment in BodiedNode. We should be able to use almost the same code here, but handle for when body is undefined.

src/compiler/base/ExportableNode.ts Outdated Show resolved Hide resolved
getStructure() {
return callBaseGetStructure<ExportableNodeStructure>(Base.prototype, this, {
isExported: this.isExported(),
isDefaultExport: this.isDefaultExport()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use this.hasDefaultKeyword().

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reason is because this.isDefaultExport() uses the symbols to figure that out, while this.hasDefaultKeyword() looks at only the AST, which is what we're interested in here.

// and also recreate the AST using structure and compare getText() of generated code with original node's
const aux = sourceFile.addStatements("class __AuxClass{}");
const decl = aux[0];
if (!TypeGuards.isClassDeclaration(decl)) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't worry about adding this. It's obvious from above that it's a class so just assert it.

@@ -202,4 +221,36 @@ describe(nameof(MethodDeclaration), () => {
});
});
});

describe(nameof<MethodDeclaration>(d => d.getStructure), () => {
function doTest(code: string, expectedStructure: MethodDeclarationStructure) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try using MakeRequired<MethodDeclarationStructure>

src/tests/compiler/function/functionDeclarationTests.ts Outdated Show resolved Hide resolved
@@ -129,4 +130,25 @@ describe(nameof(ParameterDeclaration), () => {
doTest("function identifier(param, param2, param3) {}", "param2", "function identifier(param, param3) {}");
});
});

describe(nameof<ParameterDeclaration>(d => d.getStructure), () => {
function doTest(code: string, expectedStructure: ParameterDeclarationStructure) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MakeRequired<ParameterDeclarationStructure>

function doTest(code: string, expectedStructure: ParameterDeclarationStructure) {
const {descendant} = getInfoFromTextWithDescendant<ParameterDeclaration>(code, SyntaxKind.Parameter);
const structure = descendant.getStructure();
expect(structure).to.contain(expectedStructure);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should do an exact comparison in case anything changes. expect(structure).to.deep.equal(expectedStructure).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, BTW right now for quickly testing I'm not doing what I've should, this is asserting on the structure object itself instead of re-render a new node asserting against the node.getText() - but at least it gives me some confidence I'm doing things OK and that it works ll the way down to text. Thank you very much for the review - i'm on it! :)

@cancerberoSgx
Copy link
Contributor Author

So, I made all the changes you asked David, with the exception of if (!TypeGuards.isClassDeclaration(decl)), that's my way of type-guard instead of using orThrows and also this one :

Hmmm, could we always use the same base (ConstructorDeclarationBase.prototype), but instead strip the unused properties when this.isOverload() is true? Then we can catch changes to the base that shouldn't be in there in a unit test.

@cancerberoSgx
Copy link
Contributor Author

Regarding:

By the way, if at any time you want to merge this I can merge it into a branch and then I'll pick up the work to finish it off.

I would really like to have this feature in the library since I'm generating a log of code in my projects and basically working with my handcrafted "getStructure" methods. If you think it's more practical that you finish off the work in your own branch then go ahead (I feel you wasted more time in th elast review than if you implemented by yourself.) But to be sincere I would like to keep working on this and give support for getStructure to the rest of the nodes. But primariy, as I said before I would really need this integrated in master ASAP.

Thanks!

@dsherret
Copy link
Owner

@cancerberoSgx I don't view it as wasting time because you taking on this work saves me a lot of time and plus it's another person who learns the inner workings of the library, which is always a plus. I just provided that as an option in case you didn't want to spend the time changing all my comments.

I'm going to be moving over the next week (lots of time spent packing) and attending some family events so I won't have time to work on this for the next while. Please continue working on it 😄

@cancerberoSgx
Copy link
Contributor Author

Nice thanks! BTW I also want to take this opportunity to learn about the inners of the library. I must say it was kind of intuitive once you point me how to workaround that mysterious build error :) Also I must say you are a very careful developer (compared to me) :P What do you think is missing in order to merge this work ? SHould I keep implementing getStructure for the rest of Node kinds ? As I said before I'm kind o fan urgency of having this feature and I woulnd't want to use my own branch... Please advice.

BTW I'm using the library to build TLS plugins for code fixes and refactors common in other typed languages / ides like Java/eclipse. See https://github.com/cancerberoSgx/typescript-plugins-of-mine/tree/master/typescript-plugin-proactive-code-fixes - there are some .gifs at the bottom. I bet you didn't imagine tsa being used like this. It saved me a lot of time although some of the refactors could take more than one second to apply ... Just experimenting and learning - let's see if I reach a production - ready product some day.

THanks!

@dsherret
Copy link
Owner

For it to be merged into master this would have to be complete. So for the definition of complete I would say:

  1. For every currently existing Structure interface there should exist a corresponding .getStructure() method on the node.
  2. For every .getStructure() there should exist a test that checks the return value. <-- we don't need to go over the top and test every combination, but rather just ensure things generally seem to be working (maybe ballpark 1-3 tests per .getStructure() method, but obviously use discretion in the scenario)

If you urgently need this feature, then I recommend publishing your fork to npm and using that package in what you need .getStructure() for.

RE the plugins: very cool! For performance, have you looked into why it's taking so long? Should be pretty quick if you're just looking at the AST and not any symbols or types, but yes, it could be a bit slow otherwise. By the way, see the performance tip I recently added here: https://dsherret.github.io/ts-simple-ast/manipulation/performance -- not sure if it would help though.

@cancerberoSgx
Copy link
Contributor Author

Re plugins performance, I'm creating a new project every time a refactor is applied. Probably this can be improved - but the most slow thing is typeChecker.getTypeAtPosition or type inferring in general - no matter if the project is reused or not. Sincerily didn't put much focus in performance right now but I will, thanks!

@dsherret dsherret merged commit 2d7351c into dsherret:dev Sep 15, 2018
@dsherret
Copy link
Owner

This is merged now, but will be released in v15. Thanks for the help @cancerberoSgx! This was so much work.

@dsherret
Copy link
Owner

Hey @cancerberoSgx, this is released now and seems to work well (in 15.0.1). The .fill method is deprecated now though. Use .set instead or the .addX methods.

dsherret added a commit that referenced this pull request May 14, 2019
BREAKING CHANGE: Change to jsx spread attribute structure.

Co-authored-by: Sebastián Gurin <sebastigurin@gmail.com>
Co-authored-by: David Sherret <dsherret@users.noreply.github.com>
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

Successfully merging this pull request may close these issues.

None yet

3 participants