-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
V2: Typescript Typechecking #3232
Changes from 19 commits
c1982bf
2664b27
6d2274d
dd5544a
93386df
f1c452e
cfd63fc
df26845
c8b5e95
2a991aa
b7037ac
25e97d0
0865ae0
8dd37a3
8064ffe
b42aa83
7736e1e
a4e3d04
d5d25e0
3acab07
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// @flow strict-local | ||
import nullthrows from 'nullthrows'; | ||
import type {AssetRequest, ParcelOptions} from '@parcel/types'; | ||
|
||
import path from 'path'; | ||
import Cache from '@parcel/cache'; | ||
import {resolveConfig} from '@parcel/utils'; | ||
|
||
import type Config from './public/Config'; | ||
import {report} from './ReporterRunner'; | ||
import InternalAsset from './Asset'; | ||
import type {NodeId, ConfigRequest} from './types'; | ||
import {MutableAsset} from './public/Asset'; | ||
import summarizeRequest from './summarizeRequest'; | ||
|
||
export type ValidationOpts = {| | ||
request: AssetRequest, | ||
loadConfig: (ConfigRequest, NodeId) => Promise<Config>, | ||
parentNodeId: NodeId, | ||
options: ParcelOptions | ||
|}; | ||
|
||
export default class Validation { | ||
request: AssetRequest; | ||
configRequests: Array<ConfigRequest>; | ||
loadConfig: ConfigRequest => Promise<Config>; | ||
options: ParcelOptions; | ||
cache: Cache; | ||
impactfulOptions: $Shape<ParcelOptions>; | ||
|
||
constructor({request, loadConfig, parentNodeId, options}: ValidationOpts) { | ||
this.request = request; | ||
this.configRequests = []; | ||
this.loadConfig = configRequest => { | ||
this.configRequests.push(configRequest); | ||
return loadConfig(configRequest, parentNodeId); | ||
}; | ||
this.options = options; | ||
} | ||
|
||
async run(): Promise<void> { | ||
if (this.request.filePath.includes('node_modules')) return; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we just not queue files in node_modules at all? Would avoid crossing the IPC boundary just to do nothing... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was how it was originally but you commented on it to move it to the validatorrunner. Will change it back. Well it wasn't a queue back then... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh.. haha sorry! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. feel free to update in a followup |
||
|
||
report({ | ||
type: 'validation', | ||
request: this.request | ||
}); | ||
|
||
this.cache = new Cache(this.options.outputFS, this.options.cacheDir); | ||
|
||
let asset = await this.loadAsset(); | ||
let configRequest = { | ||
filePath: this.request.filePath, | ||
meta: { | ||
actionType: 'validation' | ||
} | ||
}; | ||
|
||
let config = await this.loadConfig(configRequest); | ||
let parcelConfig = nullthrows(config.result); | ||
|
||
let validators = await parcelConfig.getValidators(this.request.filePath); | ||
for (let validator of validators) { | ||
await validator.validate({ | ||
asset: new MutableAsset(asset), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably shouldn't be mutable for validators There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ow right, this was just copy-paste will change it to Asset |
||
options: this.options, | ||
resolveConfig: (configNames: Array<string>) => | ||
resolveConfig(this.options.inputFS, asset.filePath, configNames) | ||
}); | ||
} | ||
} | ||
|
||
async loadAsset(): Promise<InternalAsset> { | ||
let {filePath, env, code, sideEffects} = this.request; | ||
let {content, size, hash} = await summarizeRequest( | ||
this.options.inputFS, | ||
this.request | ||
); | ||
|
||
return new InternalAsset({ | ||
// If the transformer request passed code rather than a filename, | ||
// use a hash as the base for the id to ensure it is unique. | ||
idBase: code != null ? hash : filePath, | ||
fs: this.options.inputFS, | ||
filePath: filePath, | ||
type: path.extname(filePath).slice(1), | ||
cache: this.cache, | ||
ast: null, | ||
content, | ||
hash, | ||
env: env, | ||
stats: { | ||
time: 0, | ||
size | ||
}, | ||
sideEffects: sideEffects | ||
}); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the parentNodeId is provided so the config requests can attach themselves to the asset request node, so that if any of the config requests are invalidated, the asset request will be invalidated. Seems like if the typescript config changes, it would trigger the transformation to run again. Something like typescript config changing might warrant the transformation running again, but not something like eslintrc. Not sure if it's a huge issue because if the relevant config for a transformation doesn't change we'll just pick up from the cache instead of running the transformers. Would be better if we could figure out a way to not trigger all of that though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I completely understand? Currently validation isn't really cacheable and should run in each subsequent build no matter if there is cache available. Unless we'd figure out a way to return the errors/warnings instead of letting the validator throw them?
I just copied the request format from transforms, wasn't sure what most of it was used for but it's all being used somewhere afaik
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
loadConfig
function is passed in from the main process so that the results can be stored in the graph for both a faster retrieval when asking for that same config again and also so that the transformation can be invalidated when the config is invalidated. I was thinking that validator plugins would be usingloadConfig
as well since it was being passed in, but it looks like it is only being used for loading parcel config right now. If validator plugins were using it the way it is now, then a change in their config would invalidate the transformation causing it to run again. The configs actually used in the transformation wouldn't change though, so it would just end up using what it found in the cache.Ideally validator and other plugins besides transformers should be using
loadConfig
, so that we can avoid rework of resolving configs between processes and so that we don't have to quit the process when we change configs. It would be a little weird if you only had to restart parcel when you change certain types of configs.How I would see this working for validation would probably be something like the
RequestGraph
having an additional node type for avalidation_request
. It would be invalidated if the original file changes, the validator plugins change, or any config the plugins used change. This way changes to transformer plugins/config wouldn't trigger validations and vice versa.