• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import path from 'path';
2import * as ts from 'typescript';
3import { Extra } from '../parser-options';
4
5interface ASTAndProgram {
6  ast: ts.SourceFile;
7  program: ts.Program;
8}
9
10/**
11 * Default compiler options for program generation from single root file
12 */
13const DEFAULT_COMPILER_OPTIONS: ts.CompilerOptions = {
14  allowNonTsExtensions: true,
15  allowJs: true,
16  checkJs: true,
17  noEmit: true,
18  // extendedDiagnostics: true,
19  /**
20   * Flags required to make no-unused-vars work
21   */
22  noUnusedLocals: true,
23  noUnusedParameters: true,
24};
25
26function createDefaultCompilerOptionsFromExtra(
27  extra: Extra,
28): ts.CompilerOptions {
29  if (extra.debugLevel.has('typescript')) {
30    return {
31      ...DEFAULT_COMPILER_OPTIONS,
32      extendedDiagnostics: true,
33    };
34  }
35
36  return DEFAULT_COMPILER_OPTIONS;
37}
38
39// This narrows the type so we can be sure we're passing canonical names in the correct places
40type CanonicalPath = string & { __brand: unknown };
41
42// typescript doesn't provide a ts.sys implementation for browser environments
43const useCaseSensitiveFileNames =
44  ts.sys !== undefined ? ts.sys.useCaseSensitiveFileNames : true;
45const correctPathCasing = useCaseSensitiveFileNames
46  ? (filePath: string): string => filePath
47  : (filePath: string): string => filePath.toLowerCase();
48
49function getCanonicalFileName(filePath: string): CanonicalPath {
50  let normalized = path.normalize(filePath);
51  if (normalized.endsWith(path.sep)) {
52    normalized = normalized.substr(0, normalized.length - 1);
53  }
54  return correctPathCasing(normalized) as CanonicalPath;
55}
56
57function ensureAbsolutePath(p: string, extra: Extra): string {
58  return path.isAbsolute(p)
59    ? p
60    : path.join(extra.tsconfigRootDir || process.cwd(), p);
61}
62
63function getTsconfigPath(tsconfigPath: string, extra: Extra): CanonicalPath {
64  return getCanonicalFileName(ensureAbsolutePath(tsconfigPath, extra));
65}
66
67function canonicalDirname(p: CanonicalPath): CanonicalPath {
68  return path.dirname(p) as CanonicalPath;
69}
70
71function getScriptKind(
72  extra: Extra,
73  filePath: string = extra.filePath,
74): ts.ScriptKind {
75  const extension = path.extname(filePath).toLowerCase();
76  // note - we respect the user's extension when it is known  we could override it and force it to match their
77  // jsx setting, but that could create weird situations where we throw parse errors when TSC doesn't
78  switch (extension) {
79    case '.ts':
80      return ts.ScriptKind.TS;
81
82    case '.tsx':
83      return ts.ScriptKind.TSX;
84
85    case '.js':
86      return ts.ScriptKind.JS;
87
88    case '.jsx':
89      return ts.ScriptKind.JSX;
90
91    case '.json':
92      return ts.ScriptKind.JSON;
93
94    default:
95      // unknown extension, force typescript to ignore the file extension, and respect the user's setting
96      return extra.jsx ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
97  }
98}
99
100export {
101  ASTAndProgram,
102  canonicalDirname,
103  CanonicalPath,
104  createDefaultCompilerOptionsFromExtra,
105  ensureAbsolutePath,
106  getCanonicalFileName,
107  getScriptKind,
108  getTsconfigPath,
109};
110