feat: typescript version#209
Conversation
|
@pimterry - this is a potential version converted to typescript, mostly as a stalking horse to talk about to see if we can figure out the right changes for a v2 release. |
Ryuno-Ki
left a comment
There was a problem hiding this comment.
I highlighted some areas where the spaces appear to be out of order.
Replacing vars can be a chore taken care of in another PR.
| pull_request: {} | ||
| push: | ||
| branches: | ||
| - main |
There was a problem hiding this comment.
Removing this would make it run for pushes to any branch.
| *.gz | ||
| *.tgz | ||
| *.code-workspace | ||
| package-lock.json |
There was a problem hiding this comment.
This file should be tracked in version control.
| *.tgz | ||
| *.code-workspace | ||
| package-lock.json | ||
| bun.lock |
There was a problem hiding this comment.
This file should be tracked in version control.
| var isIE = (typeof window !== undefinedType) && (typeof window.navigator !== undefinedType) && ( | ||
| /Trident\/|MSIE /.test(window.navigator.userAgent) | ||
| ); | ||
| const noop = function() {}; |
There was a problem hiding this comment.
If you want to be consistent:
| const noop = function() {}; | |
| const noop = function () {}; |
| function realMethod(methodName) { | ||
| if (methodName === 'debug') { | ||
| methodName = 'log'; | ||
| function defaultMethodFactory(methodName, _level, _loggerName) { |
There was a problem hiding this comment.
| function defaultMethodFactory(methodName, _level, _loggerName) { | |
| function defaultMethodFactory (methodName, _level, _loggerName) { |
| * in sync with the actual logging methods that we have installed (the | ||
| * parent could change levels but we might not have rebuilt the loggers | ||
| * in this child yet). | ||
| * @type {number} |
There was a problem hiding this comment.
Doesn't this conflict with the initialisation?
| * @type {number} | |
| * @type {number|null} |
|
|
||
| self.setDefaultLevel = function (level) { | ||
| defaultLevel = normalizeLevel(level); | ||
| if (getPersistedLevel()===undefined) { |
There was a problem hiding this comment.
Nitpick:
| if (getPersistedLevel()===undefined) { | |
| if (getPersistedLevel() === undefined) { |
| self.rebuild = function () { | ||
| inheritedLevel = null; | ||
| const result = replaceLoggingMethods.call(self); | ||
| if( self.methodFactory && self.methodFactory===(factory || defaultMethodFactory)) { |
There was a problem hiding this comment.
| if( self.methodFactory && self.methodFactory===(factory || defaultMethodFactory)) { | |
| if (self.methodFactory && self.methodFactory === (factory || defaultMethodFactory)) { |
| window.console = mockConsole(); | ||
| log.trace("trace"); | ||
| it("silent method calls are allowed", function() { | ||
| var result = log.setLevel(log.levels.SILENT); |
There was a problem hiding this comment.
Maybe worth to replace the vars here, too.
| }); | ||
|
|
||
| it("child loggers inherit parent", function(log) { | ||
| log.setLevel(0); |
There was a problem hiding this comment.
Hm. This appears to be an implementation detail.
The lib/loglevel.js file is now a generated file for compatibility - if v2 doesn't need that level of compatibility, then the ts can be the primary version and we can avoid generating a lib/loglevel.js Alterantively, we could leave lib/loglevel.ts as the primary typescript version, and add a compatible version in dist, and change the exports in package.json. |
|
Ah, so that's what you meant with TS! I was confused as I haven't seen any changes to TS files. |
|
I'm very open to migrating to TS! Fully agree that would be good. It should happen on the V2 branch though, we're not migrating v1 to TS - it's frozen and there's risk for little benefit. This PR currently targets the main branch and seems to include all the other V2 changes here as well, which makes it hard to review. Can you update it to target |
|
@wayfarer3130 sorry I’ve been so absent when I thought I’d have time to work on this. Glad someone’s taking it on. Did you maybe push the wrong commit to your PR branch? This PR appears to be the exact same as the current |
I must have pushed it wrong somehow as it doesn't seem to have the changes I had locally. I will push that on Monday when I'm back on the computer I was working on. |
| // Build the best logging method possible for this env | ||
| // Wherever possible we want to bind, not wrap, to preserve stack traces | ||
| function defaultMethodFactory(methodName, _level, _loggerName) { | ||
| /*! loglevel - https://github.com/pimterry/loglevel - licensed MIT */ |
There was a problem hiding this comment.
I'm not sure whether the comment can be changed into this form legally. Would it be possible to preserve the previous version?
Ryuno-Ki
left a comment
There was a problem hiding this comment.
Looks like it's on a good path. I feel like the typings could be more rigour.
|
|
||
| function defaultMethodFactory(methodName: LogMethodName): LoggingMethod { | ||
| if (typeof console !== undefinedType) { | ||
| const anyConsole = console as any; |
| /*jshint validthis:true */ | ||
| const level = this.getLevel(); | ||
|
|
||
| for (let i = 0; i < logMethods.length; i++) { |
There was a problem hiding this comment.
My hunch is that a for…of loop is perhaps the right way?
There was a problem hiding this comment.
Or perhaps even a logMethods.forEach((method, index) => {…})?
|
|
||
| for (let i = 0; i < logMethods.length; i++) { | ||
| const methodName = logMethods[i]; | ||
| this[methodName] = i < level ? noop : this.methodFactory(methodName, level, this.name); |
There was a problem hiding this comment.
The i should maybe be casted here. It feels kind of confusing that level is an integer in this line. (It makes me think which I interpret as a smell)
| } | ||
| } | ||
|
|
||
| function Logger(this: any, name?: LoggerName, factory?: MethodFactory, parent?: any) { |
| function Logger(this: any, name?: LoggerName, factory?: MethodFactory, parent?: any) { | ||
| const self = this; | ||
|
|
||
| // Private instance variables: |
|
|
||
| const loggers: any = {}; | ||
|
|
||
| function persistLevelIfPossible(levelNum: number): void { |
There was a problem hiding this comment.
Might make sense to define a type for Indices like this:
// Source - https://stackoverflow.com/a/63904714
// Posted by bela53
// Retrieved 2026-02-04, License - CC BY-SA 4.0
type Indices<T extends readonly any[]> = Exclude<Partial<T>["length"], T["length"]>Would then be
| function persistLevelIfPossible(levelNum: number): void { | |
| function persistLevelIfPossible(levelNum: Indices<typeof LogMethodName[]>): void { |
if I read it correctly.
| if (typeof window === undefinedType || !storageKey) return; | ||
|
|
||
| try { | ||
| (window as any).localStorage[storageKey] = levelName; |
There was a problem hiding this comment.
Is casting window really necessary here?
You check for typeof window above. Maybe there should be a general check for browser context before handling finer levels.
|
|
||
| function getPersistedLevel(): string | void { | ||
| let storedLevel: any; | ||
| if (typeof window === undefinedType || !storageKey) return; |
There was a problem hiding this comment.
This starts to ask for a refactoring that handles the question of browser vs. server context generally.
| "test-types": "tsc --noEmit ./test/type-test.ts && ts-node ./test/type-test.ts", | ||
| "dist": "grunt dist", | ||
| "dist-build": "grunt dist-build", | ||
| "test-types": "tsc --noEmit ./test/type-test.ts && ts-node --compilerOptions \"{\\\"module\\\":\\\"CommonJS\\\"}\" ./test/type-test.ts", |
There was a problem hiding this comment.
Do we really have to have this level of escaping?
| "test-types": "tsc --noEmit ./test/type-test.ts && ts-node --compilerOptions \"{\\\"module\\\":\\\"CommonJS\\\"}\" ./test/type-test.ts", | |
| "test-types": "tsc --noEmit ./test/type-test.ts && ts-node --compilerOptions '{\"module\":\"CommonJS\"}' ./test/type-test.ts", |
feels more appropriate to me.
| import typescript from "@rollup/plugin-typescript"; | ||
| import terser from "@rollup/plugin-terser"; | ||
|
|
||
| const banner = `/*! loglevel - https://github.com/pimterry/loglevel - licensed MIT */`; |
There was a problem hiding this comment.
See my comment above on the shape of the banner.
This is a potential version for typescript - the api is compatible, but I haven't used much extra in terms of the typescript versioning of any ability to over-ride a class instance.
Note the lib/loglevel.js javascript version is GENERATED now from src/loglevel.ts. That is one of the things to discuss about what level of backwards compatibility this should have and how much new features should be taken advantage of.
Please provide comments about overall goals for a v2 - we can discuss the nitpicky details once we have the high level agreement on the general pattern.