diff --git a/packages/website-eslint/src/linter/CompilerHost.js b/packages/website-eslint/src/linter/CompilerHost.js index 2b7fdec25d07..f48c77109c96 100644 --- a/packages/website-eslint/src/linter/CompilerHost.js +++ b/packages/website-eslint/src/linter/CompilerHost.js @@ -1,9 +1,43 @@ -import { getDefaultLibFileName } from 'typescript'; +import { + getDefaultLibFileName, + ScriptKind, + createSourceFile, + ScriptTarget, +} from 'typescript'; + +function getScriptKind(isJsx, filePath) { + const extension = (/(\.[a-z]+)$/.exec(filePath)?.[0] || '').toLowerCase(); + + switch (extension) { + case '.ts': + return ScriptKind.TS; + case '.tsx': + return ScriptKind.TSX; + case '.js': + return ScriptKind.JS; + + case '.jsx': + return ScriptKind.JSX; + + case '.json': + return ScriptKind.JSON; + + default: + // unknown extension, force typescript to ignore the file extension, and respect the user's setting + return isJsx ? ScriptKind.TSX : ScriptKind.TS; + } +} export class CompilerHost { - constructor(files, sourceFiles) { - this.files = files; - this.sourceFiles = sourceFiles; + constructor(libs, isJsx) { + this.files = []; + this.isJsx = isJsx || false; + + if (libs) { + for (const [key, value] of libs) { + this.files[key] = value; + } + } } fileExists(name) { @@ -39,10 +73,20 @@ export class CompilerHost { } readFile(name) { - return this.files[name]; + if (this.fileExists(name)) { + return this.files[name]; + } else { + return ''; // fallback, in case if file is not available + } } getSourceFile(name) { - return this.sourceFiles[name]; + return createSourceFile( + name, + this.readFile(name), + ScriptTarget.Latest, + /* setParentNodes */ true, + getScriptKind(this.isJsx, name), + ); } } diff --git a/packages/website-eslint/src/linter/create-ast-program.js b/packages/website-eslint/src/linter/create-ast-program.js deleted file mode 100644 index ea0444fd2491..000000000000 --- a/packages/website-eslint/src/linter/create-ast-program.js +++ /dev/null @@ -1,44 +0,0 @@ -import { - createProgram, - createSourceFile, - ScriptTarget, - ScriptKind, - JsxEmit, - ModuleKind, -} from 'typescript'; -import { CompilerHost } from './CompilerHost'; - -export function createASTProgram(code, parserOptions) { - const isJsx = !!parserOptions?.ecmaFeatures?.jsx; - const fileName = isJsx ? '/demo.tsx' : '/demo.ts'; - const files = { - [fileName]: code, - }; - const sourceFiles = { - [fileName]: createSourceFile( - fileName, - code, - ScriptTarget.Latest, - true, - isJsx ? ScriptKind.TSX : ScriptKind.TS, - ), - }; - const compilerHost = new CompilerHost(files, sourceFiles); - const compilerOptions = { - noResolve: true, - strict: true, - target: ScriptTarget.Latest, - jsx: isJsx ? JsxEmit.React : undefined, - module: ModuleKind.ES2015, - }; - const program = createProgram( - Object.keys(files), - compilerOptions, - compilerHost, - ); - const ast = program.getSourceFile(fileName); - return { - ast, - program, - }; -} diff --git a/packages/website-eslint/src/linter/linter.js b/packages/website-eslint/src/linter/linter.js index aae8ecc0feda..6d88c341f9c0 100644 --- a/packages/website-eslint/src/linter/linter.js +++ b/packages/website-eslint/src/linter/linter.js @@ -5,15 +5,20 @@ import rules from '@typescript-eslint/eslint-plugin/dist/rules'; const PARSER_NAME = '@typescript-eslint/parser'; -export function loadLinter() { +export function loadLinter(libs, compilerOptions) { const linter = new Linter(); let storedAST; let storedTsAST; let storedScope; linter.defineParser(PARSER_NAME, { - parseForESLint(code, options) { - const toParse = parseForESLint(code, options); + parseForESLint(code, eslintOptions) { + const toParse = parseForESLint( + code, + eslintOptions, + compilerOptions, + libs, + ); storedAST = toParse.ast; storedTsAST = toParse.tsAst; storedScope = toParse.scopeManager; diff --git a/packages/website-eslint/src/linter/parser.js b/packages/website-eslint/src/linter/parser.js index 41c0b24baf10..fc637fe65b7d 100644 --- a/packages/website-eslint/src/linter/parser.js +++ b/packages/website-eslint/src/linter/parser.js @@ -1,42 +1,55 @@ import { analyze } from '@typescript-eslint/scope-manager/dist/analyze'; import { visitorKeys } from '@typescript-eslint/visitor-keys/dist/visitor-keys'; import { astConverter } from '@typescript-eslint/typescript-estree/dist/ast-converter'; -import { createASTProgram } from './create-ast-program.js'; import { extra } from './config.js'; +import { CompilerHost } from './CompilerHost'; +import { createProgram } from 'typescript'; -function parseAndGenerateServices(code, options) { - const { ast, program } = createASTProgram(code, options); - const { estree, astMaps } = astConverter( - ast, - { ...extra, code, jsx: options.jsx ?? false }, - true, - ); +export function createASTProgram(code, isJsx, compilerOptions, libs) { + const fileName = isJsx ? '/demo.tsx' : '/demo.ts'; + const compilerHost = new CompilerHost(libs, isJsx); + compilerHost.files[fileName] = code; + const program = createProgram( + Object.keys(compilerHost.files), + compilerOptions, + compilerHost, + ); + const ast = program.getSourceFile(fileName); return { - ast: estree, - tsAst: ast, - services: { - hasFullTypeInformation: true, - program, - esTreeNodeToTSNodeMap: astMaps.esTreeNodeToTSNodeMap, - tsNodeToESTreeNodeMap: astMaps.tsNodeToESTreeNodeMap, - }, + ast, + program, }; } -export function parseForESLint(code, parserOptions) { - const { ast, tsAst, services } = parseAndGenerateServices(code, { - ...parserOptions, - jsx: parserOptions.ecmaFeatures?.jsx ?? false, - useJSXTextNode: true, - projectFolderIgnoreList: [], - }); +export function parseForESLint(code, eslintOptions, compilerOptions, libs) { + const isJsx = eslintOptions.ecmaFeatures?.jsx ?? false; + + const { ast: tsAst, program } = createASTProgram( + code, + isJsx, + compilerOptions, + libs, + ); + + const { estree: ast, astMaps } = astConverter( + tsAst, + { ...extra, code, jsx: isJsx }, + true, + ); + + const services = { + hasFullTypeInformation: true, + program, + esTreeNodeToTSNodeMap: astMaps.esTreeNodeToTSNodeMap, + tsNodeToESTreeNodeMap: astMaps.tsNodeToESTreeNodeMap, + }; const scopeManager = analyze(ast, { ecmaVersion: - parserOptions.ecmaVersion === 'latest' ? 1e8 : parserOptions.ecmaVersion, - globalReturn: parserOptions.ecmaFeatures?.globalReturn ?? false, - sourceType: parserOptions.sourceType ?? 'script', + eslintOptions.ecmaVersion === 'latest' ? 1e8 : eslintOptions.ecmaVersion, + globalReturn: eslintOptions.ecmaFeatures?.globalReturn ?? false, + sourceType: eslintOptions.sourceType ?? 'script', }); return { diff --git a/packages/website-eslint/types/index.d.ts b/packages/website-eslint/types/index.d.ts index ed3e1e2422f8..429de7388fa4 100644 --- a/packages/website-eslint/types/index.d.ts +++ b/packages/website-eslint/types/index.d.ts @@ -1,6 +1,6 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import type { ParserOptions } from '@typescript-eslint/types'; -import type { SourceFile } from 'typescript'; +import type { SourceFile, CompilerOptions } from 'typescript'; export type LintMessage = TSESLint.Linter.LintMessage; export type RuleFix = TSESLint.RuleFix; @@ -22,7 +22,10 @@ export interface WebLinter { } export interface LinterLoader { - loadLinter(): WebLinter; + loadLinter( + libMap: Map, + compilerOptions: CompilerOptions, + ): WebLinter; } export type { diff --git a/packages/website/src/components/ast/serializer/serializerTS.ts b/packages/website/src/components/ast/serializer/serializerTS.ts index fd03d983ba76..b89d6e0e1a44 100644 --- a/packages/website/src/components/ast/serializer/serializerTS.ts +++ b/packages/website/src/components/ast/serializer/serializerTS.ts @@ -24,6 +24,8 @@ export const propsToFilter = [ 'transformFlags', 'resolvedModules', 'imports', + 'antecedent', + 'antecedents', ]; function isTsNode(value: unknown): value is Node { diff --git a/packages/website/src/components/editor/useSandboxServices.ts b/packages/website/src/components/editor/useSandboxServices.ts index ffd6aa686ffb..b64345124b87 100644 --- a/packages/website/src/components/editor/useSandboxServices.ts +++ b/packages/website/src/components/editor/useSandboxServices.ts @@ -47,7 +47,16 @@ export const useSandboxServices = ( setLoadedTs(props.ts); sandboxSingleton(props.ts) - .then(({ main, sandboxFactory, ts, linter }) => { + .then(async ({ main, sandboxFactory, ts, linter }) => { + const compilerOptions = { + noResolve: true, + strict: true, + target: main.languages.typescript.ScriptTarget.ESNext, + jsx: props.jsx ? main.languages.typescript.JsxEmit.React : undefined, + lib: ['ESNext'], + module: main.languages.typescript.ModuleKind.ESNext, + }; + const sandboxConfig: Partial = { text: '', monacoSettings: { @@ -57,15 +66,7 @@ export const useSandboxServices = ( scrollBeyondLastLine: false, smoothScrolling: true, }, - compilerOptions: { - noResolve: true, - strict: true, - target: main.languages.typescript.ScriptTarget.ESNext, - jsx: props.jsx - ? main.languages.typescript.JsxEmit.React - : undefined, - module: main.languages.typescript.ModuleKind.ESNext, - }, + compilerOptions: compilerOptions, domID: editorEmbedId, }; @@ -75,7 +76,14 @@ export const useSandboxServices = ( ts, ); - const webLinter = linter.loadLinter(); + const libMap = await sandboxInstance.tsvfs.createDefaultMapFromCDN( + sandboxInstance.getCompilerOptions(), + props.ts, + true, + window.ts, + ); + + const webLinter = linter.loadLinter(libMap, compilerOptions); props.onLoaded(webLinter.ruleNames, sandboxInstance.supportedVersions); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy