@graphql-codegen/testing
Version:
GraphQL Codegen Testing Utils
187 lines (186 loc) • 7.75 kB
JavaScript
import { dirname, join, resolve } from 'path';
import { compressToEncodedURIComponent } from 'lz-string';
import { createCompilerHost, createProgram, createSourceFile, flattenDiagnosticMessageText, JsxEmit, ModuleKind, ModuleResolutionKind, ScriptKind, ScriptTarget, } from 'typescript';
export function validateTs(pluginOutput, options = {
noEmitOnError: true,
noImplicitAny: true,
moduleResolution: ModuleResolutionKind.NodeJs,
experimentalDecorators: true,
emitDecoratorMetadata: true,
target: ScriptTarget.ES5,
typeRoots: [resolve(require.resolve('typescript'), '../../../@types/')],
jsx: JsxEmit.React,
allowJs: true,
skipLibCheck: true,
lib: [
join(dirname(require.resolve('typescript')), 'lib.es5.d.ts'),
join(dirname(require.resolve('typescript')), 'lib.es6.d.ts'),
join(dirname(require.resolve('typescript')), 'lib.dom.d.ts'),
join(dirname(require.resolve('typescript')), 'lib.scripthost.d.ts'),
join(dirname(require.resolve('typescript')), 'lib.es2015.d.ts'),
join(dirname(require.resolve('typescript')), 'lib.esnext.d.ts'),
],
module: ModuleKind.ESNext,
}, isTsx = false, isStrict = false, suspenseErrors = [], compileProgram = false) {
if (process.env.SKIP_VALIDATION) {
return;
}
if (isStrict) {
options.strictNullChecks = true;
options.strict = true;
options.strictBindCallApply = true;
options.strictPropertyInitialization = true;
options.alwaysStrict = true;
options.strictFunctionTypes = true;
}
const contents = typeof pluginOutput === 'string'
? pluginOutput
: [...(pluginOutput.prepend || []), pluginOutput.content, ...(pluginOutput.append || [])].join('\n');
const testFile = `test-file.${isTsx ? 'tsx' : 'ts'}`;
const errors = [];
if (compileProgram) {
const host = createCompilerHost(options);
const program = createProgram([testFile], options, {
...host,
getSourceFile: (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
if (fileName === testFile) {
return createSourceFile(fileName, contents, options.target);
}
return host.getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile);
},
writeFile() { },
useCaseSensitiveFileNames() {
return false;
},
getCanonicalFileName(filename) {
return filename;
},
getCurrentDirectory() {
return '';
},
getNewLine() {
return '\n';
},
});
const emitResult = program.emit();
const allDiagnostics = emitResult.diagnostics;
for (const diagnostic of allDiagnostics) {
if (diagnostic.file) {
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
const message = flattenDiagnosticMessageText(diagnostic.messageText, '\n');
errors.push(`${line + 1},${character + 1}: ${message} ->
${contents.split('\n')[line]}`);
}
else {
errors.push(String(flattenDiagnosticMessageText(diagnostic.messageText, '\n')));
}
}
}
else {
const result = createSourceFile(testFile, contents, ScriptTarget.ES2016, false, isTsx ? ScriptKind.TSX : undefined);
const allDiagnostics = result.parseDiagnostics;
if (allDiagnostics && allDiagnostics.length > 0) {
for (const diagnostic of allDiagnostics) {
if (diagnostic.file) {
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
const message = flattenDiagnosticMessageText(diagnostic.messageText, '\n');
errors.push(`${line + 1},${character + 1}: ${message} ->
${contents.split('\n')[line]}`);
}
else {
errors.push(String(flattenDiagnosticMessageText(diagnostic.messageText, '\n')));
}
}
}
}
const relevantErrors = errors.filter(e => {
if (e.includes('Cannot find module')) {
return false;
}
for (const suspenseError of suspenseErrors) {
if (e.includes(suspenseError)) {
return false;
}
}
return true;
});
if (relevantErrors && relevantErrors.length > 0) {
throw new Error(relevantErrors.join('\n'));
}
}
export function compileTs(contents, options = {
noEmitOnError: true,
noImplicitAny: true,
moduleResolution: ModuleResolutionKind.NodeJs,
allowSyntheticDefaultImports: true,
experimentalDecorators: true,
emitDecoratorMetadata: true,
target: ScriptTarget.ES5,
typeRoots: [resolve(require.resolve('typescript'), '../../../@types/')],
jsx: JsxEmit.Preserve,
allowJs: true,
lib: [
join(dirname(require.resolve('typescript')), 'lib.es5.d.ts'),
join(dirname(require.resolve('typescript')), 'lib.es6.d.ts'),
join(dirname(require.resolve('typescript')), 'lib.dom.d.ts'),
join(dirname(require.resolve('typescript')), 'lib.scripthost.d.ts'),
join(dirname(require.resolve('typescript')), 'lib.es2015.d.ts'),
join(dirname(require.resolve('typescript')), 'lib.esnext.asynciterable.d.ts'),
],
module: ModuleKind.ESNext,
}, isTsx = false, openPlayground = false) {
if (process.env.SKIP_VALIDATION) {
return;
}
try {
const testFile = `test-file.${isTsx ? 'tsx' : 'ts'}`;
const host = createCompilerHost(options);
const program = createProgram([testFile], options, {
...host,
getSourceFile: (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
if (fileName === testFile) {
return createSourceFile(fileName, contents, options.target);
}
return host.getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile);
},
writeFile() { },
useCaseSensitiveFileNames() {
return false;
},
getCanonicalFileName(filename) {
return filename;
},
getCurrentDirectory() {
return '';
},
getNewLine() {
return '\n';
},
});
const emitResult = program.emit();
const allDiagnostics = emitResult.diagnostics;
const errors = [];
for (const diagnostic of allDiagnostics) {
if (diagnostic.file) {
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
const message = flattenDiagnosticMessageText(diagnostic.messageText, '\n');
errors.push(`${line + 1},${character + 1}: ${message} ->
${contents.split('\n')[line]}`);
}
else {
errors.push(String(flattenDiagnosticMessageText(diagnostic.messageText, '\n')));
}
}
const relevantErrors = errors.filter(e => !e.includes('Cannot find module'));
if (relevantErrors && relevantErrors.length > 0) {
throw new Error(relevantErrors.join('\n'));
}
}
catch (e) {
if (openPlayground) {
const compressedCode = compressToEncodedURIComponent(contents);
open('http://www.typescriptlang.org/play/#code/' + compressedCode);
}
throw e;
}
}