Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 15 additions & 16 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7749,17 +7749,17 @@ namespace ts {

context.pragmas = createMap() as PragmaMap;
for (const pragma of pragmas) {
if (context.pragmas.has(pragma!.name)) { // TODO: GH#18217
const currentValue = context.pragmas.get(pragma!.name);
if (context.pragmas.has(pragma.name)) {
const currentValue = context.pragmas.get(pragma.name);
if (currentValue instanceof Array) {
currentValue.push(pragma!.args);
currentValue.push(pragma.args);
}
else {
context.pragmas.set(pragma!.name, [currentValue, pragma!.args]);
context.pragmas.set(pragma.name, [currentValue, pragma.args]);
}
continue;
}
context.pragmas.set(pragma!.name, pragma!.args);
context.pragmas.set(pragma.name, pragma.args);
}
}

Expand All @@ -7783,9 +7783,8 @@ namespace ts {
const typeReferenceDirectives = context.typeReferenceDirectives;
const libReferenceDirectives = context.libReferenceDirectives;
forEach(toArray(entryOrList), (arg: PragmaPseudoMap["reference"]) => {
// TODO: GH#18217
const { types, lib, path } = arg!.arguments;
if (arg!.arguments["no-default-lib"]) {
const { types, lib, path } = arg.arguments;
if (arg.arguments["no-default-lib"]) {
context.hasNoDefaultLib = true;
}
else if (types) {
Expand All @@ -7798,41 +7797,41 @@ namespace ts {
referencedFiles.push({ pos: path.pos, end: path.end, fileName: path.value });
}
else {
reportDiagnostic(arg!.range.pos, arg!.range.end - arg!.range.pos, Diagnostics.Invalid_reference_directive_syntax);
reportDiagnostic(arg.range.pos, arg.range.end - arg.range.pos, Diagnostics.Invalid_reference_directive_syntax);
}
});
break;
}
case "amd-dependency": {
context.amdDependencies = map(
toArray(entryOrList),
(x: PragmaPseudoMap["amd-dependency"]) => ({ name: x!.arguments.name!, path: x!.arguments.path })); // TODO: GH#18217
(x: PragmaPseudoMap["amd-dependency"]) => ({ name: x.arguments.name, path: x.arguments.path }));
break;
}
case "amd-module": {
if (entryOrList instanceof Array) {
for (const entry of entryOrList) {
if (context.moduleName) {
// TODO: It's probably fine to issue this diagnostic on all instances of the pragma
reportDiagnostic(entry!.range.pos, entry!.range.end - entry!.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments);
reportDiagnostic(entry.range.pos, entry.range.end - entry.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments);
}
context.moduleName = (entry as PragmaPseudoMap["amd-module"])!.arguments.name;
context.moduleName = (entry as PragmaPseudoMap["amd-module"]).arguments.name;
}
}
else {
context.moduleName = (entryOrList as PragmaPseudoMap["amd-module"])!.arguments.name;
context.moduleName = (entryOrList as PragmaPseudoMap["amd-module"]).arguments.name;
}
break;
}
case "ts-nocheck":
case "ts-check": {
// _last_ of either nocheck or check in a file is the "winner"
forEach(toArray(entryOrList), entry => {
if (!context.checkJsDirective || entry!.range.pos > context.checkJsDirective.pos) { // TODO: GH#18217
if (!context.checkJsDirective || entry.range.pos > context.checkJsDirective.pos) {
context.checkJsDirective = {
enabled: key === "ts-check",
end: entry!.range.end,
pos: entry!.range.pos
end: entry.range.end,
pos: entry.range.pos
};
}
});
Expand Down
48 changes: 20 additions & 28 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5950,26 +5950,18 @@ namespace ts {
/* @internal */
export interface PragmaDefinition<T1 extends string = string, T2 extends string = string, T3 extends string = string, T4 extends string = string> {
args?:
| [PragmaArgumentSpecification<T1>]
| [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>]
| [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>]
| [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>, PragmaArgumentSpecification<T4>];
| readonly [PragmaArgumentSpecification<T1>]
| readonly [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>]
| readonly [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>]
| readonly [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>, PragmaArgumentSpecification<T4>];
// If not present, defaults to PragmaKindFlags.Default
kind?: PragmaKindFlags;
}

/**
* This function only exists to cause exact types to be inferred for all the literals within `commentPragmas`
*/
/* @internal */
function _contextuallyTypePragmas<T extends {[name: string]: PragmaDefinition<K1, K2, K3, K4>}, K1 extends string, K2 extends string, K3 extends string, K4 extends string>(args: T): T {
return args;
}

// While not strictly a type, this is here because `PragmaMap` needs to be here to be used with `SourceFile`, and we don't
// fancy effectively defining it twice, once in value-space and once in type-space
/* @internal */
export const commentPragmas = _contextuallyTypePragmas({
export const commentPragmas = {
"reference": {
args: [
{ name: "types", optional: true, captureSpan: true },
Expand Down Expand Up @@ -5997,7 +5989,7 @@ namespace ts {
args: [{ name: "factory" }],
kind: PragmaKindFlags.MultiLine
},
});
} as const;

/* @internal */
type PragmaArgTypeMaybeCapture<TDesc> = TDesc extends {captureSpan: true} ? {value: string, pos: number, end: number} : string;
Expand All @@ -6008,29 +6000,29 @@ namespace ts {
? {[K in TName]?: PragmaArgTypeMaybeCapture<TDesc>}
: {[K in TName]: PragmaArgTypeMaybeCapture<TDesc>};

/* @internal */
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;

/* @internal */
type ArgumentDefinitionToFieldUnion<T extends readonly PragmaArgumentSpecification<any>[]> = {
[K in keyof T]: PragmaArgTypeOptional<T[K], T[K] extends {name: infer TName} ? TName extends string ? TName : never : never>
}[Extract<keyof T, number>]; // The mapped type maps over only the tuple members, but this reindex gets _all_ members - by extracting only `number` keys, we get only the tuple members

/**
* Maps a pragma definition into the desired shape for its arguments object
* Maybe the below is a good argument for types being iterable on struture in some way.
*/
/* @internal */
type PragmaArgumentType<T extends PragmaDefinition> =
T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>, PragmaArgumentSpecification<infer TName3>, PragmaArgumentSpecification<infer TName4>] }
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2> & PragmaArgTypeOptional<T["args"][2], TName3> & PragmaArgTypeOptional<T["args"][2], TName4>
: T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>, PragmaArgumentSpecification<infer TName3>] }
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2> & PragmaArgTypeOptional<T["args"][2], TName3>
: T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>] }
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2>
: T extends { args: [PragmaArgumentSpecification<infer TName>] }
? PragmaArgTypeOptional<T["args"][0], TName>
: object;
// The above fallback to `object` when there's no args to allow `{}` (as intended), but not the number 2, for example
// TODO: Swap to `undefined` for a cleaner API once strictNullChecks is enabled
type PragmaArgumentType<KPrag extends keyof ConcretePragmaSpecs> =
ConcretePragmaSpecs[KPrag] extends { args: readonly PragmaArgumentSpecification<any>[] }
? UnionToIntersection<ArgumentDefinitionToFieldUnion<ConcretePragmaSpecs[KPrag]["args"]>>
: never;

/* @internal */
type ConcretePragmaSpecs = typeof commentPragmas;

/* @internal */
export type PragmaPseudoMap = {[K in keyof ConcretePragmaSpecs]?: {arguments: PragmaArgumentType<ConcretePragmaSpecs[K]>, range: CommentRange}};
export type PragmaPseudoMap = {[K in keyof ConcretePragmaSpecs]: {arguments: PragmaArgumentType<K>, range: CommentRange}};

/* @internal */
export type PragmaPseudoMapEntry = {[K in keyof PragmaPseudoMap]: {name: K, args: PragmaPseudoMap[K]}}[keyof PragmaPseudoMap];
Expand Down