Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for tsconfig.json files #1692

Merged
merged 14 commits into from
Jan 21, 2015
Merged

Support for tsconfig.json files #1692

merged 14 commits into from
Jan 21, 2015

Conversation

ahejlsberg
Copy link
Member

This PR implements #1667 with some modifications.

The presence of a tsconfig.json file in a directory indicates that the directory is the root of a TypeScript project. The tsconfig.json file specifies the root files and the compiler options required to compile the project. A project is compiled in one of the following ways:

  • By invoking tsc with no input files, in which case the compiler searches for the tsconfig.json file starting in the current directory and continuing up the parent directory chain.
  • By invoking tsc with no input files and a -project (or just -p) command line option that specifies the path of a directory containing a tsconfig.json file.

When input files are specified on the command line, tsconfig.json files are ignored.

An example tsconfig.json file:

{
    "compilerOptions": {
        "module": "commonjs",
        "noImplicitAny": true,
        "removeComments": true,
        "preserveConstEnums": true,
        "out": "../../built/local/tsc.js",
        "sourceMap": true,
    },
    "files": [
        "core.ts",
        "sys.ts",
        "types.ts",
        "scanner.ts",
        "parser.ts",
        "utilities.ts",
        "binder.ts",
        "checker.ts",
        "emitter.ts",
        "program.ts",
        "commandLineParser.ts",
        "tsc.ts",
        "diagnosticInformationMap.generated.ts"
    ]
}

The "compilerOptions" property can be omitted, in which case the compiler's defaults are used.

If no "files" property is present in a tsconfig.json, the compiler defaults to including all files the containing directory and subdirectories. When a "files" property is specified, only those files are included.

A tsconfig.json file is permitted to be completely empty, which compiles all files in the containing directory and subdirectories with the default compiler options.

Compiler options specified on the command line override those specified in the tsconfig.json file.

@Arnavion
Copy link
Contributor

This allows watch as a compiler option in the file. Should it be ignored?

When input files are specified on the command line, tsconfig.json files are ignored.

Why is the entire file ignored instead of just the files section? It would be useful to partially compile a project by specifying individual files, but using the compiler options specified in the project file.

@ahejlsberg
Copy link
Member Author

@Arnavion I agree, we should probably disallow watch in tsconfig.json. Same for project which only makes sense on the command line.

Regarding your second question, I'd like to do what you suggest, but I wonder about this scenario: Say you have directories c:\src\foo and c:\src\bar, each containing a tsconfig.json, and that the current directory is c:\src\foo. Now if you say tsc c:\src\bar\somefile.ts we'd compile a file from the c:\src\bar project with the options of the c:\src\foo project. This may be just fine, but perhaps also confusing.

@Arnavion
Copy link
Contributor

That makes sense. You could expect it to use the tsconfig.json based on the file being compiled (c:\src\bar\tsconfig.json), but then that won't work if you wanted to compile files from both directories with the same commandline. Compiling with the tsconfig.json based on the current directory would be deterministic but, as you said, not intuitive either.

One alternative is:

  • For each file, find the tsconfig.json relative to it (the same directory-tree-climbing algorithm as now).
  • If all files map to a single project file, use it.
  • Else print an error ("Multiple project files found. Please specify one with -p") and abort.

It'll probably be more common for all the individual files being compiled to be in the same project, so this approach would allow them to be compiled with that project file. On the other hand it's more complicated, and expensive if the files are in multiple directories.

Then again, this might not even be really necessary. The use case I was imagining was that someone makes a change to only a few files of a large project and wants to recompile those files, but perhaps they'd be okay with just compiling the whole project every time. Or they could use automation like tsc -watch, watchify, etc. to only compile the changed files.

I guess the current behavior is fine.

@NoelAbrahams
Copy link

@ahejlsberg

When a "files" property is specified, only those files are included.

I am thinking why would anyone want to have .ts files in a directory and not have them compiled?

Perhaps an "exclude": [ "foo/bar.ts" ] would make more sense?

@dbaeumer
Copy link
Member

+1 for the exclude behavior.

One question: can I combine regular command line options with the -p option E.g. tsc -p src -module "commonjs"

If you share code between the browser and nodejs and you need to compile the code once for commonjs and once for amd it would make sense to only maintain one tsconfig.json file.

@ahejlsberg
Copy link
Member Author

@NoelAbrahams I think there are two important scenarios: (1) Let me drop an empty tsconfig.json file in a directory and have everything in there be a project, and (2) let me describe the exact list of files I want included. The current design covers both with a minimum of complexity. That said, I can certainly see how an "exclude" list could be useful, although I suspect we'd then need globbing as well, so the level of complexity goes up. I definitely don't want this growing into an alternate build system. The intent is more to offer tools (e.g. editors) a simple and deterministic way to decide what the compilation context for a particular file is.

