Skip to content

Commit

Permalink
fix: support ts configs with comments (#167)
Browse files Browse the repository at this point in the history
  • Loading branch information
ValeraS authored Dec 9, 2024
1 parent 156a270 commit e6021bc
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 50 deletions.
38 changes: 12 additions & 26 deletions src/common/typescript/compile.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type Typescript from 'typescript';
import type {Logger} from '../logger';
import {displayFilename, getProjectConfig} from './utils';
import {displayFilename, getTsProjectConfig} from './utils';
import {createTransformPathsToLocalModules} from './transformers';
import {elapsedTime} from '../logger/pretty-time';
import {formatDiagnosticBrief} from './diagnostic';
Expand All @@ -21,32 +21,12 @@ export function compile(
logger.message(`Typescript v${ts.version}`);

logger.verbose(`Searching for the ${configFileName} in ${projectPath}`);
const configPath = getProjectConfig(ts, projectPath, configFileName);
const parsedConfig = getTsProjectConfig(ts, projectPath, configFileName, {
noEmit: false,
noEmitOnError: true,
...optionsToExtend,
});

const formatHost = {
getCanonicalFileName: (path: string) => path,
getCurrentDirectory: ts.sys.getCurrentDirectory,
getNewLine: () => ts.sys.newLine,
};

const parseConfigFileHost: Typescript.ParseConfigFileHost = {
getCurrentDirectory: ts.sys.getCurrentDirectory,
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
readDirectory: ts.sys.readDirectory,
fileExists: ts.sys.fileExists,
readFile: ts.sys.readFile,
onUnRecoverableConfigFileDiagnostic: reportDiagnostic,
};

const parsedConfig = ts.getParsedCommandLineOfConfigFile(
configPath,
{noEmit: false, noEmitOnError: true, ...optionsToExtend},
parseConfigFileHost,
);

if (!parsedConfig) {
throw new Error(`Invalid '${configFileName}'`);
}
logger.verbose('Config found and parsed');

logger.verbose("We're about to create the program");
Expand Down Expand Up @@ -81,6 +61,12 @@ export function compile(
logger.success(`Compiled successfully in ${elapsedTime(start)}`);
}

const formatHost = {
getCanonicalFileName: (path: string) => path,
getCurrentDirectory: ts.sys.getCurrentDirectory,
getNewLine: () => ts.sys.newLine,
};

function reportDiagnostic(diagnostic: Typescript.Diagnostic) {
if (logger.isVerbose) {
logger.message(ts.formatDiagnosticsWithColorAndContext([diagnostic], formatHost));
Expand Down
32 changes: 31 additions & 1 deletion src/common/typescript/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import paths from '../paths';
import type Typescript from 'typescript';
import type {Logger} from '../logger';

export function getProjectConfig(
export function getTsProjectConfigPath(
ts: typeof Typescript,
projectPath: string,
filename = 'tsconfig.json',
Expand All @@ -16,6 +16,36 @@ export function getProjectConfig(

return configPath;
}
export function getTsProjectConfig(
ts: typeof Typescript,
projectPath: string,
filename = 'tsconfig.json',
optionsToExtend?: Typescript.CompilerOptions,
) {
const configPath = getTsProjectConfigPath(ts, projectPath, filename);

const parseConfigFileHost: Typescript.ParseConfigFileHost = {
getCurrentDirectory: ts.sys.getCurrentDirectory,
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
readDirectory: ts.sys.readDirectory,
fileExists: ts.sys.fileExists,
readFile: ts.sys.readFile,
// this is required in types but not used
onUnRecoverableConfigFileDiagnostic: () => {},
};

const parsedConfig = ts.getParsedCommandLineOfConfigFile(
configPath,
optionsToExtend,
parseConfigFileHost,
);

if (!parsedConfig) {
throw new Error(`Invalid config file '${configPath}'`);
}

return parsedConfig;
}

export function displayFilename(
originalFunc: (path: string, encoding?: string) => string | undefined,
Expand Down
4 changes: 2 additions & 2 deletions src/common/typescript/watch.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type Typescript from 'typescript';
import type {Logger} from '../logger';
import {createTransformPathsToLocalModules} from './transformers';
import {displayFilename, getProjectConfig, onHostEvent} from './utils';
import {displayFilename, getTsProjectConfigPath, onHostEvent} from './utils';
import {formatDiagnosticBrief} from './diagnostic';

export function watch(
Expand All @@ -15,7 +15,7 @@ export function watch(
) {
logger.message('Start compilation in watch mode');
logger.message(`Typescript v${ts.version}`);
const configPath = getProjectConfig(ts, projectPath);
const configPath = getTsProjectConfigPath(ts, projectPath);

const createProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram;

Expand Down
5 changes: 2 additions & 3 deletions src/common/webpack/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {babelPreset} from '../babel';
import type {NormalizedClientConfig} from '../models';
import type {Logger} from '../logger';
import {ProgressPlugin} from './progress-plugin';
import {resolveTsconfigPathsToAlias} from './utils';
import {resolveTsConfigPathsToAlias} from './utils';
import {S3UploadPlugin} from '../s3-upload';
import {logConfig} from '../logger/log-config';
import {resolveTypescript} from '../typescript/utils';
Expand Down Expand Up @@ -199,8 +199,7 @@ export function configureResolve({isEnvProduction, config}: HelperOptions): webp
alias['scheduler/tracing'] = 'scheduler/tracing-profiling';
}

const {aliases, modules = []} =
resolveTsconfigPathsToAlias(path.resolve(paths.appClient, 'tsconfig.json')) || {};
const {aliases, modules = []} = resolveTsConfigPathsToAlias(paths.appClient);
return {
alias: {
...aliases,
Expand Down
33 changes: 15 additions & 18 deletions src/common/webpack/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as path from 'node:path';
import * as fs from 'node:fs';
import * as ts from 'typescript';
import {prettyTime} from '../logger/pretty-time';
import {getTsProjectConfig} from '../typescript/utils';

import type webpack from 'webpack';
import type {Logger} from '../logger';
Expand Down Expand Up @@ -47,18 +48,25 @@ export function webpackCompilerHandlerFactory(logger: Logger, onCompilationEnd?:
}

const endStarRe = /\/?\*$/;
export function resolveTsconfigPathsToAlias(tsConfigPath: string) {
if (!fs.existsSync(tsConfigPath) || !fs.statSync(tsConfigPath).isFile) {
return undefined;
export function resolveTsConfigPathsToAlias(projectPath: string, filename = 'tsconfig.json') {
let parsed;
try {
parsed = getTsProjectConfig(ts, projectPath, filename);
} catch {
return {};
}

const {paths = {}, baseUrl} = readJsonConfig(tsConfigPath).compilerOptions || {};
if (parsed.errors.length > 0) {
return {};
}

const {paths = {}, baseUrl} = parsed.options;

if (!baseUrl) {
return undefined;
return {};
}

const basePath = path.resolve(path.dirname(tsConfigPath), baseUrl);
const basePath = path.resolve(path.dirname(projectPath), baseUrl);
const aliases: Record<string, string[]> = {};
const modules: string[] = [basePath];
for (const [key, value] of Object.entries(paths)) {
Expand All @@ -78,14 +86,3 @@ export function resolveTsconfigPathsToAlias(tsConfigPath: string) {

return {aliases, modules};
}

function readJsonConfig(pathname: string) {
try {
const json = fs.readFileSync(pathname, 'utf-8');
return {
...JSON.parse(json),
};
} catch {
throw new Error(`Couldn't read config ${pathname}`);
}
}

0 comments on commit e6021bc

Please sign in to comment.