Skip to content

Commit a51f0bf

Browse files
committed
added relaxed emit rules for separate compilation
1 parent 8610a88 commit a51f0bf

3 files changed

Lines changed: 97 additions & 3 deletions

File tree

src/compiler/checker.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -713,8 +713,14 @@ module ts {
713713
function markExportAsReferenced(node: ImportEqualsDeclaration | ExportAssignment | ExportSpecifier) {
714714
let symbol = getSymbolOfNode(node);
715715
let target = resolveAlias(symbol);
716-
if (target && target !== unknownSymbol && target.flags & SymbolFlags.Value && !isConstEnumOrConstEnumOnlyModule(target)) {
717-
markAliasSymbolAsReferenced(symbol);
716+
if (target) {
717+
let markAlias =
718+
(target === unknownSymbol && compilerOptions.separateCompilation) ||
719+
(target !== unknownSymbol && target.flags & SymbolFlags.Value && !isConstEnumOrConstEnumOnlyModule(target));
720+
721+
if (markAlias) {
722+
markAliasSymbolAsReferenced(symbol);
723+
}
718724
}
719725
}
720726

@@ -9745,7 +9751,9 @@ module ts {
97459751

97469752
checkKindsOfPropertyMemberOverrides(type, baseType);
97479753
}
9754+
}
97489755

9756+
if (type.baseTypes.length || (baseTypeNode && compilerOptions.separateCompilation)) {
97499757
// Check that base type can be evaluated as expression
97509758
checkExpressionOrQualifiedName(baseTypeNode.typeName);
97519759
}
@@ -11264,11 +11272,16 @@ module ts {
1126411272
// parent is not source file or it is not reference to internal module
1126511273
return false;
1126611274
}
11267-
return isAliasResolvedToValue(getSymbolOfNode(node));
11275+
11276+
var isValue = isAliasResolvedToValue(getSymbolOfNode(node));
11277+
return isValue && node.moduleReference && !nodeIsMissing(node.moduleReference);
1126811278
}
1126911279

1127011280
function isAliasResolvedToValue(symbol: Symbol): boolean {
1127111281
let target = resolveAlias(symbol);
11282+
if (target === unknownSymbol && compilerOptions.separateCompilation) {
11283+
return true;
11284+
}
1127211285
// const enums and modules that contain only const enums are not considered values from the emit perespective
1127311286
return target !== unknownSymbol && target.flags & SymbolFlags.Value && !isConstEnumOrConstEnumOnlyModule(target);
1127411287
}

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,6 +1587,7 @@ module ts {
15871587
target?: ScriptTarget;
15881588
version?: boolean;
15891589
watch?: boolean;
1590+
separateCompilation?: boolean;
15901591
/* @internal */ stripInternal?: boolean;
15911592
/* @internal */ preserveNewLines?: boolean;
15921593
/* @internal */ cacheDownlevelForOfLength?: boolean;

src/services/services.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1635,6 +1635,86 @@ module ts {
16351635
sourceFile.scriptSnapshot = scriptSnapshot;
16361636
}
16371637

1638+
export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, syntaxErrors?: Diagnostic[]): string {
1639+
let options = compilerOptions ? ts.clone(compilerOptions) : getDefaultCompilerOptions();
1640+
1641+
// Single file transformation is only guranteed to be correct if inside an external module.
1642+
// External modules have thier own scope and can not contribute to internal modules outside their
1643+
// scope.
1644+
if (options.target !== ScriptTarget.ES6 && (!options.module || options.module === ModuleKind.None)) {
1645+
// add errors
1646+
}
1647+
1648+
// In sigle file transformation the compiler does not have access to declaration sites.
1649+
// Const enum property access will not be detected if they are not in the same file as the enum.
1650+
// thus they are goign to be emitted as normal propety access. To ensure correct behaviour at runtime,
1651+
// we need to generare the actual enum object so that the proprty accesses do not fail.
1652+
options.preserveConstEnums = true;
1653+
1654+
// No reason to get declarations, we are only returning javascript
1655+
options.declaration = false;
1656+
1657+
// Filename can be non-ts file. We are not locating any modules as well, so allow
1658+
// non-ts extensions
1659+
options.allowNonTsExtensions = true;
1660+
1661+
// enable relaxed emit rules
1662+
options.separateCompilation = true;
1663+
1664+
// We are not resolving references or modules, or even including the library. Disabling
1665+
// emit on error will block generating the output and has no meaningful use here.
1666+
options.noEmitOnError = false;
1667+
1668+
// No resolution requests will be honered anyways. So do not do it
1669+
options.noResolve = true;
1670+
1671+
// TODO (vladima): add inlineSourceMap once it is checked in
1672+
//if (options.sourceMap) {
1673+
// // We need to return a single string, so inline the sourceMap in the output
1674+
// options.inlineSourceMap = true;;
1675+
//}
1676+
1677+
// Parse
1678+
var inputFileName = fileName || "module.ts";
1679+
var sourceFile = ts.createSourceFile(inputFileName, input, options.target);
1680+
1681+
// Store syntactic diagnostics
1682+
if (syntaxErrors && sourceFile.parseDiagnostics) {
1683+
syntaxErrors.push(...sourceFile.parseDiagnostics);
1684+
}
1685+
1686+
// Output
1687+
let outputText: string;
1688+
1689+
// Create a compilerHost object to allow the compiler to read and write files
1690+
var compilerHost: CompilerHost = {
1691+
getSourceFile: (fileName, target) => fileName === inputFileName ? sourceFile : undefined,
1692+
writeFile: (name, text, writeByteOrderMark) => {
1693+
if (ts.fileExtensionIs(name, ".js")) {
1694+
Debug.assert(outputText === undefined, "Unexpected multiple outputs for the file: " + name);
1695+
outputText = text;
1696+
}
1697+
},
1698+
getDefaultLibFileName: () => "lib.d.ts",
1699+
useCaseSensitiveFileNames: () => false,
1700+
getCanonicalFileName: fileName => fileName,
1701+
getCurrentDirectory: () => "",
1702+
getNewLine: () => "\r\n"
1703+
};
1704+
1705+
// Note: The emitter needs a the checker to walk the file, so we will create a program for this
1706+
// though single file transformation does not really need this. First we need to drop the emitter
1707+
// dependcy on the checker and then implement a new resolver that does not do the full check.
1708+
var program = ts.createProgram([inputFileName], options, compilerHost);
1709+
1710+
// Emit
1711+
program.emit();
1712+
1713+
Debug.assert(outputText !== undefined, "Output generation failed");
1714+
1715+
return outputText;
1716+
}
1717+
16381718
export function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, setNodeParents: boolean): SourceFile {
16391719
let sourceFile = createSourceFile(fileName, scriptSnapshot.getText(0, scriptSnapshot.getLength()), scriptTarget, setNodeParents);
16401720
setSourceFileFields(sourceFile, scriptSnapshot, version);

0 commit comments

Comments
 (0)