@parcel/core
Version:
360 lines (291 loc) • 8.72 kB
JavaScript
// @flow strict-local
import type SourceMap from '@parcel/source-map';
import type {Readable} from 'stream';
import type {FileSystem} from '@parcel/fs';
import type {
Asset as IAsset,
AST,
ASTGenerator,
Dependency as IDependency,
DependencyOptions,
Environment as IEnvironment,
EnvironmentOptions,
FileCreateInvalidation,
FilePath,
Meta,
MutableAsset as IMutableAsset,
Stats,
MutableAssetSymbols as IMutableAssetSymbols,
AssetSymbols as IAssetSymbols,
BundleBehavior,
} from '@parcel/types';
import type {Asset as AssetValue, ParcelOptions} from '../types';
import nullthrows from 'nullthrows';
import Environment from './Environment';
import {getPublicDependency} from './Dependency';
import {AssetSymbols, MutableAssetSymbols} from './Symbols';
import UncommittedAsset from '../UncommittedAsset';
import CommittedAsset from '../CommittedAsset';
import {createEnvironment} from '../Environment';
import {fromProjectPath, toProjectPath} from '../projectPath';
import {
BundleBehavior as BundleBehaviorMap,
BundleBehaviorNames,
} from '../types';
import {toInternalSourceLocation} from '../utils';
const inspect = Symbol.for('nodejs.util.inspect.custom');
const uncommittedAssetValueToAsset: WeakMap<AssetValue, Asset> = new WeakMap();
const committedAssetValueToAsset: WeakMap<AssetValue, Asset> = new WeakMap();
const assetValueToMutableAsset: WeakMap<AssetValue, MutableAsset> =
new WeakMap();
const _assetToAssetValue: WeakMap<
IAsset | IMutableAsset | BaseAsset,
AssetValue,
> = new WeakMap();
const _mutableAssetToUncommittedAsset: WeakMap<
IMutableAsset,
UncommittedAsset,
> = new WeakMap();
export function assetToAssetValue(asset: IAsset | IMutableAsset): AssetValue {
return nullthrows(_assetToAssetValue.get(asset));
}
export function mutableAssetToUncommittedAsset(
mutableAsset: IMutableAsset,
): UncommittedAsset {
return nullthrows(_mutableAssetToUncommittedAsset.get(mutableAsset));
}
export function assetFromValue(
value: AssetValue,
options: ParcelOptions,
): Asset {
return new Asset(
value.committed
? new CommittedAsset(value, options)
: new UncommittedAsset({
value,
options,
}),
);
}
class BaseAsset {
#asset: CommittedAsset | UncommittedAsset;
#query /*: ?URLSearchParams */;
constructor(asset: CommittedAsset | UncommittedAsset) {
this.#asset = asset;
_assetToAssetValue.set(this, asset.value);
}
// $FlowFixMe[unsupported-syntax]
[inspect](): string {
return `Asset(${this.filePath})`;
}
get id(): string {
return this.#asset.value.id;
}
get type(): string {
return this.#asset.value.type;
}
get env(): IEnvironment {
return new Environment(this.#asset.value.env, this.#asset.options);
}
get fs(): FileSystem {
return this.#asset.options.inputFS;
}
get filePath(): FilePath {
return fromProjectPath(
this.#asset.options.projectRoot,
this.#asset.value.filePath,
);
}
get query(): URLSearchParams {
if (!this.#query) {
this.#query = new URLSearchParams(this.#asset.value.query ?? '');
}
return this.#query;
}
get meta(): Meta {
return this.#asset.value.meta;
}
get bundleBehavior(): ?BundleBehavior {
let bundleBehavior = this.#asset.value.bundleBehavior;
return bundleBehavior == null ? null : BundleBehaviorNames[bundleBehavior];
}
get isBundleSplittable(): boolean {
return this.#asset.value.isBundleSplittable;
}
get isSource(): boolean {
return this.#asset.value.isSource;
}
get sideEffects(): boolean {
return this.#asset.value.sideEffects;
}
get symbols(): IAssetSymbols {
return new AssetSymbols(this.#asset.options, this.#asset.value);
}
get uniqueKey(): ?string {
return this.#asset.value.uniqueKey;
}
get astGenerator(): ?ASTGenerator {
return this.#asset.value.astGenerator;
}
get pipeline(): ?string {
return this.#asset.value.pipeline;
}
getDependencies(): $ReadOnlyArray<IDependency> {
return this.#asset
.getDependencies()
.map(dep => getPublicDependency(dep, this.#asset.options));
}
getCode(): Promise<string> {
return this.#asset.getCode();
}
getBuffer(): Promise<Buffer> {
return this.#asset.getBuffer();
}
getStream(): Readable {
return this.#asset.getStream();
}
getMap(): Promise<?SourceMap> {
return this.#asset.getMap();
}
getAST(): Promise<?AST> {
return this.#asset.getAST();
}
getMapBuffer(): Promise<?Buffer> {
return this.#asset.getMapBuffer();
}
}
export class Asset extends BaseAsset implements IAsset {
#asset /*: CommittedAsset | UncommittedAsset */;
#env /*: ?Environment */;
constructor(asset: CommittedAsset | UncommittedAsset): Asset {
let assetValueToAsset = asset.value.committed
? committedAssetValueToAsset
: uncommittedAssetValueToAsset;
let existing = assetValueToAsset.get(asset.value);
if (existing != null) {
return existing;
}
super(asset);
this.#asset = asset;
assetValueToAsset.set(asset.value, this);
return this;
}
get env(): IEnvironment {
this.#env ??= new Environment(this.#asset.value.env, this.#asset.options);
return this.#env;
}
get stats(): Stats {
return this.#asset.value.stats;
}
}
export class MutableAsset extends BaseAsset implements IMutableAsset {
#asset /*: UncommittedAsset */;
constructor(asset: UncommittedAsset): MutableAsset {
let existing = assetValueToMutableAsset.get(asset.value);
if (existing != null) {
return existing;
}
super(asset);
this.#asset = asset;
assetValueToMutableAsset.set(asset.value, this);
_mutableAssetToUncommittedAsset.set(this, asset);
return this;
}
setMap(map: ?SourceMap): void {
this.#asset.setMap(map);
}
get type(): string {
return this.#asset.value.type;
}
set type(type: string): void {
if (type !== this.#asset.value.type) {
this.#asset.value.type = type;
this.#asset.updateId();
}
}
get bundleBehavior(): ?BundleBehavior {
let bundleBehavior = this.#asset.value.bundleBehavior;
return bundleBehavior == null ? null : BundleBehaviorNames[bundleBehavior];
}
set bundleBehavior(bundleBehavior: ?BundleBehavior): void {
this.#asset.value.bundleBehavior = bundleBehavior
? BundleBehaviorMap[bundleBehavior]
: null;
}
get isBundleSplittable(): boolean {
return this.#asset.value.isBundleSplittable;
}
set isBundleSplittable(isBundleSplittable: boolean): void {
this.#asset.value.isBundleSplittable = isBundleSplittable;
}
get sideEffects(): boolean {
return this.#asset.value.sideEffects;
}
set sideEffects(sideEffects: boolean): void {
this.#asset.value.sideEffects = sideEffects;
}
get uniqueKey(): ?string {
return this.#asset.value.uniqueKey;
}
set uniqueKey(uniqueKey: ?string): void {
if (this.#asset.value.uniqueKey != null) {
throw new Error(
"Cannot change an asset's uniqueKey after it has been set.",
);
}
this.#asset.value.uniqueKey = uniqueKey;
}
get symbols(): IMutableAssetSymbols {
return new MutableAssetSymbols(this.#asset.options, this.#asset.value);
}
addDependency(dep: DependencyOptions): string {
return this.#asset.addDependency(dep);
}
invalidateOnFileChange(filePath: FilePath): void {
this.#asset.invalidateOnFileChange(
toProjectPath(this.#asset.options.projectRoot, filePath),
);
}
invalidateOnFileCreate(invalidation: FileCreateInvalidation): void {
this.#asset.invalidateOnFileCreate(invalidation);
}
invalidateOnEnvChange(env: string): void {
this.#asset.invalidateOnEnvChange(env);
}
invalidateOnStartup(): void {
this.#asset.invalidateOnStartup();
}
invalidateOnBuild(): void {
this.#asset.invalidateOnBuild();
}
isASTDirty(): boolean {
return this.#asset.isASTDirty;
}
setBuffer(buffer: Buffer): void {
this.#asset.setBuffer(buffer);
}
setCode(code: string): void {
this.#asset.setCode(code);
}
setStream(stream: Readable): void {
this.#asset.setStream(stream);
}
setAST(ast: AST): void {
return this.#asset.setAST(ast);
}
addURLDependency(url: string, opts: $Shape<DependencyOptions>): string {
return this.addDependency({
specifier: url,
specifierType: 'url',
priority: 'lazy',
...opts,
});
}
setEnvironment(env: EnvironmentOptions): void {
this.#asset.value.env = createEnvironment({
...env,
loc: toInternalSourceLocation(this.#asset.options.projectRoot, env.loc),
});
this.#asset.updateId();
}
}