@neo-one/smart-contract-compiler
Version:
NEO•ONE TypeScript smart contract compiler.
115 lines (113 loc) • 4.86 kB
JavaScript
import { tsUtils } from '@neo-one/ts-utils';
import ts from 'typescript';
import { Context } from './Context';
import { getAllSourceFiles } from './utils';
function createContext(sourceFiles, program, typeChecker, languageService, host) {
return new Context(sourceFiles, program, typeChecker, languageService, host);
}
export function updateContext(context, files) {
const { program, typeChecker, languageService } = createProgram(Object.keys(files), context.host, {
modifyHost: createModifyHostFiles(files),
withTestHarness: context.program.__withTestHarness,
});
const sourceFiles = getAllSourceFiles(Object.keys(files).map((rootName) => tsUtils.file.getSourceFileOrThrow(program, rootName)), typeChecker);
return context.update(sourceFiles, program, typeChecker, languageService);
}
const CREATE_CONTEXT_OPTIONS_DEFAULT = {
withTestHarness: false,
};
const defaultModifyHost = () => {
};
const DEFAULT_MAKE_CONTEXT_OPTIONS = {
...CREATE_CONTEXT_OPTIONS_DEFAULT,
modifyHost: defaultModifyHost,
};
export const COMPILER_OPTIONS = {
target: ts.ScriptTarget.ESNext,
module: ts.ModuleKind.ESNext,
moduleResolution: ts.ModuleResolutionKind.NodeJs,
noLib: true,
typeRoots: [],
pretty: true,
noEmit: true,
declaration: false,
allowSyntheticDefaultImports: true,
resolveJsonModule: false,
experimentalDecorators: true,
jsx: ts.JsxEmit.React,
alwaysStrict: true,
strict: true,
skipLibCheck: true,
noUnusedLocals: true,
noImplicitReturns: true,
allowUnusedLabels: false,
noUnusedParameters: false,
allowUnreachableCode: false,
noFallthroughCasesInSwitch: true,
forceConsistentCasingInFileNames: true,
};
const makeContext = (rootNames, host, options = DEFAULT_MAKE_CONTEXT_OPTIONS) => {
const { program, typeChecker, languageService } = createProgram(rootNames, host, options);
const sourceFiles = getAllSourceFiles(rootNames.map((rootName) => tsUtils.file.getSourceFileOrThrow(program, rootName)), typeChecker);
return createContext(sourceFiles, program, typeChecker, languageService, host);
};
const createModifyHostFiles = (files) => (host) => {
const originalFileExists = host.fileExists === undefined ? undefined : host.fileExists.bind(host);
host.fileExists = (file) => {
if (files[file] !== undefined) {
return true;
}
return originalFileExists === undefined ? false : originalFileExists(file);
};
const originalReadFile = host.readFile === undefined ? undefined : host.readFile.bind(host);
host.readFile = (file, ...args) => {
const foundFile = files[file];
if (foundFile !== undefined) {
return foundFile;
}
return originalReadFile === undefined ? undefined : originalReadFile(file, ...args);
};
};
const createProgram = (rootNames, host, { modifyHost = defaultModifyHost, withTestHarness = false } = DEFAULT_MAKE_CONTEXT_OPTIONS) => {
const servicesHost = host.createLanguageServiceHost(rootNames, COMPILER_OPTIONS, withTestHarness);
modifyHost(servicesHost);
const languageService = ts.createLanguageService(servicesHost);
const program = languageService.getProgram();
if (program === undefined) {
throw new Error('Something went wrong');
}
program.__withTestHarness = withTestHarness;
return {
program,
typeChecker: program.getTypeChecker(),
languageService,
};
};
export const createContextForDir = async (dir, host, options = CREATE_CONTEXT_OPTIONS_DEFAULT) => {
const files = await host.getAllTypescriptFilesInDir(dir);
return makeContext(files, host, options);
};
export const createContextForPath = (filePath, host, options = CREATE_CONTEXT_OPTIONS_DEFAULT) => makeContext([filePath], host, options);
export const createContextForSnippet = (code, host, { fileName: fileNameIn, ...rest } = CREATE_CONTEXT_OPTIONS_DEFAULT) => {
const fileName = host.createSnippetFile(fileNameIn);
const context = makeContext([fileName], host, {
...rest,
modifyHost: createModifyHostFiles({ [fileName]: code }),
});
const sourceFile = tsUtils.file.getSourceFileOrThrow(context.program, fileName);
return {
context,
sourceFile,
};
};
export const createContextForLanguageService = (filePath, languageService, host) => {
const program = languageService.getProgram();
if (program === undefined) {
throw new Error('Something went wrong');
}
const sourceFile = tsUtils.file.getSourceFileOrThrow(program, filePath);
const typeChecker = program.getTypeChecker();
const sourceFiles = getAllSourceFiles([sourceFile], typeChecker);
return createContext(sourceFiles, program, typeChecker, languageService, host);
};
//# sourceMappingURL=createContext.js.map