-
Notifications
You must be signed in to change notification settings - Fork 47
Gracefully handle files that are not from a theme #985
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
'@shopify/theme-language-server-common': patch | ||
'@shopify/theme-language-server-node': patch | ||
'@shopify/theme-check-common': patch | ||
'theme-check-vscode': patch | ||
--- | ||
|
||
Gracefully handle files that are not part of a theme |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ import { AbstractFileSystem, FileStat, FileTuple, FileType } from '../AbstractFi | |
import { deepGet } from '../utils'; | ||
import { normalize, relative } from '../path'; | ||
import { MockTheme } from './MockTheme'; | ||
import * as path from '../path'; | ||
|
||
interface FileTree { | ||
[fileName: string]: string | FileTree; | ||
|
@@ -24,14 +25,15 @@ export class MockFileSystem implements AbstractFileSystem { | |
} | ||
|
||
async readDirectory(uri: string): Promise<FileTuple[]> { | ||
// eslint-disable-next-line no-param-reassign | ||
uri = uri.replace(/\/$/, ''); | ||
const relativePath = this.rootRelative(uri); | ||
const tree = | ||
normalize(uri) === this.rootUri | ||
path.normalize(uri) === this.rootUri | ||
? this.fileTree | ||
: deepGet(this.fileTree, relativePath.split('/')); | ||
if (tree === undefined) { | ||
throw new Error(`Directory not found: ${uri} in ${this.rootUri}`); | ||
if (tree === undefined || tree === null) { | ||
throw new Error(`Directory not found: ${uri} for ${this.rootUri}`); | ||
} | ||
|
||
if (typeof tree === 'string') { | ||
|
@@ -46,32 +48,37 @@ export class MockFileSystem implements AbstractFileSystem { | |
async stat(uri: string): Promise<FileStat> { | ||
const relativePath = this.rootRelative(uri); | ||
const source = this.mockTheme[relativePath]; | ||
if (source === undefined) { | ||
throw new Error('File not found'); | ||
if (source) { | ||
return { | ||
type: FileType.File, | ||
size: source.length ?? 0, | ||
}; | ||
} | ||
return { | ||
type: FileType.File, | ||
size: source.length ?? 0, | ||
}; | ||
} | ||
|
||
private _fileTree: FileTree | null = null; | ||
const readdirResult = await this.readDirectory(uri); | ||
if (readdirResult) { | ||
return { | ||
type: FileType.Directory, | ||
size: 0, // Size is not applicable for directories | ||
}; | ||
} | ||
|
||
throw new Error(`File not found: ${uri} for ${this.rootUri}`); | ||
} | ||
|
||
private get fileTree(): FileTree { | ||
if (!this._fileTree) { | ||
this._fileTree = {}; | ||
for (const [relativePath, source] of Object.entries(this.mockTheme)) { | ||
const segments = relativePath.split('/'); | ||
let current = this._fileTree; | ||
for (let i = 0; i < segments.length - 1; i++) { | ||
const segment = segments[i]; | ||
current[segment] ??= {}; | ||
current = current[segment] as FileTree; | ||
} | ||
current[segments[segments.length - 1]] = source; | ||
const result: FileTree = {}; | ||
for (const [relativePath, source] of Object.entries(this.mockTheme)) { | ||
const segments = relativePath.split('/'); | ||
let current = result; | ||
for (let i = 0; i < segments.length - 1; i++) { | ||
const segment = segments[i]; | ||
current[segment] ??= {}; | ||
current = current[segment] as FileTree; | ||
} | ||
current[segments[segments.length - 1]] = source; | ||
} | ||
return this._fileTree; | ||
return result; | ||
Comment on lines
+70
to
+81
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Had to remove memoization because of a test that mutated this.mockTheme. It's only for tests, perf doesn't matter :) |
||
} | ||
|
||
private rootRelative(uri: string) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,7 +43,7 @@ export function makeRunChecks( | |
// then we recheck theme1 | ||
const fileExists = makeFileExists(fs); | ||
const rootURIs = await Promise.all(triggerURIs.map((uri) => findRoot(uri, fileExists))); | ||
const deduplicatedRootURIs = new Set(rootURIs); | ||
const deduplicatedRootURIs = new Set<string>(rootURIs.filter((x): x is string => !!x)); | ||
await Promise.all([...deduplicatedRootURIs].map(runChecksForRoot)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Impact: runChecks won't run when triggered from a file that you can't find a root for. |
||
|
||
return; | ||
|
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.
toURI does this better.