-
Notifications
You must be signed in to change notification settings - Fork 21
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
Typescript conversion #32
Conversation
Added types for babylon
Converted more to Typescript Some more conversions
Hmmm, looks like I need to fix the linting... |
Ah looks like the version of node on the CI server is too low to run one of the new dependencies. Can we bump the version? |
while I like typescript a lot personally, I am not the only contributor in this repo, @stephtr @seanpoulter, are you guys ok to move the repo to typescript? |
Personally, I definitely prefer working with TypeScript. It would also better fit to |
.eslintrc.js
Outdated
extends: ['airbnb-base', 'plugin:flowtype/recommended', 'prettier', 'plugin:prettier/recommended'], | ||
extends: [ | ||
'airbnb-typescript/base', | ||
"airbnb/hooks", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we should use quotes consistently 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My choice would have been for double quotes, but I tried to stick with the Prettier rules that were already present.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was just refering to some extends
strings being single- and some being doublequoted. I would prefer enforcing consistent quotes for the whole project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah my bad. Was reading that comment on mobile. Not sure why I've got a mixture there. Will fix.
@@ -1,4 +1,4 @@ | |||
// @flow | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do some files start with an empty line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thats a good question. It took me ages to figure out why some unit tests were failing. Turns out the line numbers are hard-coded in them and I was trying to change the minimal amount of code, so that this PR was readable.
So I didn't update the tests with new line numbers.
fixtures/parser_tests.ts
Outdated
const fixtures = __dirname; | ||
|
||
function parserTests(parse: (file: string) => ParserResult) { | ||
function parserTests(parse: (file: string, data?: string | undefined) => ParseResult) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ?
already contains undefined
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't have time to go through all changes, but these are my comments for some of them.
fixtures/parser_tests.ts
Outdated
name: string | null = null, | ||
) => assertBlock(block, {column: sc, line: sl}, {column: ec, line: el}, name); | ||
const assertBlock = (block, start, end, name: ?string = null) => { | ||
const assertBlock = (block, start, end, name: string | null = null) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could change this to just name?: string
.
fixtures/parser_tests.ts
Outdated
|
||
// check test blocks, including the template literal | ||
const found = descBlock.children.filter( | ||
const found = descBlock?.children?.map(b => b as ItBlock)?.filter( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion we don't need a ?.
after map
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
How did you add these @rossknudsen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@seanpoulter if you mean this specific piece of code, it now looks like this:
// check test blocks, including the template literal
const found = descBlock.children
.map(b => b as NamedBlock)
.filter(
b =>
b.name === 'needs to have a PR number' ||
b.name === 'does not validate without josh' ||
b.name === 'does not validate when ${key} is missing'
);
expect(found.length).toBe(3);
I was just trying to assert that the type of the array elements were NamedBlock
s (originally ItBlock
s). There is potentially another way to write this which is arguably more elegant. Now that the children
property is not potentially null, it is a lot clearer.
If you are talking more generally, you might need to give me some more context.
fixtures/parser_tests.ts
Outdated
export { | ||
parserTests, | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use export function parserTests
?
fixtures/parser_tests.ts
Outdated
@@ -184,24 +186,24 @@ function parserTests(parse: (file: string) => ParserResult) { | |||
it('finds test blocks within describe blocks', () => { | |||
const data = parse(`${fixtures}/dangerjs/travis-ci.example`); | |||
const descBlock = data.describeBlocks[1]; | |||
expect(descBlock.children.length).toBe(4); | |||
expect(descBlock.children?.length).toBe(4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can children
really be not an (empty) array? I'm just wondering about the change between old and new code.
src/Runner.ts
Outdated
import ProjectWorkspace from './project_workspace'; | ||
import {createProcess} from './Process'; | ||
|
||
// This class represents the running process, and | ||
// passes out events when it understands what data is being | ||
// pass sent out of the process | ||
export default class Runner extends EventEmitter { | ||
debugprocess: ChildProcess; | ||
debugprocess: ChildProcess | null = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about debugprocess?: ChildProcess;
?
src/__tests__/process.test.ts
Outdated
@@ -30,24 +29,24 @@ describe('createProcess', () => { | |||
const args = []; | |||
createProcess(workspace, args); | |||
|
|||
expect(spawn.mock.calls[0][0]).toBe('jest'); | |||
expect(spawn.mock.calls[0][1]).toEqual([]); | |||
expect((spawn as any).mock.calls[0][0]).toBe('jest'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One could also use the as Mock<any>
type from Jest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, slightly more type-safe. Any ideas on replacing the any
part of the type with something more specific?
src/parsers/parser_nodes.ts
Outdated
|
||
export class ParsedNode { | ||
type: ParsedNodeType; | ||
|
||
start: Location; | ||
start: Location | undefined = undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On such occasions start?: Location;
would be sufficient.
src/parsers/parser_nodes.ts
Outdated
@@ -1,14 +1,15 @@ | |||
/* eslint-disable @typescript-eslint/no-use-before-define */ | |||
/* eslint-disable max-classes-per-file */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion we could also get rid of the max-classes-per-file
policy project-wide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
What is your opinion of placement of the copyright notice vs linting configuration? I had just left it where the intellisense put it, at the very top.
export const ParsedNodeTypes: { | ||
describe: 'describe'; | ||
expect: 'expect'; | ||
it: 'it'; | ||
root: 'root'; | ||
} = { | ||
describe: 'describe', | ||
expect: 'expect', | ||
it: 'it', | ||
root: 'root', | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has to be tested, but this could be replaced by either an enum or export type ParsedNodeTypes = 'describe' | 'expect' | ...
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. I was tempted to rewrite some of the parser code relying on TS more, but I see that #30 is already rewriting the parser code. It would probably make more sense to merge those changes first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually having read that PR, I'm inclined to wait until it is merged because it will remove the typescript parser. That reduces the delta in this PR.
src/parsers/parser_nodes.ts
Outdated
|
||
file: string; | ||
|
||
children: ?Array<ParsedNode>; | ||
children?: Array<ParsedNode>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ParsedNode[]
is easier to read than Array<...>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Pretty sure this is a Prettier/ESLint rule.
Fixed bug introduced in previous commit that broke tests.
0e61a26
to
2ac03d3
Compare
Huh, somehow the coverage dropped... |
Fair enough, I was going by this comment which is probably old/stale now. I ran across the comment because I wanted to access more of the Jest settings. I guess I went down a bit of a rabbit hole with this one... |
Thanks for the huge effort @rossknudsen! 👏 --
Yes, you can substitute npm packages using "linking". Here's the docs for --
I've got two answers for this: one with best interest of the project in mind, and the other from my own perspective.
[1]: https://2019.stateofjs.com/javascript-flavors/typescript/ |
Co-Authored-By: Sean Poulter <[email protected]>
let line = null; | ||
let short: string | undefined; | ||
let terse: string | undefined; | ||
let line: number | undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change from null
to undefined
stands out to me as a potentially risky API change. The risk is that a caller uses all three types from the Flow Maybe type (type | null | void (undefined)
) to differentiate between values that aren't in the map/object, are invalid, or are a valid number. It makes me worry that I'd/we'd have to do a more thorough code review or testing.
In this particular case, the caller seems fine but there's still the rough edge of how we're using this.lineOfError(...) || undefined
to do ... something. What would ever be falsy enough to end up as undefined
?! I actually had to run this in the Dev Tools console just to check the falsy precedence:
I guess I learned (or relearned) that.
- line = this.lineOfError(message, filename) || undefined;
+ line = this.lineOfError(message, filename);
with lineOfError
returning undefined
. I'm not a fan of the magic numbers like [1]
in there so I'd hope to see something like:
- lineOfError(message: string, filePath: string): number | null {
- const filename = path.basename(filePath);
- const restOfTrace = message.split(filename, 2)[1];
- return restOfTrace ? parseInt(restOfTrace.split(':')[1], 10) : null;
- }
+ lineOfError(message: string, filepath: string): ?number {
+ const filename = path.basename(filepath);
+ const [_msgIncludingFilename, msgAfterFilename] = message.split(filename, 2);
+ if (! msgAfterFilename) return;
+ const [_colon, lineNumber] = msgAfterFilename(':');
+ return parseInt(lineNumber, 10);
+ }
--
The underlying question for the folks reviewing is are we OK with migrating and refactoring at the same time. Here's the docs for the Flow Maybe type.
@seanpoulter I appreciate the time taken to write your thoughts regarding this PR. I reviewed the changed files again and it is substantial. My original intent was to avoid a massive delta as it has potential to introduce regressions etc and part of the reason why people wouldn't want to convert in the first place. Also 100% appreciate your limited time in reviewing this. In light of all this, I stepped back and thought about whether its possible to take an incremental approach to conversion. So I looked at the recommendations for conversion from Microsoft and cherry-picked some changes from this branch into a new branch. If you like this approach I can open another PR for review. I think I've kept everything operational while converting just one file to Typescript. |
I like that! 👍 |
superseded by #33 |
This is a conversion to Typescript, removing Flow and updating build scripts.
Unit tests should be passing, but I need to manually test. Maybe we can get a pre-release, or is there another simple way to substitute an npm package in my extension?