@dbaeumer Yes, you can combine other command line options with -p.

@fdecampredon
Copy link

I think there are two important scenarios: (1) Let me drop an empty tsconfig.json file in a directory and have everything in there be a project, and (2) let me describe the exact list of files I want included. The current design covers both with a minimum of complexity. That said, I can certainly see how an "exclude" list could be useful, although I suspect we'd then need globbing as well, so the level of complexity goes up. I definitely don't want this growing into an alternate build system. The intent is more to offer tools (e.g. editors) a simple and deterministic way to decide what the compilation context for a particular file is.

Honestly if your target is editor I would prefer that this feature never make it to master. If those configuration files are implemented, I will have to support them, if I want to offer more complex configuration mechanisms, I will have to support another config file and figure when a file configuration has precedence over another.
Build/project configuration has always be a topic where everyone make its own sauce, the amazing number of build/lint/configuration tools is a good example of that.
I don't clearly see the value of those tsconfig.json file over storing the command line in simple bash script, however I'm pretty much sure they will give me headache when I'll have to decide how I should integrate them.

@basarat
Copy link
Contributor

basarat commented Jan 18, 2015

I agree with @fdecampredon that this PR might not be a good idea for IDE developers. Nevertheless

Perhaps an "exclude": [ "foo/bar.ts" ] would make more sense?

No. Better to have !foo/bar.ts included in files than to add another option to the root. If this PR does get merged I would as a second step recommend making files support the entire glob/minmatch/regexp syntax common in JavaScript build tools. Having a custom hacked exclude option would just be painful to allow that next step. You would pretty soon want to do exclude: node_modules/**/*.

@Arnavion
Copy link
Contributor

@basarat Anders mentioned that already:

That said, I can certainly see how an "exclude" list could be useful, although I suspect we'd then need globbing as well, so the level of complexity goes up.

The problem with supporting globbing is that it needs to be an own-implementation, since tsc can't rely on node modules. This is why the previous PR for wildcards was abandoned.

@basarat
Copy link
Contributor

basarat commented Jan 18, 2015

@Arnavion sorry. Thanks!

@NoelAbrahams
Copy link

What's wrong with exclude: [ node_modules/**/*]? That's what people do already with .gitignore. I'm not suggesting that exclude be another option, rather it should be the only option. There's no real need for files. A directory already adequately describes that.

As I see it:

  • Use the file system to describe the project structure
  • Use .gitignore (or equivalent) to share that structure amongst your team
  • Use tsconfig.json to build the project structure

@ahejlsberg
Copy link
Member Author

@NoelAbrahams There are actually two very real needs for files:

  • It allows you to specify a file ordering, which matters in projects that use -out.
  • It allows you to reference files outside this directory tree. This is particularly important for referencing declarations files.

Yes, you can cover those with /// <reference /> but a lot of folks don't like putting those in their programs.

@NoelAbrahams
Copy link

@ahejlsberg, Ah! I failed to spot the potential for including references.

The only objection I have is to the following:

When a "files" property is specified, only those files are included.

In the project structure we have, all files are included in the compilation, including subdirectories.

But certainly, I would like to see ordering and referencing to be part of this.

@DanielRosenwasser
Copy link
Member

@ahejlsberg, this fails hard if you have a loop in your file system and "files" isn't specified.

compiler Daniel$ ln -s uhoh .
compiler Daniel$ node ../../built/local/tsc.js

fs.js:689
  return binding.stat(pathModule._makeLong(path));
                 ^
Error: ELOOP, too many symbolic links encountered 'uhoh'
    at Object.fs.statSync (fs.js:689:18)
    at visitDirectory (/Users/Daniel/TypeScript/built/local/tsc.js:1334:40)
    at Object.readDirectory (/Users/Daniel/TypeScript/built/local/tsc.js:1327:17)
    at getFiles (/Users/Daniel/TypeScript/built/local/tsc.js:20219:39)
    at Object.parseConfigFile (/Users/Daniel/TypeScript/built/local/tsc.js:20167:24)
    at Object.executeCommandLine (/Users/Daniel/TypeScript/built/local/tsc.js:20389:40)
    === Snip ===

This is mostly a problem if we let others consume this functionality.

@NoelAbrahams
Copy link

Just to clarify my point above. We would like to make use of the external file reference and ordering feature introduced by files, but then we're also forced to include the files that need to be compiled, because one cannot have one without the other as it stands.

This introduces a maintenance problem: every time a new file is added or an existing file deleted tsconfig.json needs to be modified; and there is danger of files being inadvertently excluded from compilation.

If this change is accompanied by associated changes to the tooling (i.e. in Visual Studio for instance the "Add file" feature should automatically update tsconfig.json) then that should be fine.

@basarat
Copy link
Contributor

basarat commented Jan 19, 2015

