Skip to content

Commit 6f05b40

Browse files
arielshaqeddomoritz
authored andcommitted
Add --include flag: further limits files from tsconfig.json. (YousefED#211)
* Add --include flag: further limits files from tsconfig.json. In a large project, it is slow and not needed to extract schemata from all TypeScript files in `tsconfig.json` (also it can be infeasible due to limitations of what can be converted to JSON schema). OTOH listing the files as the command-line argument ignores all the parameters from `tsconfig.json`. `--include` gets us the advantages of both. Tests for --include flag (and programFromConfig). (PR ready: no generated files). * Document --include flag. * Fix lint error. * Update README.md
1 parent 3f68c8e commit 6f05b40

10 files changed

+71
-5
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ test/*.d.ts
44
test/*.map
55
.vscode/*.*
66
npm-debug.log
7-
.idea
7+
.idea
8+
*~
9+
.#*

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ Generate json-schemas from your Typescript sources.
1616
* Install with `npm install typescript-json-schema -g`
1717
* Generate schema from a typescript type: `typescript-json-schema project/directory/tsconfig.json TYPE`
1818

19+
To generate files for only _some_ types in `tsconfig.json` specify
20+
filenames or globs with the `--include` option. This is especially useful for large projects.
21+
1922
In case no `tsconfig.json` is available for your project, you can directly specify the .ts files (this in this case we use some built-in compiler presets):
2023

2124
* Generate schema from a typescript type: `typescript-json-schema "project/directory/**/*.ts" TYPE`
@@ -38,6 +41,7 @@ Options:
3841
--useTypeOfKeyword Use `typeOf` keyword (https://goo.gl/DC6sni) for functions. [boolean] [default: false]
3942
--out, -o The output file, defaults to using stdout
4043
--validationKeywords Provide additional validation keywords to include [array] [default: []]
44+
--include Further limit tsconfig to include only matching files [array] [default: []]
4145
--ignoreErrors Generate even if the program has errors. [boolean] [default: false]
4246
--excludePrivate Exclude private members from the schema [boolean] [default: false]
4347
```

test/programs/tsconfig/exclude.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// This file is ignored.
2+
3+
export interface Excluded {
4+
a: string;
5+
}
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// This file is included by tsconfig.json and --include.
2+
3+
export interface IncludedAlways {
4+
a: string;
5+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// This file is included by tsconfig.json.
2+
3+
export interface IncludedOnlyByTsConfig {
4+
a: string;
5+
};

test/programs/tsconfig/tsconfig.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es5",
4+
},
5+
"include": [
6+
"**/include*.ts",
7+
]
8+
}

test/schema.test.ts

+27
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,30 @@ describe("schema", () => {
243243
assertSchema("builtin-names", "Ext.Foo");
244244
});
245245
});
246+
247+
describe("tsconfig.json", () => {
248+
it("should read files from tsconfig.json", () => {
249+
const program = TJS.programFromConfig(resolve(BASE + "tsconfig/tsconfig.json"));
250+
const generator = TJS.buildGenerator(program);
251+
assert(generator !== null);
252+
assert.instanceOf(generator, TJS.JsonSchemaGenerator);
253+
if (generator !== null) {
254+
assert.doesNotThrow(() => generator.getSchemaForSymbol("IncludedAlways"));
255+
assert.doesNotThrow(() => generator.getSchemaForSymbol("IncludedOnlyByTsConfig"));
256+
assert.throws(() => generator.getSchemaForSymbol("Excluded"));
257+
}
258+
});
259+
it("should support includeOnlyFiles with tsconfig.json", () => {
260+
const program = TJS.programFromConfig(
261+
resolve(BASE + "tsconfig/tsconfig.json"), [resolve(BASE + "tsconfig/includedAlways.ts")]
262+
);
263+
const generator = TJS.buildGenerator(program);
264+
assert(generator !== null);
265+
assert.instanceOf(generator, TJS.JsonSchemaGenerator);
266+
if (generator !== null) {
267+
assert.doesNotThrow(() => generator.getSchemaForSymbol("IncludedAlways"));
268+
assert.throws(() => generator.getSchemaForSymbol("Excluded"));
269+
assert.throws(() => generator.getSchemaForSymbol("IncludedOnlyByTsConfig"));
270+
}
271+
});
272+
});

typescript-json-schema-cli.ts

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ export function run() {
3232
.describe("out", "The output file, defaults to using stdout")
3333
.array("validationKeywords").default("validationKeywords", defaultArgs.validationKeywords)
3434
.describe("validationKeywords", "Provide additional validation keywords to include.")
35+
.array("include").default("*", defaultArgs.include)
36+
.describe("include", "Further limit tsconfig to include only matching files.")
3537
.argv;
3638

3739
exec(args._[0], args._[1], {
@@ -48,6 +50,7 @@ export function run() {
4850
ignoreErrors: args.ignoreErrors,
4951
out: args.out,
5052
validationKeywords: args.validationKeywords,
53+
include: args.include,
5154
excludePrivate: args.excludePrivate,
5255
});
5356
}

typescript-json-schema.d.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export declare type Args = {
1818
ignoreErrors: boolean;
1919
out: string;
2020
validationKeywords: string[];
21+
include: string[];
2122
excludePrivate: boolean;
2223
};
2324
export declare type PartialArgs = Partial<Args>;
@@ -90,5 +91,5 @@ export declare class JsonSchemaGenerator {
9091
export declare function getProgramFromFiles(files: string[], jsonCompilerOptions?: any, basePath?: string): ts.Program;
9192
export declare function buildGenerator(program: ts.Program, args?: PartialArgs): JsonSchemaGenerator | null;
9293
export declare function generateSchema(program: ts.Program, fullTypeName: string, args?: PartialArgs, onlyIncludeFiles?: string[]): Definition | null;
93-
export declare function programFromConfig(configFileName: string): ts.Program;
94+
export declare function programFromConfig(configFileName: string, onlyIncludeFiles?: string[]): ts.Program;
9495
export declare function exec(filePattern: string, fullTypeName: string, args?: Args): void;

typescript-json-schema.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export function getDefaultArgs(): Args {
2626
ignoreErrors: false,
2727
out: "",
2828
validationKeywords: [],
29+
include: [],
2930
excludePrivate: false,
3031
};
3132
}
@@ -48,6 +49,7 @@ export type Args = {
4849
ignoreErrors: boolean;
4950
out: string;
5051
validationKeywords: string[];
52+
include: string[];
5153
excludePrivate: boolean;
5254
};
5355

@@ -1083,7 +1085,7 @@ export function generateSchema(program: ts.Program, fullTypeName: string, args:
10831085
}
10841086
}
10851087

1086-
export function programFromConfig(configFileName: string): ts.Program {
1088+
export function programFromConfig(configFileName: string, onlyIncludeFiles?: string[]): ts.Program {
10871089
// basically a copy of https://github.com/Microsoft/TypeScript/blob/3663d400270ccae8b69cbeeded8ffdc8fa12d7ad/src/compiler/tsc.ts -> parseConfigFile
10881090
const result = ts.parseConfigFileTextToJson(configFileName, ts.sys.readFile(configFileName)!);
10891091
const configObject = result.config;
@@ -1096,7 +1098,7 @@ export function programFromConfig(configFileName: string): ts.Program {
10961098
delete options.outFile;
10971099
delete options.declaration;
10981100

1099-
const program = ts.createProgram(configParseResult.fileNames, options);
1101+
const program = ts.createProgram(onlyIncludeFiles || configParseResult.fileNames, options);
11001102
return program;
11011103
}
11021104

@@ -1111,7 +1113,11 @@ export function exec(filePattern: string, fullTypeName: string, args = getDefaul
11111113
let program: ts.Program;
11121114
let onlyIncludeFiles: string[] | undefined = undefined;
11131115
if (REGEX_TSCONFIG_NAME.test(path.basename(filePattern))) {
1114-
program = programFromConfig(filePattern);
1116+
if (args.include.length > 0) {
1117+
const globs: string[][] = args.include.map(f => glob.sync(f));
1118+
onlyIncludeFiles = ([] as string[]).concat(...globs).map(normalizeFileName);
1119+
}
1120+
program = programFromConfig(filePattern, onlyIncludeFiles);
11151121
} else {
11161122
onlyIncludeFiles = glob.sync(filePattern);
11171123
program = getProgramFromFiles(onlyIncludeFiles, {

0 commit comments

Comments
 (0)