Skip to content

Commit

Permalink
Circular imports error catching
Browse files Browse the repository at this point in the history
  • Loading branch information
breck7 committed Jan 25, 2025
1 parent b60bd66 commit 958e131
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 13 deletions.
19 changes: 19 additions & 0 deletions fusion/Fusion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,25 @@ This is my content
equal(result.footers[0], "The end.")
}

testParticles.circularImports = async equal => {
const files = {
"/a.scroll": "b.scroll",
"/b.scroll": "a.scroll",
"/c.scroll": "c.scroll",
"/d.scroll": "e.scroll\nf.scroll",
"/e.scroll": "f.scroll",
"/f.scroll": "g.scroll",
"/g.scroll": ""
}
const tfs = new Fusion(files)
const result = await tfs.fuseFile("/a.scroll")
equal(result.fused.includes("Circular import detected"), true, "Should have detected circularImports")
const result2 = await tfs.fuseFile("/c.scroll")
equal(result2.fused.includes("Circular import detected"), true, "Should have detected circularImports")
const result3 = await tfs.fuseFile("/d.scroll")
equal(result3.fused.includes("Circular import detected"), false, "No circularImports detected")
}

testParticles.quickImports = async equal => {
// Arrange/Act/Assert
const files = {
Expand Down
24 changes: 21 additions & 3 deletions fusion/Fusion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ interface FusedFile {
parser?: particlesTypes.particle
filepathsWithParserDefinitions: string[]
exists: boolean
circularImportError?: boolean
}

interface Storage {
Expand Down Expand Up @@ -405,7 +406,7 @@ class Fusion implements Storage {
return _particleCache[absoluteFilePathOrUrl]
}

private async _fuseFile(absoluteFilePathOrUrl: string): Promise<FusedFile> {
private async _fuseFile(absoluteFilePathOrUrl: string, importStack: string[] = []): Promise<FusedFile> {
const { _expandedImportCache } = this
if (_expandedImportCache[absoluteFilePathOrUrl]) return _expandedImportCache[absoluteFilePathOrUrl]

Expand Down Expand Up @@ -451,8 +452,19 @@ class Fusion implements Storage {
if (isUrl(rawPath)) absoluteImportFilePath = rawPath
else if (isUrl(folder)) absoluteImportFilePath = folder + "/" + rawPath

if (importStack.includes(absoluteFilePathOrUrl)) {
const circularImportError = `Circular import detected: ${[...importStack, absoluteFilePathOrUrl].join(" -> ")}`
return {
expandedFile: circularImportError,
exists: true,
absoluteImportFilePath,
importParticle,
circularImportError
}
}

// todo: race conditions
const [expandedFile, exists] = await Promise.all([this._fuseFile(absoluteImportFilePath), this.exists(absoluteImportFilePath)])
const [expandedFile, exists] = await Promise.all([this._fuseFile(absoluteImportFilePath, [...importStack, absoluteFilePathOrUrl]), this.exists(absoluteImportFilePath)])
return {
expandedFile,
exists,
Expand All @@ -466,13 +478,18 @@ class Fusion implements Storage {
// Assemble all imports
let importFilePaths: string[] = []
let footers: string[] = []
let hasCircularImportError = false
imported.forEach(importResults => {
const { importParticle, absoluteImportFilePath, expandedFile, exists } = importResults
const { importParticle, absoluteImportFilePath, expandedFile, exists, circularImportError } = importResults
importFilePaths.push(absoluteImportFilePath)
importFilePaths = importFilePaths.concat(expandedFile.importFilePaths)

importParticle.setLine("imported " + absoluteImportFilePath)
importParticle.set("exists", `${exists}`)
if (circularImportError) {
hasCircularImportError = true
importParticle.set("circularImportError", circularImportError)
}

footers = footers.concat(expandedFile.footers)
if (importParticle.has("footer")) footers.push(expandedFile.fused)
Expand All @@ -488,6 +505,7 @@ class Fusion implements Storage {
isImportOnly,
fused: particle.toString(),
footers,
circularImportError: hasCircularImportError,
exists: allImportsExist,
filepathsWithParserDefinitions: (
await Promise.all(
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "scrollsdk",
"version": "100.2.0",
"version": "100.3.0",
"description": "This npm package includes the Particles class, the Parsers compiler-compiler, a Parsers IDE, and more, all implemented in Particles, Parsers, and TypeScript.",
"types": "./built/scrollsdk.node.d.ts",
"main": "./products/Particle.js",
Expand Down
2 changes: 1 addition & 1 deletion particle/Particle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3119,7 +3119,7 @@ class Particle extends AbstractParticle {
return str ? indent + str.replace(/\n/g, indent) : ""
}

static getVersion = () => "100.2.0"
static getVersion = () => "100.3.0"

static fromDisk(path: string): Particle {
const format = this._getFileFormat(path)
Expand Down
22 changes: 19 additions & 3 deletions products/Fusion.browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ class Fusion {
}
return _particleCache[absoluteFilePathOrUrl]
}
async _fuseFile(absoluteFilePathOrUrl) {
async _fuseFile(absoluteFilePathOrUrl, importStack = []) {
const { _expandedImportCache } = this
if (_expandedImportCache[absoluteFilePathOrUrl]) return _expandedImportCache[absoluteFilePathOrUrl]
const [code, exists] = await Promise.all([this.read(absoluteFilePathOrUrl), this.exists(absoluteFilePathOrUrl)])
Expand Down Expand Up @@ -355,8 +355,18 @@ class Fusion {
let absoluteImportFilePath = this.join(folder, rawPath)
if (isUrl(rawPath)) absoluteImportFilePath = rawPath
else if (isUrl(folder)) absoluteImportFilePath = folder + "/" + rawPath
if (importStack.includes(absoluteFilePathOrUrl)) {
const circularImportError = `Circular import detected: ${[...importStack, absoluteFilePathOrUrl].join(" -> ")}`
return {
expandedFile: circularImportError,
exists: true,
absoluteImportFilePath,
importParticle,
circularImportError
}
}
// todo: race conditions
const [expandedFile, exists] = await Promise.all([this._fuseFile(absoluteImportFilePath), this.exists(absoluteImportFilePath)])
const [expandedFile, exists] = await Promise.all([this._fuseFile(absoluteImportFilePath, [...importStack, absoluteFilePathOrUrl]), this.exists(absoluteImportFilePath)])
return {
expandedFile,
exists,
Expand All @@ -368,12 +378,17 @@ class Fusion {
// Assemble all imports
let importFilePaths = []
let footers = []
let hasCircularImportError = false
imported.forEach(importResults => {
const { importParticle, absoluteImportFilePath, expandedFile, exists } = importResults
const { importParticle, absoluteImportFilePath, expandedFile, exists, circularImportError } = importResults
importFilePaths.push(absoluteImportFilePath)
importFilePaths = importFilePaths.concat(expandedFile.importFilePaths)
importParticle.setLine("imported " + absoluteImportFilePath)
importParticle.set("exists", `${exists}`)
if (circularImportError) {
hasCircularImportError = true
importParticle.set("circularImportError", circularImportError)
}
footers = footers.concat(expandedFile.footers)
if (importParticle.has("footer")) footers.push(expandedFile.fused)
else importParticle.insertLinesAfter(expandedFile.fused)
Expand All @@ -385,6 +400,7 @@ class Fusion {
isImportOnly,
fused: particle.toString(),
footers,
circularImportError: hasCircularImportError,
exists: allImportsExist,
filepathsWithParserDefinitions: (
await Promise.all(
Expand Down
22 changes: 19 additions & 3 deletions products/Fusion.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ class Fusion {
}
return _particleCache[absoluteFilePathOrUrl]
}
async _fuseFile(absoluteFilePathOrUrl) {
async _fuseFile(absoluteFilePathOrUrl, importStack = []) {
const { _expandedImportCache } = this
if (_expandedImportCache[absoluteFilePathOrUrl]) return _expandedImportCache[absoluteFilePathOrUrl]
const [code, exists] = await Promise.all([this.read(absoluteFilePathOrUrl), this.exists(absoluteFilePathOrUrl)])
Expand Down Expand Up @@ -363,8 +363,18 @@ class Fusion {
let absoluteImportFilePath = this.join(folder, rawPath)
if (isUrl(rawPath)) absoluteImportFilePath = rawPath
else if (isUrl(folder)) absoluteImportFilePath = folder + "/" + rawPath
if (importStack.includes(absoluteFilePathOrUrl)) {
const circularImportError = `Circular import detected: ${[...importStack, absoluteFilePathOrUrl].join(" -> ")}`
return {
expandedFile: circularImportError,
exists: true,
absoluteImportFilePath,
importParticle,
circularImportError
}
}
// todo: race conditions
const [expandedFile, exists] = await Promise.all([this._fuseFile(absoluteImportFilePath), this.exists(absoluteImportFilePath)])
const [expandedFile, exists] = await Promise.all([this._fuseFile(absoluteImportFilePath, [...importStack, absoluteFilePathOrUrl]), this.exists(absoluteImportFilePath)])
return {
expandedFile,
exists,
Expand All @@ -376,12 +386,17 @@ class Fusion {
// Assemble all imports
let importFilePaths = []
let footers = []
let hasCircularImportError = false
imported.forEach(importResults => {
const { importParticle, absoluteImportFilePath, expandedFile, exists } = importResults
const { importParticle, absoluteImportFilePath, expandedFile, exists, circularImportError } = importResults
importFilePaths.push(absoluteImportFilePath)
importFilePaths = importFilePaths.concat(expandedFile.importFilePaths)
importParticle.setLine("imported " + absoluteImportFilePath)
importParticle.set("exists", `${exists}`)
if (circularImportError) {
hasCircularImportError = true
importParticle.set("circularImportError", circularImportError)
}
footers = footers.concat(expandedFile.footers)
if (importParticle.has("footer")) footers.push(expandedFile.fused)
else importParticle.insertLinesAfter(expandedFile.fused)
Expand All @@ -393,6 +408,7 @@ class Fusion {
isImportOnly,
fused: particle.toString(),
footers,
circularImportError: hasCircularImportError,
exists: allImportsExist,
filepathsWithParserDefinitions: (
await Promise.all(
Expand Down
2 changes: 1 addition & 1 deletion products/Particle.browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2622,7 +2622,7 @@ Particle.iris = `sepal_length,sepal_width,petal_length,petal_width,species
4.9,2.5,4.5,1.7,virginica
5.1,3.5,1.4,0.2,setosa
5,3.4,1.5,0.2,setosa`
Particle.getVersion = () => "100.2.0"
Particle.getVersion = () => "100.3.0"
class AbstractExtendibleParticle extends Particle {
_getFromExtended(cuePath) {
const hit = this._getParticleFromExtended(cuePath)
Expand Down
2 changes: 1 addition & 1 deletion products/Particle.js
Original file line number Diff line number Diff line change
Expand Up @@ -2612,7 +2612,7 @@ Particle.iris = `sepal_length,sepal_width,petal_length,petal_width,species
4.9,2.5,4.5,1.7,virginica
5.1,3.5,1.4,0.2,setosa
5,3.4,1.5,0.2,setosa`
Particle.getVersion = () => "100.2.0"
Particle.getVersion = () => "100.3.0"
class AbstractExtendibleParticle extends Particle {
_getFromExtended(cuePath) {
const hit = this._getParticleFromExtended(cuePath)
Expand Down
3 changes: 3 additions & 0 deletions releaseNotes.scroll
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ node_modules/scroll-cli/microlangs/changes.parsers

thinColumns 4

📦 100.3.0 2025-01-24
🏥 catch circular import errors in Fusion

📦 100.2.0 2024-12-23
🎉 added murmurHash for cache use

Expand Down

0 comments on commit 958e131

Please sign in to comment.