Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 92 additions & 62 deletions packages/typescript-plugin/src/svelte-snapshots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,73 +279,103 @@ export class SvelteSnapshotManager {
}

private patchProjectServiceReadFile() {
const readFile = this.projectService.host.readFile;
this.projectService.host.readFile = (path: string, encoding?: string | undefined) => {
if (!this.configManager.getConfig().enable) {
return readFile(path, encoding);
}
// @ts-ignore The projectService is shared across some instances, make sure we patch readFile only once
if (!this.projectService.host[onReadSvelteFile]) {
this.logger.log('patching projectService host readFile');

// @ts-ignore
this.projectService.host[onReadSvelteFile] = [];

// The following (very hacky) first two checks make sure that the ambient module definitions
// that tell TS "every import ending with .svelte is a valid module" are removed.
// They exist in svelte2tsx and svelte to make sure that people don't
// get errors in their TS files when importing Svelte files and not using our TS plugin.
// If someone wants to get back the behavior they can add an ambient module definition
// on their own.
const normalizedPath = path.replace(/\\/g, '/');
if (normalizedPath.endsWith('node_modules/svelte/types/runtime/ambient.d.ts')) {
return '';
} else if (normalizedPath.endsWith('svelte2tsx/svelte-shims.d.ts')) {
let originalText = readFile(path) || '';
if (!originalText.includes('// -- start svelte-ls-remove --')) {
return originalText; // uses an older version of svelte2tsx
const readFile = this.projectService.host.readFile;
this.projectService.host.readFile = (path: string, encoding?: string | undefined) => {
if (!this.configManager.getConfig().enable) {
return readFile(path, encoding);
}
originalText =
originalText.substring(
0,
originalText.indexOf('// -- start svelte-ls-remove --')
) +
originalText.substring(originalText.indexOf('// -- end svelte-ls-remove --'));
return originalText;
} else if (isSvelteFilePath(path)) {
this.logger.debug('Read Svelte file:', path);
const svelteCode = readFile(path) || '';
try {
const isTsFile = true; // TODO check file contents? TS might be okay with importing ts into js.
const result = svelte2tsx(svelteCode, {
filename: path.split('/').pop(),
isTsFile,
mode: 'ts', // useNewTransformation
typingsNamespace: this.svelteOptions.namespace
});
const canonicalFilePath = this.projectService.toCanonicalFileName(path);
const existingSnapshot = this.snapshots.get(canonicalFilePath);
if (existingSnapshot) {
existingSnapshot.update(svelteCode, new SourceMapper(result.map.mappings));
} else {
this.snapshots.set(
canonicalFilePath,
new SvelteSnapshot(
this.typescript,
path,
svelteCode,
new SourceMapper(result.map.mappings),
this.logger,
isTsFile
)

// The following (very hacky) first two checks make sure that the ambient module definitions
// that tell TS "every import ending with .svelte is a valid module" are removed.
// They exist in svelte2tsx and svelte to make sure that people don't
// get errors in their TS files when importing Svelte files and not using our TS plugin.
// If someone wants to get back the behavior they can add an ambient module definition
// on their own.
const normalizedPath = path.replace(/\\/g, '/');
if (normalizedPath.endsWith('node_modules/svelte/types/runtime/ambient.d.ts')) {
return '';
} else if (normalizedPath.endsWith('svelte2tsx/svelte-shims.d.ts')) {
let originalText = readFile(path) || '';
if (!originalText.includes('// -- start svelte-ls-remove --')) {
return originalText; // uses an older version of svelte2tsx or is already patched
}
originalText =
originalText.substring(
0,
originalText.indexOf('// -- start svelte-ls-remove --')
) +
originalText.substring(
originalText.indexOf('// -- end svelte-ls-remove --')
);
return originalText;
} else if (isSvelteFilePath(path)) {
this.logger.debug('Read Svelte file:', path);
const svelteCode = readFile(path) || '';
const isTsFile = true; // TODO check file contents? TS might be okay with importing ts into js.
let code: string;
let mapper: SourceMapper;

try {
const result = svelte2tsx(svelteCode, {
filename: path.split('/').pop(),
isTsFile,
mode: 'ts', // useNewTransformation
typingsNamespace: this.svelteOptions.namespace
});
code = result.code;
mapper = new SourceMapper(result.map.mappings);
this.logger.log('Successfully read Svelte file contents of', path);
} catch (e) {
this.logger.log('Error loading Svelte file:', path, ' Using fallback.');
this.logger.debug('Error:', e);
// Return something either way, else "X is not a module" errors will appear
// in the TS files that use this file.
code = 'export default class extends Svelte2TsxComponent<any,any,any> {}';
mapper = new SourceMapper('');
}
this.logger.log('Successfully read Svelte file contents of', path);
return result.code;
} catch (e) {
this.logger.log('Error loading Svelte file:', path, ' Using fallback.');
this.logger.debug('Error:', e);
// Return something either way, else "X is not a module" errors will appear
// in the TS files that use this file.
return 'export default class extends Svelte2TsxComponent<any,any,any> {}';

// @ts-ignore
this.projectService.host[onReadSvelteFile].forEach((listener) =>
listener(path, code, isTsFile, mapper)
);

return code;
} else {
return readFile(path, encoding);
}
};
}

// @ts-ignore
this.projectService.host[onReadSvelteFile].push(
(path: string, svelteCode: string, isTsFile: boolean, mapper: SourceMapper) => {
const canonicalFilePath = this.projectService.toCanonicalFileName(path);
const existingSnapshot = this.snapshots.get(canonicalFilePath);
if (existingSnapshot) {
existingSnapshot.update(svelteCode, mapper);
} else {
this.snapshots.set(
canonicalFilePath,
new SvelteSnapshot(
this.typescript,
path,
svelteCode,
mapper,
this.logger,
isTsFile
)
);
}
} else {
return readFile(path, encoding);
}
};
);
}
}

const onReadSvelteFile = Symbol('sveltePluginPatchSymbol');