@NoelAbrahams perhaps solvable by a third party tool :

support a files-expansion:['!somefile','must/include/**/*.ts'] sort of transform inside tsconfig.json which will expand the files member.

@NoelAbrahams
Copy link

@basarat, that is an option.

But I would prefer the syntax be simple. We expect to have 40+ tsconfig.json files and things may get out of hand.

Perhaps "files": [*] as a shortcut to include all files in the current directory and all subdirectories.

@basarat
Copy link
Contributor

basarat commented Jan 19, 2015

Perhaps "files": [*] as a shortcut to include all files in the current directory and all subdirectories.

@NoelAbrahams isn't this already take care of by (see original PR comments):

If no "files" property is present in a tsconfig.json, the compiler defaults to including all files the containing directory and subdirectories.

@basarat
Copy link
Contributor

basarat commented Jan 21, 2015

🎉 🎊

@mhegazy
Copy link
Contributor

mhegazy commented Jan 21, 2015

@basarat we would interested to hear how grunt-TS would be using this and if there are any changes on the compiler side you would need

@lcorneliussen
Copy link

Any information yet in which release this will be available? (incl. VS-support?)

@ahejlsberg
Copy link
Member Author

This will be in the 1.5 release. Not sure yet what level of VS support we'll have in that release.

@madskristensen
Copy link

I've added a JSON Schema for this format on http://json.schemastore.org/tsconfig

@basarat
Copy link
Contributor

basarat commented Mar 25, 2015

@madskristensen
Copy link

@basarat Awesome. Thanks. Are you sure all those options are supported in tsconfig.json files too? Where's the official documentation for these options so I can get the proper description text?

@basarat
Copy link
Contributor

basarat commented Mar 25, 2015

Are you sure all those options are supported in tsconfig.json files too

I assumed so. Considering they added watch to tsconfig.json as well #2222 (which I think might be a bad idea but nonetheless).

Pinging @mhegazy for an exact answer.

Where's the official documentation for these options so I can get the proper description text

Your best bet : for an up to date list: https://github.com/Microsoft/TypeScript/blob/master/src/compiler/commandLineParser.ts#L7-L175

@madskristensen
Copy link

Thanks for the link to the commandLineParser.ts for the definitions. I've updated the schema to reflect the entire list of options. http://json.schemastore.org/tsconfig

@mhegazy
Copy link
Contributor

mhegazy commented Mar 25, 2015

thanks @madskristensen, experimental switches are not guaranteed to work, and can be removed. so i would not add them to the schema.

@madskristensen
Copy link

Thanks, I've removed the experimental options

@ladaltamirano
Copy link

Is

files:['./someDirectory/'] ( == files:['someDirectory/'] )

equivalent to

files:['./someDirectory/**/*.ts']

?
If not so, could you add support for this? I wouldn't like compiler to waste time looking into /bower_components/ or /node_modules/ folders, meaning that I'd like to "easily" specify the folders to include in the project...

(* Function Definition *)
function Salute(): string;
var
   (* mmm... none... *)
begin
   writeln( 'Thank you :)');
end;

@basarat
Copy link
Contributor

basarat commented Apr 13, 2015

equivalent to

No. It must point to a file. No gobbing support yet.

Requested here : #1927

@srackham
Copy link

srackham commented May 5, 2015

Is there a reason that the --rootDir tsc command option is not included in the tsconfig.json schema? I'm using 1.5.0-beta.

@mhegazy
Copy link
Contributor

mhegazy commented May 5, 2015

@srackham we have not updated the schema yet.. will look into it. thanks for reporting this. filed #3046 to get it fixed.

@ghost
Copy link

ghost commented Jun 9, 2015

I think it's a bit silly to disallow globs because a small percentage of use-cases would not work, when the majority of use-cases need it.

@httpete
Copy link

httpete commented Jul 15, 2015

The use for filesGlob is so great - to do exclusions of the node_modules and other dirs, which cause tsc to choike. VSCode is crippled without this.

@mhegazy
Copy link
Contributor

mhegazy commented Jul 24, 2015

More details can be found at: https://github.com/Microsoft/TypeScript/wiki/tsconfig.json

@matthew-dean
Copy link

sigh I wish that:

a) The web community would unify on adopting a .config directory in the root of a project to store this eve-expanding list of config files.
b) Config file definitions could be unified into a standard format. Why can't it just be config.json, with a definition specific for TypeScript, like package.json? And then Sass, Less, and others could all define their respective config.json settings (or alternatively, .config/config.json), that an IDE could import?

I think it's really unfortunate this idea was implemented in this way. 😢

@nojvek
Copy link
Contributor

nojvek commented Dec 10, 2015

Isn't that what the.{file} notation is for. Files that are hidden and special.What's wrong with having .gitignore, .vscode, .tsconfig. they all target different purposes.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.