From 81b244d135d1cccefb69b331382e5c93169caddb Mon Sep 17 00:00:00 2001 From: Armano Date: Wed, 30 Mar 2022 22:47:58 +0200 Subject: [PATCH 1/3] fix(website): load typescript libs in playground #4493 --- .../website-eslint/src/linter/CompilerHost.js | 50 ++++++++++++-- .../src/linter/create-ast-program.js | 44 ------------- packages/website-eslint/src/linter/linter.js | 11 +++- packages/website-eslint/src/linter/parser.js | 65 +++++++++++-------- packages/website-eslint/types/index.d.ts | 7 +- .../components/editor/useSandboxServices.ts | 30 +++++---- 6 files changed, 116 insertions(+), 91 deletions(-) delete mode 100644 packages/website-eslint/src/linter/create-ast-program.js diff --git a/packages/website-eslint/src/linter/CompilerHost.js b/packages/website-eslint/src/linter/CompilerHost.js index 2b7fdec25d07..67fd8dbd7d42 100644 --- a/packages/website-eslint/src/linter/CompilerHost.js +++ b/packages/website-eslint/src/linter/CompilerHost.js @@ -1,9 +1,39 @@ import { getDefaultLibFileName } from 'typescript'; +import { ScriptKind } 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 ? ts.ScriptKind.TSX : ts.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 +69,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 ts.createSourceFile( + name, + this.readFile(name), + ts.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/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); From 49a5557d15a771f37577029a492f9aaa8b08df74 Mon Sep 17 00:00:00 2001 From: Armano Date: Wed, 30 Mar 2022 23:12:56 +0200 Subject: [PATCH 2/3] fix(website): correct issue with infinite render loop #4493 --- packages/website/src/components/ast/serializer/serializerTS.ts | 2 ++ 1 file changed, 2 insertions(+) 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 { From 271530a92a308a021c6d5bc4fc6367512ab95d40 Mon Sep 17 00:00:00 2001 From: Armano Date: Thu, 31 Mar 2022 00:03:15 +0200 Subject: [PATCH 3/3] fix(website): deduplicate imports --- packages/website-eslint/src/linter/CompilerHost.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/website-eslint/src/linter/CompilerHost.js b/packages/website-eslint/src/linter/CompilerHost.js index 67fd8dbd7d42..f48c77109c96 100644 --- a/packages/website-eslint/src/linter/CompilerHost.js +++ b/packages/website-eslint/src/linter/CompilerHost.js @@ -1,5 +1,9 @@ -import { getDefaultLibFileName } from 'typescript'; -import { ScriptKind } from 'typescript'; +import { + getDefaultLibFileName, + ScriptKind, + createSourceFile, + ScriptTarget, +} from 'typescript'; function getScriptKind(isJsx, filePath) { const extension = (/(\.[a-z]+)$/.exec(filePath)?.[0] || '').toLowerCase(); @@ -20,7 +24,7 @@ function getScriptKind(isJsx, filePath) { default: // unknown extension, force typescript to ignore the file extension, and respect the user's setting - return isJsx ? ts.ScriptKind.TSX : ts.ScriptKind.TS; + return isJsx ? ScriptKind.TSX : ScriptKind.TS; } } @@ -77,10 +81,10 @@ export class CompilerHost { } getSourceFile(name) { - return ts.createSourceFile( + return createSourceFile( name, this.readFile(name), - ts.ScriptTarget.Latest, + ScriptTarget.Latest, /* setParentNodes */ true, getScriptKind(this.isJsx, name), ); 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