mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-19 10:41:56 -05:00
Add support for list types
consolidate typings options and commmandline option parsing from json files Fix
This commit is contained in:
committed by
Kanchalai Tanglertsampan
parent
3adab0cec3
commit
0735f465f0
@@ -186,8 +186,8 @@ namespace ts {
|
||||
name: "rootDir",
|
||||
type: "string",
|
||||
isFilePath: true,
|
||||
description: Diagnostics.Specifies_the_root_directory_of_input_files_Use_to_control_the_output_directory_structure_with_outDir,
|
||||
paramType: Diagnostics.LOCATION,
|
||||
description: Diagnostics.Specifies_the_root_directory_of_input_files_Use_to_control_the_output_directory_structure_with_outDir,
|
||||
},
|
||||
{
|
||||
name: "isolatedModules",
|
||||
@@ -268,14 +268,17 @@ namespace ts {
|
||||
error: Diagnostics.Argument_for_moduleResolution_option_must_be_node_or_classic,
|
||||
},
|
||||
{
|
||||
name: "list",
|
||||
elementType: {
|
||||
"node": ModuleResolutionKind.NodeJs,
|
||||
"classic": ModuleResolutionKind.Classic,
|
||||
},
|
||||
name: "lib",
|
||||
type: "list",
|
||||
element: {
|
||||
name: "lib",
|
||||
type: {
|
||||
"node": ModuleResolutionKind.NodeJs,
|
||||
"classic": ModuleResolutionKind.Classic,
|
||||
},
|
||||
error: Diagnostics.Argument_for_moduleResolution_option_must_be_node_or_classic,
|
||||
},
|
||||
description: Diagnostics.Specifies_module_resolution_strategy_Colon_node_Node_js_or_classic_TypeScript_pre_1_6,
|
||||
error: Diagnostics.Argument_for_moduleResolution_option_must_be_node_or_classic,
|
||||
},
|
||||
{
|
||||
name: "allowUnusedLabels",
|
||||
@@ -319,9 +322,13 @@ namespace ts {
|
||||
// this option can only be specified in tsconfig.json
|
||||
// use type = object to copy the value as-is
|
||||
name: "rootDirs",
|
||||
type: "object",
|
||||
type: "list",
|
||||
isTSConfigOnly: true,
|
||||
isFilePath: true
|
||||
element: {
|
||||
name: "rootDirs",
|
||||
type: "string",
|
||||
isFilePath: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "traceModuleResolution",
|
||||
@@ -345,6 +352,30 @@ namespace ts {
|
||||
}
|
||||
];
|
||||
|
||||
/* @internal */
|
||||
export let typingOptionDeclarations: CommandLineOption[] = [
|
||||
{
|
||||
name: "enableAutoDiscovery",
|
||||
type: "boolean",
|
||||
},
|
||||
{
|
||||
name: "include",
|
||||
type: "list",
|
||||
element: {
|
||||
name: "include",
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "exclude",
|
||||
type: "list",
|
||||
element: {
|
||||
name: "include",
|
||||
type: "string"
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
/* @internal */
|
||||
export interface OptionNameMap {
|
||||
optionNameMap: Map<CommandLineOption>;
|
||||
@@ -401,7 +432,40 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (hasProperty(optionNameMap, s)) {
|
||||
parseString(optionNameMap[s], args[i]);
|
||||
const opt = optionNameMap[s];
|
||||
|
||||
if (opt.isTSConfigOnly) {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file, opt.name));
|
||||
}
|
||||
else {
|
||||
// Check to see if no argument was provided (e.g. "--locale" is the last command-line argument).
|
||||
if (!args[i] && opt.type !== "boolean") {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_expects_an_argument, opt.name));
|
||||
}
|
||||
|
||||
switch (opt.type) {
|
||||
case "number":
|
||||
options[opt.name] = parseInt(args[i]);
|
||||
i++;
|
||||
break;
|
||||
case "boolean":
|
||||
options[opt.name] = true;
|
||||
break;
|
||||
case "string":
|
||||
options[opt.name] = args[i] || "";
|
||||
i++;
|
||||
break;
|
||||
case "list":
|
||||
options[opt.name] = parseListTypeOption(<CommandLineOptionOfListType>opt, args[i]);
|
||||
i++;
|
||||
break;
|
||||
// If not a primitive, the possible types are specified in what is effectively a map of options.
|
||||
default:
|
||||
options[opt.name] = parseCustomTypeOption(<CommandLineOptionOfCustomType>opt, args[i]);
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_compiler_option_0, s));
|
||||
@@ -410,40 +474,25 @@ namespace ts {
|
||||
else {
|
||||
fileNames.push(s);
|
||||
}
|
||||
}
|
||||
|
||||
function parseString(opt: CommandLineOption, value: string) {
|
||||
// Check to see if no argument was provided (e.g. "--locale" is the last command-line argument).
|
||||
if (!value && opt.type !== "boolean") {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_expects_an_argument, opt.name));
|
||||
function parseCustomTypeOption(opt: CommandLineOptionOfCustomType, value: string) {
|
||||
const map = <Map<number>>opt.type;
|
||||
const key = (value || "").toLowerCase();
|
||||
if (hasProperty(map, key)) {
|
||||
return map[key];
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(opt.error));
|
||||
}
|
||||
}
|
||||
|
||||
switch (opt.type) {
|
||||
case "number":
|
||||
options[opt.name] = parseInt(value);
|
||||
i++;
|
||||
break;
|
||||
case "boolean":
|
||||
options[opt.name] = true;
|
||||
break;
|
||||
case "string":
|
||||
options[opt.name] = value || "";
|
||||
i++;
|
||||
break;
|
||||
case "list":
|
||||
forEach((value || "").split(","), s => parseString(opt.name, opti );
|
||||
break;
|
||||
// If not a primitive, the possible types are specified in what is effectively a map of options.
|
||||
default:
|
||||
let map = <Map<number>>opt.type;
|
||||
let key = (value || "").toLowerCase();
|
||||
i++;
|
||||
if (hasProperty(map, key)) {
|
||||
options[opt.name] = map[key];
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic((<CommandLineOptionOfCustomType>opt).error));
|
||||
}
|
||||
function parseListTypeOption(opt: CommandLineOptionOfListType, value: string): number[] | string[] {
|
||||
const values = (value || "").split(",");
|
||||
switch (opt.element.type) {
|
||||
case "number": return ts.map(values, parseInt);
|
||||
case "string": return ts.map(values, v => v || "");
|
||||
default: return ts.map(values, v => parseCustomTypeOption(<CommandLineOptionOfCustomType>opt.element, v));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -512,7 +561,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the comments from a json like text.
|
||||
* Comments can be single line comments (starting with # or //) or multiline comments using / * * /
|
||||
@@ -546,18 +594,20 @@ namespace ts {
|
||||
* file to. e.g. outDir
|
||||
*/
|
||||
export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions: CompilerOptions = {}, configFileName?: string): ParsedCommandLine {
|
||||
const { options: optionsFromJsonConfigFile, errors } = convertCompilerOptionsFromJson(json["compilerOptions"], basePath, configFileName);
|
||||
|
||||
const errors: Diagnostic[] = [];
|
||||
const optionsFromJsonConfigFile = convertOptionsFromJson<CompilerOptions>(optionDeclarations, json["compilerOptions"], basePath, configFileName, errors);
|
||||
const options = extend(existingOptions, optionsFromJsonConfigFile);
|
||||
const typingOptions = convertOptionsFromJson<TypingOptions>(typingOptionDeclarations, json["typingOptions"], basePath, configFileName, errors);
|
||||
const fileNames = getFileNames(errors);
|
||||
|
||||
return {
|
||||
options,
|
||||
fileNames: getFileNames(),
|
||||
typingOptions: getTypingOptions(),
|
||||
fileNames,
|
||||
typingOptions,
|
||||
errors
|
||||
};
|
||||
|
||||
function getFileNames(): string[] {
|
||||
function getFileNames(errors: Diagnostic[]): string[] {
|
||||
let fileNames: string[] = [];
|
||||
if (hasProperty(json, "files")) {
|
||||
if (json["files"] instanceof Array) {
|
||||
@@ -618,47 +668,24 @@ namespace ts {
|
||||
}
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
function getTypingOptions(): TypingOptions {
|
||||
const options: TypingOptions = getBaseFileName(configFileName) === "jsconfig.json"
|
||||
? { enableAutoDiscovery: true, include: [], exclude: [] }
|
||||
: { enableAutoDiscovery: false, include: [], exclude: [] };
|
||||
const jsonTypingOptions = json["typingOptions"];
|
||||
if (jsonTypingOptions) {
|
||||
for (const id in jsonTypingOptions) {
|
||||
if (id === "enableAutoDiscovery") {
|
||||
if (typeof jsonTypingOptions[id] === "boolean") {
|
||||
options.enableAutoDiscovery = jsonTypingOptions[id];
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_typing_option_0, id));
|
||||
}
|
||||
}
|
||||
else if (id === "include") {
|
||||
options.include = convertJsonOptionToStringArray(id, jsonTypingOptions[id], errors);
|
||||
}
|
||||
else if (id === "exclude") {
|
||||
options.exclude = convertJsonOptionToStringArray(id, jsonTypingOptions[id], errors);
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_typing_option_0, id));
|
||||
}
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
||||
export function convertCompilerOptionsFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: CompilerOptions, errors: Diagnostic[] } {
|
||||
const options: CompilerOptions = {};
|
||||
const errors: Diagnostic[] = [];
|
||||
const options = convertOptionsFromJson<CompilerOptions>(optionDeclarations, jsonOptions, basePath, configFileName, errors);
|
||||
|
||||
if (configFileName && getBaseFileName(configFileName) === "jsconfig.json") {
|
||||
if (configFileName && getBaseFileName(configFileName) === "jsconfig.json" && typeof options.allowJs === "undefined") {
|
||||
options.allowJs = true;
|
||||
}
|
||||
|
||||
return { options, errors };
|
||||
}
|
||||
|
||||
function convertOptionsFromJson<T extends CompilerOptions | TypingOptions>(optionDeclarations: CommandLineOption[], jsonOptions: any, basePath: string, configFileName: string, errors: Diagnostic[]): T {
|
||||
const options = {} as T;
|
||||
|
||||
if (!jsonOptions) {
|
||||
return { options, errors };
|
||||
return options;
|
||||
}
|
||||
|
||||
const optionNameMap = arrayToMap(optionDeclarations, opt => opt.name);
|
||||
@@ -666,69 +693,53 @@ namespace ts {
|
||||
for (const id in jsonOptions) {
|
||||
if (hasProperty(optionNameMap, id)) {
|
||||
const opt = optionNameMap[id];
|
||||
const optType = opt.type;
|
||||
let value = jsonOptions[id];
|
||||
const expectedType = typeof optType === "string" ? optType : "string";
|
||||
if (typeof value === expectedType) {
|
||||
if (typeof optType !== "string") {
|
||||
const key = value.toLowerCase();
|
||||
if (hasProperty(optType, key)) {
|
||||
value = optType[key];
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic((<CommandLineOptionOfCustomType>opt).error));
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
if (opt.isFilePath) {
|
||||
switch (typeof value) {
|
||||
case "string":
|
||||
value = normalizePath(combinePaths(basePath, value));
|
||||
break;
|
||||
case "object":
|
||||
// "object" options with 'isFilePath' = true expected to be string arrays
|
||||
value = convertJsonOptionToStringArray(opt.name, value, errors, (element) => normalizePath(combinePaths(basePath, element)));
|
||||
break;
|
||||
}
|
||||
if (value === "") {
|
||||
value = ".";
|
||||
}
|
||||
}
|
||||
options[opt.name] = value;
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, id, expectedType));
|
||||
}
|
||||
options[opt.name] = convertJsonOption(opt, jsonOptions[id], basePath, errors);
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_compiler_option_0, id));
|
||||
}
|
||||
}
|
||||
|
||||
return { options, errors };
|
||||
return options;
|
||||
}
|
||||
|
||||
function convertJsonOptionToStringArray(optionName: string, optionJson: any, errors: Diagnostic[], func?: (element: string) => string): string[] {
|
||||
const items: string[] = [];
|
||||
let invalidOptionType = false;
|
||||
if (!isArray(optionJson)) {
|
||||
invalidOptionType = true;
|
||||
function convertJsonOption(opt: CommandLineOption, value: any, basePath: string, errors: Diagnostic[]): number | string | number[] | string[] {
|
||||
const optType = opt.type;
|
||||
const expectedType = typeof optType === "string" ? optType : "string";
|
||||
if (optType === "list" && isArray(value)) {
|
||||
return convertJsonOptionOfListType(<CommandLineOptionOfListType>opt, value, basePath, errors);
|
||||
}
|
||||
else {
|
||||
for (const element of <any[]>optionJson) {
|
||||
if (typeof element === "string") {
|
||||
const item = func ? func(element) : element;
|
||||
items.push(item);
|
||||
}
|
||||
else {
|
||||
invalidOptionType = true;
|
||||
break;
|
||||
else if (typeof value === expectedType) {
|
||||
if (typeof optType !== "string") {
|
||||
return convertJsonOptionOfCustomType(<CommandLineOptionOfCustomType>opt, value, errors);
|
||||
}
|
||||
else {
|
||||
if (opt.isFilePath) {
|
||||
value = normalizePath(combinePaths(basePath, value));
|
||||
if (value === "") {
|
||||
value = ".";
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
if (invalidOptionType) {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Option_0_should_have_array_of_strings_as_a_value, optionName));
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, opt.name, expectedType));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
function convertJsonOptionOfCustomType(opt: CommandLineOptionOfCustomType, value: string, errors: Diagnostic[]) {
|
||||
const key = value.toLowerCase();
|
||||
if (hasProperty(opt.type, key)) {
|
||||
return opt.type[key];
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(opt.error));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function convertJsonOptionOfListType(option: CommandLineOptionOfListType, values: any[], basePath: string, errors: Diagnostic[]): any[] {
|
||||
return ts.map(values, v => convertJsonOption(option.element, v, basePath, errors));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2444,7 +2444,9 @@ namespace ts {
|
||||
// Do not perform validation of output file name in transpile scenarios
|
||||
/* @internal */ suppressOutputPathCheck?: boolean;
|
||||
|
||||
[option: string]: string | number | boolean | TsConfigOnlyOptions;
|
||||
list?: string[];
|
||||
|
||||
[option: string]: string | number | boolean | TsConfigOnlyOptions | string[] | number[];
|
||||
}
|
||||
|
||||
export interface TypingOptions {
|
||||
@@ -2554,13 +2556,14 @@ namespace ts {
|
||||
type: "object";
|
||||
}
|
||||
|
||||
export interface CommandlineOptionOfListType extends CommandLineOptionBase {
|
||||
type: "list",
|
||||
elementType: Map<number> | "string" | "number";
|
||||
/* @internal */
|
||||
export interface CommandLineOptionOfListType extends CommandLineOptionBase {
|
||||
type: "list";
|
||||
element: CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export type CommandLineOption = CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType | TsConfigOnlyOption | CommandlineOptionOfListType;
|
||||
export type CommandLineOption = CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType | TsConfigOnlyOption | CommandLineOptionOfListType;
|
||||
|
||||
/* @internal */
|
||||
export const enum CharacterCodes {
|
||||
|
||||
Reference in New Issue
Block a user