Skip to content

Commit

Permalink
feat: replace svelte-preprocess with barebones TS preprocessor (#2452)
Browse files Browse the repository at this point in the history
Removes the need for a dependency on svelte-preprocess in svelte-language-server, since that was all we used it for.

closes:
- #1683 and #1259, because the situation no longer arises (because we no longer have svelte-preprocess inside the VS Code extension)
- #2391
  • Loading branch information
dummdidumm authored Aug 19, 2024
1 parent 05a489c commit f6ad24d
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 43 deletions.
1 change: 0 additions & 1 deletion packages/language-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
"prettier": "~3.2.5",
"prettier-plugin-svelte": "^3.2.2",
"svelte": "^3.57.0",
"svelte-preprocess": "^5.1.3",
"svelte2tsx": "workspace:~",
"typescript": "^5.5.2",
"typescript-auto-import-cache": "^0.3.3",
Expand Down
20 changes: 14 additions & 6 deletions packages/language-server/src/importPackage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { dirname, resolve } from 'path';
import * as prettier from 'prettier';
import * as svelte from 'svelte/compiler';
import sveltePreprocess from 'svelte-preprocess';
import { Logger } from './logger';

/**
Expand All @@ -25,11 +24,15 @@ function dynamicRequire(dynamicFileToRequire: string): any {
return require(dynamicFileToRequire);
}

export function getPackageInfo(packageName: string, fromPath: string) {
const paths = [__dirname];
export function getPackageInfo(packageName: string, fromPath: string, use_fallback = true) {
const paths: string[] = [];
if (isTrusted) {
paths.unshift(fromPath);
paths.push(fromPath);
}
if (use_fallback) {
paths.push(__dirname);
}

const packageJSONPath = require.resolve(`${packageName}/package.json`, {
paths
});
Expand Down Expand Up @@ -73,8 +76,13 @@ export function importSvelte(fromPath: string): typeof svelte {
}
}

export function importSveltePreprocess(fromPath: string): typeof sveltePreprocess {
const pkg = getPackageInfo('svelte-preprocess', fromPath);
/** Can throw because no fallback guaranteed */
export function importSveltePreprocess(fromPath: string): any {
const pkg = getPackageInfo(
'svelte-preprocess',
fromPath,
false // svelte-language-server doesn't have a dependency on svelte-preprocess so we can't provide a fallback
);
const main = resolve(pkg.path);
Logger.debug('Using svelte-preprocess v' + pkg.version.full, 'from', main);
return dynamicRequire(main);
Expand Down
62 changes: 44 additions & 18 deletions packages/language-server/src/lib/documents/configLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import _path from 'path';
import _fs from 'fs';
import { pathToFileURL, URL } from 'url';
import { FileMap } from './fileCollection';
import ts from 'typescript';

export type InternalPreprocessorGroup = PreprocessorGroup & {
/**
Expand Down Expand Up @@ -249,24 +250,49 @@ export class ConfigLoader {
}

private useFallbackPreprocessor(path: string, foundConfig: boolean): SvelteConfig {
Logger.log(
(foundConfig
? 'Found svelte.config.js but there was an error loading it. '
: 'No svelte.config.js found. ') +
'Using https://github.com/sveltejs/svelte-preprocess as fallback'
);
const sveltePreprocess = importSveltePreprocess(path);
return {
preprocess: sveltePreprocess({
// 4.x does not have transpileOnly anymore, but if the user has version 3.x
// in his repo, that one is loaded instead, for which we still need this.
typescript: <any>{
transpileOnly: true,
compilerOptions: { sourceMap: true, inlineSourceMap: false }
}
}),
isFallbackConfig: true
};
try {
const sveltePreprocess = importSveltePreprocess(path);
Logger.log(
(foundConfig
? 'Found svelte.config.js but there was an error loading it. '
: 'No svelte.config.js found. ') +
'Using https://github.com/sveltejs/svelte-preprocess as fallback'
);
return {
preprocess: sveltePreprocess({
// 4.x does not have transpileOnly anymore, but if the user has version 3.x
// in his repo, that one is loaded instead, for which we still need this.
typescript: {
transpileOnly: true,
compilerOptions: { sourceMap: true, inlineSourceMap: false }
}
}),
isFallbackConfig: true
};
} catch (e) {
// User doesn't have svelte-preprocess installed, provide a barebones TS preprocessor
return {
preprocess: {
// @ts-ignore name property exists in Svelte 4 onwards
name: 'svelte-language-tools-ts-fallback-preprocessor',
script: ({ content, attributes, filename }) => {
if (attributes.lang !== 'ts') return;

const { outputText, sourceMapText } = ts.transpileModule(content, {
fileName: filename,
compilerOptions: {
module: ts.ModuleKind.ESNext,
target: ts.ScriptTarget.ESNext,
sourceMap: true,
verbatimModuleSyntax: true
}
});
return { code: outputText, map: sourceMapText };
}
},
isFallbackConfig: true
};
}
}
}

Expand Down
9 changes: 6 additions & 3 deletions packages/language-server/src/plugins/svelte/SvelteDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type PositionMapper = Pick<DocumentMapper, 'getGeneratedPosition' | 'getOriginal
export class SvelteDocument {
private transpiledDoc: ITranspiledSvelteDocument | undefined;
private compileResult: SvelteCompileResult | undefined;
private svelteVersion: [number, number] | undefined;

public script: TagInformation | null;
public moduleScript: TagInformation | null;
Expand Down Expand Up @@ -69,9 +70,11 @@ export class SvelteDocument {

async getTranspiled(): Promise<ITranspiledSvelteDocument> {
if (!this.transpiledDoc) {
const {
version: { major, minor }
} = getPackageInfo('svelte', this.getFilePath());
if (!this.svelteVersion) {
const { major, minor } = getPackageInfo('svelte', this.getFilePath()).version;
this.svelteVersion = [major, minor];
}
const [major, minor] = this.svelteVersion;

if (major > 3 || (major === 3 && minor >= 32)) {
this.transpiledDoc = await TranspiledSvelteDocument.create(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @ts-ignore
import { Warning } from 'svelte/types/compiler/interfaces';
import {
CancellationToken,
Diagnostic,
Expand Down Expand Up @@ -63,6 +61,17 @@ async function tryGetDiagnostics(
if (cancellationToken?.isCancellationRequested) {
return [];
}

let ignoreScriptWarnings = false;
let ignoreStyleWarnings = false;
let ignoreTemplateWarnings = false;
if (!document.config?.preprocess || !!document.config.isFallbackConfig) {
ignoreTemplateWarnings = !!document.getLanguageAttribute('template');
ignoreStyleWarnings = !!document.getLanguageAttribute('style');
const scriptAttr = document.getLanguageAttribute('script');
ignoreScriptWarnings = !!scriptAttr && scriptAttr !== 'ts';
}

return (res.warnings || [])
.filter((warning) => settings[warning.code] !== 'ignore')
.map((warning) => {
Expand All @@ -81,7 +90,15 @@ async function tryGetDiagnostics(
})
.map((diag) => mapObjWithRangeToOriginal(transpiled, diag))
.map((diag) => adjustMappings(diag, document))
.filter((diag) => isNoFalsePositive(diag, document));
.filter((diag) =>
isNoFalsePositive(
diag,
document,
ignoreScriptWarnings,
ignoreStyleWarnings,
ignoreTemplateWarnings
)
);
} catch (err) {
return createParserErrorDiagnostic(err, document)
.map((diag) => mapObjWithRangeToOriginal(transpiled, diag))
Expand Down Expand Up @@ -290,8 +307,28 @@ function getErrorMessage(error: any, source: string, hint = '') {
);
}

function isNoFalsePositive(diag: Diagnostic, doc: Document): boolean {
if (diag.code !== 'unused-export-let') {
function isNoFalsePositive(
diag: Diagnostic,
doc: Document,
ignoreScriptWarnings: boolean,
ignoreStyleWarnings: boolean,
ignoreTemplateWarnings: boolean
): boolean {
if (
(ignoreTemplateWarnings || ignoreScriptWarnings) &&
(typeof diag.code !== 'string' || !diag.code.startsWith('a11y'))
) {
return false;
}

if (
ignoreStyleWarnings &&
(diag.code === 'css-unused-selector' || diag.code === 'css_unused_selector')
) {
return false;
}

if (diag.code !== 'unused-export-let' && diag.code !== 'export_let_unused') {
return true;
}

Expand Down Expand Up @@ -328,7 +365,7 @@ function adjustMappings(diag: Diagnostic, doc: Document): Diagnostic {
diag.range = moveRangeStartToEndIfNecessary(diag.range);

if (
diag.code === 'css-unused-selector' &&
(diag.code === 'css-unused-selector' || diag.code === 'css_unused_selector') &&
doc.styleInfo &&
!isInTag(diag.range.start, doc.styleInfo)
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ describe('SveltePlugin#getDiagnostics', () => {
docText?: string;
}) {
const document = new Document('', docText);
const svelteDoc: SvelteDocument = <any>{ getTranspiled, getCompiled, config };
const svelteDoc: SvelteDocument = <any>{
getTranspiled,
getCompiled,
config,
getSvelteVersion: () => [4, 0]
};
const result = await getDiagnostics(document, svelteDoc, settings);
return {
toEqual: (expected: Diagnostic[]) => assert.deepStrictEqual(result, expected)
Expand Down Expand Up @@ -298,7 +303,9 @@ describe('SveltePlugin#getDiagnostics', () => {
}
]
}),
config: {}
config: {
preprocess: []
}
})
).toEqual([
{
Expand Down Expand Up @@ -343,7 +350,9 @@ describe('SveltePlugin#getDiagnostics', () => {
]
}
}),
config: {}
config: {
preprocess: []
}
})
).toEqual([]);
});
Expand Down Expand Up @@ -372,7 +381,9 @@ describe('SveltePlugin#getDiagnostics', () => {
]
}
}),
config: {}
config: {
preprocess: []
}
})
).toEqual([]);
});
Expand All @@ -399,7 +410,9 @@ describe('SveltePlugin#getDiagnostics', () => {
]
}
}),
config: {},
config: {
preprocess: []
},
settings: { 123: 'ignore' }
})
).toEqual([]);
Expand All @@ -425,7 +438,9 @@ describe('SveltePlugin#getDiagnostics', () => {
}
]
}),
config: {},
config: {
preprocess: []
},
settings: { 123: 'error' }
})
).toEqual([
Expand Down
3 changes: 0 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f6ad24d

Please sign in to comment.