Conversation
…ED-982] `checkly debug parse-project` printed the synthesized payload without the per-resource `sourceFile` that a deploy sends, because it never passed the git repository root to `synthesize()`. It now resolves the root the same way `checkly deploy` does, so the debug output shows which file each resource is attributed to. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…RED-982] A construct copied `Session.checkFileAbsolutePath`, the check file the parser was loading, into `checkFileAbsolutePath`. A module a check file imports is evaluated during its first importer's load and then cached, so every construct in a shared alerts or groups module was attributed to that importer, and glob order decided which one. The deploy payload's `sourceFile`, `checkly test <file>` filtering, reporter grouping, relative entrypoints and `CheckGroupV1.testMatch` all read that path. The `Construct` constructor now reads the declaring file off the call stack: the frame below the construct's own constructor chain (counted from `new.target`, so a user subclass is skipped and a wrapper class counts as a helper) and outside the CLI's own code. When that frame is a tool under node_modules the parser's current file remains the answer, as before. The loading check file is kept alongside: relative file paths and `testMatch` globs resolve next to it first, as they always did, and next to the declaring file when nothing is there; `checkly test <file>` matches either. `Session.checkFilePath` is replaced by `Session.checkFilesDirectory` and `relativeCheckFilePath()`; `Check.__checkFilePath` derives from the construct's own path. `parseProject` and the config loader work on physical paths, since loaders report resolved imports that way. A `CheckGroupV1` declared in the config file with a matching `testMatch` used to crash on the missing base path; it now fails with the rule that checks cannot be declared there. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ED-982] A fixture project keeps an alert channel, a group, an API check, a browser check and a legacy group in modules no check glob matches, imported by two check files, next to a factory helper, a group helper and a subclass. The sandbox spec runs the packed CLI's `debug parse-project` on it and asserts every resource's `sourceFile`, where relative entrypoints and `testMatch` globs resolve, and that loading only the second check file gives the same attribution. The e2e `checkly test --list` cases cover selection by the declaring module, by the loading check file and by neither. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The posix frame fixtures were parsed with the platform's path module, so on Windows a drive-less file URL threw inside the helper and the frame was skipped. They now pin posix rules, as the win32 case pins its own. The expected physical paths came from the native realpath, which on Windows expands 8.3 short names while the loader and the parser use the JS realpath; the spec now uses the same one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…Windows [RED-982] jiti normalises the path it is asked to load to forward slashes, so on Windows the entry file's frame reads `C:/...` while the expectation is built with backslashes. Resolved imports keep native separators. The assertion now tolerates that one difference and nothing else. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
RED-982.
A construct was attributed to whichever check file the project parser was loading when the construct's module was first evaluated. The parser sets
Session.checkFileAbsolutePatharound eachSession.loadFile(checkFile), and theConstructconstructor copied it. That is right for a construct declared at the top of the check file being loaded, and wrong for everything else: a module a check file imports (a sharedalerts.ts, agroups.tsno glob matches) is evaluated during its first importer's load and then served from the module cache, so every construct in it was attributed to that importer, and which importer that was depended on glob order.Four things read that path and were wrong for such constructs:
sourceFilein the deploy payload (shown in the deploy preview and recorded by the backend),__checkFilePathon checks (checkly test <file>filtering,--listand reporter grouping),resolveContentFilePath(relativeentrypointand other file props resolved against the importer's directory), andCheckGroupV1'stestMatchglob root.How
constructs/internal/declaring-file.tsreads the call stack in theConstructconstructor (Error.prepareStackTracecall sites, restored right after). It skips the construct's own constructor chain (counted fromnew.target, so a subclass the user derives from a construct is skipped and a wrapper class is not), the CLI's own code (dist/in the package,src/from source) and Node internals, and takes the first remaining frame as the declaring file: the file that rannew, or the helper function that did so on a check file's behalf. When that frame sits undernode_modulesno user code created the construct (the CLI made it for abrowserChecksglob entry or a Playwright check, or a test runner did) and the parser's current file stays the answer, soSession.checkFileAbsolutePathremains as the fallback. Both jiti and Node's ESM loader report the original file, as a path or afile://URL; resolved imports come back at their physical location, the entry file as given.entrypoint(and the other relative file props) resolves next to that check file, as before, and next to the declaring file when it does not exist there, so a construct declared in a shared module can keep its script next to the module while a factory called from a check file keeps resolving paths from the check file.CheckGroupV1globstestMatchfrom the loading check file, as before, and from its declaring file when that finds nothing.checkly test <file>matches its file patterns against the declaring file and the check file that was being loaded (filterByCheckFilesintest-filters.ts), so naming a check file still selects everything loaded through it, as before, and naming a shared module now selects the checks declared there.--listand reporter grouping use the declaring file.Session.checkFilePathis gone;Session.checkFilesDirectory(the physical directory the project is parsed from) andSession.relativeCheckFilePath()replace it, andCheck.__checkFilePathis derived from the construct's own absolute path.parseProjectresolves its directory withfs.realpathfirst, so the base path, glob results and stack-derived paths agree even when the project is reached through a symlink.checkly debug parse-projectpasses the git repository root tosynthesize()likecheckly deploydoes, so its payload showssourceFile(first commit; the sandbox spec asserts on it).Other changes
CheckGroupV1declared incheckly.config.tswhosetestMatchmatched files crashed with aTypeErroron the missing base path before reaching the rule that checks cannot be declared in the config file. It now fails with that rule's message.Behaviour changes
sourceFile, the preview's file column and--listheadings name the declaring module for constructs in shared modules.checkly test <shared-module>selects the checks declared there. Naming a check file still selects the checks loaded through it (the first importer of a shared module, as before).checkly test --listand the reporters group a check made by a helper under the helper's file.entrypointon a check declared in a shared module resolves against that module's directory when it does not exist next to the importing check file.Session.checkFilePathno longer exists on theSessionclass exported fromcheckly/constructs; it had no documented use.Accepted
newis).testMatchor anentrypointis resolved or which filecheckly test <file>matches, so there is nothing to update.node_modules(not linked from workspace source) falls back to the parser's current file.debug parse-project --statsreports the parse step at about 90 ms after this change against about 65 ms before (roughly 12 µs per construct, subscriptions included; the warm figure over four runs).Verification
declaring-file.spec.tscovers the frame filter (constructor frames, posix,file://, Windows drive letters and URLs,node:frames,node_modulesfirst frame, empty stacks), the hook restoration, and a real capture through jiti from a temp directory: an imported module rather than its importer, a subclass instantiated from the entry file, a factory function, a wrapper class.project-parser-source-file.spec.tsruns the packed CLI'sdebug parse-projectagainst a fixture with an alert channel, a group, an API check and a browser check in modules the check glob does not match, imported by two check files, plus a factory-made browser check with a relative entrypoint, a helper-madeCheckGroupV1with atestMatch, a shared-moduleCheckGroupV1whosetestMatchmatches only next to the module, and a subclass: every construct reports its declaring module, relative paths resolve next to the loading check file first and the declaring module second, and loading with a config that matches only the second check file gives the same attribution.checkly-config-loader.spec.ts: a config-declaredCheckGroupV1with a matchingtestMatchfails with the config-file rule's message.test.spec.ts:checkly test --list shared/checkslists the shared check undersrc/shared/checks.ts;--list factory.checklists the helper-made check;--list b.checkincludes the shared checks it loads;--list a.checkdoes not.test-filters.spec.tspins the selection rule offline.Session.relativeCheckFilePath,Check.__checkFilePath(fallback path and config-file case) and the physical parse directory.🤖 Generated with Claude Code