fix(function): support multiline import type statements in import scanning#4872
Conversation
…nning
The regex pattern `.*?` does not match newlines, causing multiline
`import type { X }` statements to be skipped during bind-mount file
scanning. This results in type-only imports not being mounted in
the Docker container, causing runtime errors like:
worker boot error: Module not found "file:///.../types/MyType.ts"
Changed `.*?` to `[\s\S]*?` to match any character including newlines,
consistent with the `{[^{}]+}` pattern used for braced imports.
This fix enables proper handling of Deno 2.x style multiline type imports:
```typescript
import type {
MyType,
OtherType,
} from './types.ts'
```
Includes test case to prevent regression.
Cover `import type Foo from '...'` pattern in the multiline import type test. This form also routes through the `[\s\S]*?` branch and was previously untested.
|
No actionable comments were generated in the recent review. 🎉 📝 WalkthroughSummary by CodeRabbit
WalkthroughThe pull request updates import path parsing for Deno modules to handle multiline import type statements. A regex pattern in Comment |
Pull Request Test Coverage Report for Build 22164832869Details
💛 - Coveralls |
|
Would be great to get some eyes on this one! |
| // Ref: https://regex101.com/r/DfBdJA/1 | ||
| var importPathPattern = regexp.MustCompile(`(?i)(?:import|export)\s+(?:{[^{}]+}|.*?)\s*(?:from)?\s*['"](.*?)['"]|import\(\s*['"](.*?)['"]\)`) | ||
| // Note: Using [\s\S]*? instead of .*? to match newlines in multiline import type statements | ||
| var importPathPattern = regexp.MustCompile(`(?i)(?:import|export)\s+(?:{[^{}]+}|[\s\S]*?)\s*(?:from)?\s*['"](.*?)['"]|import\(\s*['"](.*?)['"]\)`) |
There was a problem hiding this comment.
Hey, thanks for tracking this down! The [\s\S]*? change works, but I'm a little hesitant to widen the catch-all branch to match across newlines for everything — even with the lazy quantifier it feels like a broader change than what we need here.
The root issue is that import type { ... } doesn't hit the braced branch because type sits between the whitespace and {. What if we handled that more explicitly instead?
(?:import|export)\s+(?:type\s+)?(?:{[^{}]+}|.*?)\s*(?:from)?\s*['"](.*?)['"]
Adding (?:type\s+)? lets import type { Foo, Bar } fall into the {[^{}]+} branch, which already crosses line boundaries fine. That way .*? stays single-line and we're only changing the behavior for actual type imports rather than everything.
Happy to be wrong if there's a case I'm missing though do you have a test that the (?:type\s+)? approach wouldn't cover?
Fixes regex pattern in
importPathPatternso that multilineimport type { ... }andexport type { ... }statements are correctly matched during bind-mount file scanning. Without this fix, type-only imports split across multiple lines are silently skipped, causing runtime errors in Deno edge functions.What kind of change does this PR introduce?
Bug fix — corrects the import-path regex to handle multiline type imports.
What is the current behavior?
The
importPathPatternregex inpkg/function/deno.gouses.*?in the non-braced import branch. Since.does not match newline characters in Go'sregexppackage, multilineimport typestatements like:are not matched. The referenced module is never bind-mounted into the Docker container, producing a runtime error:
This occurs whenever a code formatter (e.g.,
deno fmt, Prettier) breaks a longimport typestatement across multiple lines.What is the new behavior?
The regex replaces
.*?with[\s\S]*?, which matches any character including newlines. This is consistent with the{[^{}]+}pattern already used for braced imports elsewhere in the same regex.Before:
(?:import|export)\s+(?:{[^{}]+}|.*?)\s*(?:from)?\s*['"](.*?)['"]After:
(?:import|export)\s+(?:{[^{}]+}|[\s\S]*?)\s*(?:from)?\s*['"](.*?)['"]All existing single-line imports continue to work. Multiline
import typeandexport typestatements are now correctly resolved.Files changed (4):
pkg/function/deno.go— regex fix (.*?→[\s\S]*?) + explanatory commentpkg/function/deno_test.go— new test case:iterates multiline import type statementspkg/function/testdata/modules/import_types.ts— test fixture with multiline import/export type patternspkg/function/testdata/types/database.ts— test fixture target moduleAdditional context
Why
{[^{}]+}doesn't coverimport typestatementsThe regex alternation
(?:{[^{}]+}|[\s\S]*?)is evaluated after(?:import|export)\s+. Forimport type { ... }, thetypekeyword sits between\s+and the opening brace, so the position after matching the whitespace ist— not{. The{[^{}]+}branch fails immediately and the engine falls through to[\s\S]*?.This means all
import typeforms — braced or not, single-line or multiline — are handled by the second branch. The old.*?worked for single-line cases because it could lazily expand across the entire line, but broke on multiline statements because.does not match\nin Go regex. The[\s\S]*?replacement matches any character including newlines, allowing the lazy expansion to cross line boundaries and reachfrom '...'.Why
[\s\S]*?instead of the(?s)flag?Go's
regexpsupports(?s)to make.match newlines, but applying it globally would change every.in the pattern — including the(.*?)capture groups for the import path, which should remain single-line.[\s\S]*?is a targeted fix that only affects the specifier-matching branch.Not a regression — an original limitation
The
importPathPatternregex was introduced in commit4b0b2b1d(Feb 2025, "support deploying functions without docker") with.*?from the start. Multiline type imports were never supported. The bug surfaces whenever a code formatter breaks a longimport typeorexport typestatement across lines — a common occurrence with auto-generated types or projects using default line-width limits.