-
Notifications
You must be signed in to change notification settings - Fork 204
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
@NaridaL refactor(utils): set tsconfig strict=true for utils package and fix errors #1679
Conversation
@@ -160,8 +159,8 @@ export function validateRedundantMethods( | |||
for (const prop in visitorInstance) { | |||
if ( | |||
isFunction(visitorInstance[prop]) && | |||
!contains(VALID_PROP_NAMES, prop) && | |||
!contains(ruleNames, prop) | |||
!VALID_PROP_NAMES.includes(prop) && |
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.
includes is not supported in IE11
and while I intend to drop support for legacy runtimes this has not been made official yet
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.
Yeah I guess I missed that, I looked for the engines field in the package.json.
As my other PRs had breaking changes too, we could drop IE11 support with 10? An alternative is to use the standardized functions such as .includes
etc but use a polyfill for IE11 instead of using custom function everywhere.
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.
This change also assumes the property is always a valid array, while contains (depending on how its implemented) could work on null/undefined values as well.
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'm fine with targeting more modern runtimes in version 10.0 and dropping IE11 support
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 will answer this in the root PR chat
I moved this to a discussion |
Moved to discussion #1681 |
Perhaps this PR contains too many topics, |
778bf05
to
17f6442
Compare
…rrors This also created some errors in other packages due to variables now being typed correctly. These errors were also fixed. This includes a non-type fix in errors_public.ts. Also removed packArray function entirely as it was broken. BREAKING CHANGE: packArray function was removed from utils
17f6442
to
37c63bd
Compare
They're kind of related because I just replaced some methods instead of trying to fix their types. But I've reset this PR to the first commit, let's get this merged first (y). I assume you also consider changes to @chevrotain/utils API as breaking? |
Nope, while its technically a public package, the important API is the one specified in the Feel free to break whatever you want in the |
packages/types/api.d.ts
Outdated
@@ -1246,7 +1246,7 @@ export interface ILexerConfig { | |||
* This can be useful when wishing to indicate lexer errors in another manner | |||
* than simply throwing an error (for example in an online playground). | |||
*/ | |||
deferDefinitionErrorsHandling?: boolean | |||
deferDefinitionErrorsHandling: boolean |
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 don't get it, why are these properties that are definitively optional, marked as none optional?
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.
Once the lexer is initialized, all the properties are set (by the user or defaults). Hence it makes sense to have all properties non-optional in the interface to prevent "can be undefined" errors anytime you access an option.
The parameter to the Lexer constructor is then changed to Partial so not all of them have to be explicitly passed.
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 like the idea in this approach, but it won't "scale" if there is ever any property that is not optional.
I suggest the complement approach, internally transforming the Interface using Required
and leaving the public API
with the "correct" typings and without requiring consumers to understand Mapped types in TypeScript
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.
Yeah, that's the way to go
packages/types/api.d.ts
Outdated
@@ -2300,6 +2300,7 @@ export interface IProduction { | |||
|
|||
export interface IProductionWithOccurrence extends IProduction { | |||
idx: number | |||
maxLookahead?: number |
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.
Not all IProductionWithOccurrence
can have maxLookahead
.
Only those that involve Lookahead logic, e.g OR / MANY / OPTION,
But a Terminal / Non-Terminal would not...
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.
hence why it is optional
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 packages/chevrotain/src/parse/grammar/checks.ts 532 currProd.maxLookahead
is accessed. currProd has type IProductionWithOccurrence, so it needs to have maxLookahead declared.
(It used to be IProduction, but currProd.idx is also accessed)
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.
This is a public API so it should be more strict.
I'd prefer to only add this maxLookahead
where it actually exists (e.g via an additional interface, or a property on each concrete type.
And if needed change/fix the internal code to deal with it, (even if in an ugly manner, e.g casting)
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.
If the AST nodes are public, then it stands to reason that users may also need the maxLookahead property? On an interface this doesn't really mean much except "IF a instance has this property, then it must be of type number"?
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.
If the AST nodes are public, then it stands to reason that users may also need the maxLookahead property?
To be honest, that is a great question which I did not fully consider.
Initially I was automatically in favor of exposing it.
But realistically I can't imagine any scenario in which a consumer would be interested in it.
The internal GAST is already for unique and advanced flows, e.g building your own syntax diagrams.
But would the maxLookAhead really matter for such scenarios? maybe it is just an implementation detail and should be removed from the public API.
unfortunately only now realized the PR targeted the @NaridaL I truly appreciate your time investment in improving the code quality of this project.
Perhaps a more incremental approach would be to enable a single sub-strict setting in the root ts.config
Maybe the long term approach to reach
|
I will close this PR, but will attempt to enable some sub-strict options on the root ts.config to at least stabilize the current status. |
@bd82 While I did only enable strict in the utils package, this revealed a lot of errors/problems outside the utils package. Hence why most of the improvments are actually to files outside the utils package. This PR should therefore still be merged, even if you intend to remove the utils package. |
I see, so we will need to do a few review iterations because I don't understand some of the fixes and some seem incorrect (api.d.ts). I will try to review it fully tomororw |
@@ -1086,7 +1088,7 @@ export function buildLineBreakIssueMessage( | |||
|
|||
function getCharCodes(charsOrCodes: (number | string)[]): number[] { | |||
const charCodes = map(charsOrCodes, (numOrString) => { | |||
if (isString(numOrString) && numOrString.length > 0) { |
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.
getCharCodes
is used on input from an end-user (the custom lineTerminatorCharacters
).
Until now if a user passed an empty string it would be ignored, now it would add NaN
to the result.
I don't know what effect this could have, and not sure I want to spend the time investigating.
Could we keep the extra length condition to ensure numOrString.charCodeAt(0)
will return a real number?
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 function as written before returned numbers or empty strings, which didn't match the function return signature. As far as I can see, none of the callers of getCharCodes seem to handle strings?
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.
Yeah good catch 👍 it seems like a bug, so maybe returning NaN is better (after your refactor)
@@ -186,7 +184,7 @@ export class Lexer { | |||
} | |||
}) | |||
|
|||
if (this.config.skipValidations === false) { |
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.
this === false
is a personal style, maybe I just don't see the !
mark well 😄
The problem in JavaScript this change actually introduces semantic difference because of automatic conversion to boolean.
- Note that due to the automatic conversions more operations are made, so in hotspots (e.g tokenize method) I make sure to compare to exactly the right value (true/false/null/undefined) for performance reasons.
The 2nd problem is that there are ~70 other places in the code that perform === true/false
so if we change style we should change it everywhere.
The 3rd problem is that we have enough topics in this PR already, lets avoid style questions as part of it.
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.
OK. To me this reads as if this was done for the explicit semantic difference. But as skipValidations can actually only be true or false here it is confusing.
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.
But as skipValidations can actually only be true or false here it is confusing.
That is a good point, skipValidations
is provided by an end user, and can be anything, because TypeScript
is a design time tool only which is not even used by all (most?) consumers.
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.
Well I'm assuming the passed values are valid according to TS definitions.
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.
That is a very strong assumption when it a value typed in by an end user :)
@@ -262,7 +260,8 @@ export class Lexer { | |||
this.charCodeToPatternIdxToConfig[currModName] = | |||
currAnalyzeResult.charCodeToPatternIdxToConfig | |||
|
|||
this.emptyGroups = merge( | |||
this.emptyGroups = Object.assign( |
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.
keep the merge
so it would be easy for me to replace with 3rd party library and
- otherwise I will likely miss this and won't replace when I introduce the new library
- or use the
assign
from the utils instead of re-introducing themerge
if its easier...
export function contains<T>(arr: T[], item): boolean { | ||
return find(arr, (currItem) => currItem === item) !== undefined ? true : false | ||
export function contains<T>(arr: T[], item: T): boolean { | ||
return arr.includes(item) |
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.
includes
is okay only because ES5.1 was deprecated earlier today...
There may also be the behavior difference if undefined is ever passed (the type system does not guarantee it would not 100%)
But I hope to delete this utils package completely, so it can be merged for now.
Okay I finished reviewing, see the in-lined comments. Things to note:
|
I have fixed your comments. If style questions are important, then they should probably be added to an eslint or similar to avoid discussions in PRs :-) |
I agree, The more people contribute to this repository (on regular basis) the more useful a linting tool becomes. However, I found that when I am the "main" contributor for a project I end up wasting more time dealing with false positives and ESLint configurations than true linting issues, which is why it is currently not used here. Generally speaking, when contributing to an open source project you often would simply align with the existing style in the project/file. and focus on the change you want to implement, and the fewer topics per PR (one is best) the better. |
I'm merging this and may do micro changes (e.g maxLookAhead) in a different commit |
Thanks @NaridaL 👍 |
This is the micro change I've done: |
and this will ensure strict===true in new sub-packages |
No description provided.