|
1 | 1 | # `std.module.format` |
2 | 2 |
|
3 | | -> version 0.1.1 |
| 3 | +> version 0.1.2 |
4 | 4 |
|
5 | 5 | - [`std.module.format`](#-stdmoduleformat-) |
6 | 6 | * [Overview](#overview) |
|
23 | 23 | * [Note](#note) |
24 | 24 | + [Needs two lines for non-class / non-function](#needs-two-lines-for-non-class---non-function) |
25 | 25 | + [React.js - Named Exports](#reactjs---named-exports) |
26 | | - * [The {} type](#---type) |
| 26 | + * [{} type](#---type) |
27 | 27 | + [If you want a type that means "empty object"](#if-you-want-a-type-that-means--empty-object-) |
28 | 28 | + [If you are using React, and you want to define `type Props = {}`.](#if-you-are-using-react--and-you-want-to-define--type-props------) |
29 | 29 | + [`GenericObject`](#-genericobject-) |
30 | 30 | + [Module-related host hooks](#module-related-host-hooks) |
| 31 | + * [Customizing module resolution](#customizing-module-resolution) |
| 32 | + + [parserOptions.moduleResolver](#parseroptionsmoduleresolver) |
| 33 | + * [License](#license) |
31 | 34 |
|
32 | 35 | <small><i><a href='#'>This is a work in progress</a></i></small> |
33 | 36 |
|
@@ -596,6 +599,127 @@ The following are not valid module specifiers according to the above algorithm: |
596 | 599 | - `.\yam.es` |
597 | 600 |
|
598 | 601 |
|
| 602 | +## Customizing module resolution |
| 603 | +
|
| 604 | +> [source, https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#customizing-module-resolution] |
| 605 | +
|
| 606 | +You can override the standard way the compiler resolves modules by implementing optional method: CompilerHost.resolveModuleNames: |
| 607 | +
|
| 608 | +```typescript |
| 609 | +CompilerHost.resolveModuleNames(moduleNames: string[], containingFile: string): string[]. |
| 610 | +``` |
| 611 | +
|
| 612 | +The method is given a list of module names in a file, and is expected to return an array of size moduleNames.length, each element of the array stores either: |
| 613 | +
|
| 614 | +an instance of ResolvedModule with non-empty property resolvedFileName - resolution for corresponding name from moduleNames array or undefined if module name cannot be resolved. |
| 615 | +
|
| 616 | +You can invoke the standard module resolution process via calling resolveModuleName: |
| 617 | +
|
| 618 | +```typescript |
| 619 | +resolveModuleName(moduleName: string, containingFile: string, options: CompilerOptions, moduleResolutionHost: ModuleResolutionHost): ResolvedModuleNameWithFallbackLocations. |
| 620 | +``` |
| 621 | +
|
| 622 | +This function returns an object that stores result of module resolution (value of resolvedModule property) as well as list of file names that were considered candidates before making current decision. |
| 623 | +
|
| 624 | +```typescript |
| 625 | +import * as ts from "typescript"; |
| 626 | +import * as path from "path"; |
| 627 | +
|
| 628 | +function createCompilerHost(options: ts.CompilerOptions, moduleSearchLocations: string[]): ts.CompilerHost { |
| 629 | + return { |
| 630 | + getSourceFile, |
| 631 | + getDefaultLibFileName: () => "lib.d.ts", |
| 632 | + writeFile: (fileName, content) => ts.sys.writeFile(fileName, content), |
| 633 | + getCurrentDirectory: () => ts.sys.getCurrentDirectory(), |
| 634 | + getDirectories: path => ts.sys.getDirectories(path), |
| 635 | + getCanonicalFileName: fileName => |
| 636 | + ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(), |
| 637 | + getNewLine: () => ts.sys.newLine, |
| 638 | + useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames, |
| 639 | + fileExists, |
| 640 | + readFile, |
| 641 | + resolveModuleNames |
| 642 | + }; |
| 643 | +
|
| 644 | + function fileExists(fileName: string): boolean { |
| 645 | + return ts.sys.fileExists(fileName); |
| 646 | + } |
| 647 | +
|
| 648 | + function readFile(fileName: string): string | undefined { |
| 649 | + return ts.sys.readFile(fileName); |
| 650 | + } |
| 651 | +
|
| 652 | + function getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void) { |
| 653 | + const sourceText = ts.sys.readFile(fileName); |
| 654 | + return sourceText !== undefined |
| 655 | + ? ts.createSourceFile(fileName, sourceText, languageVersion) |
| 656 | + : undefined; |
| 657 | + } |
| 658 | +
|
| 659 | + function resolveModuleNames( |
| 660 | + moduleNames: string[], |
| 661 | + containingFile: string |
| 662 | + ): ts.ResolvedModule[] { |
| 663 | + const resolvedModules: ts.ResolvedModule[] = []; |
| 664 | + for (const moduleName of moduleNames) { |
| 665 | + // try to use standard resolution |
| 666 | + let result = ts.resolveModuleName(moduleName, containingFile, options, { |
| 667 | + fileExists, |
| 668 | + readFile |
| 669 | + }); |
| 670 | + if (result.resolvedModule) { |
| 671 | + resolvedModules.push(result.resolvedModule); |
| 672 | + } else { |
| 673 | + // check fallback locations, for simplicity assume that module at location |
| 674 | + // should be represented by '.d.ts' file |
| 675 | + for (const location of moduleSearchLocations) { |
| 676 | + const modulePath = path.join(location, moduleName + ".d.ts"); |
| 677 | + if (fileExists(modulePath)) { |
| 678 | + resolvedModules.push({ resolvedFileName: modulePath }); |
| 679 | + } |
| 680 | + } |
| 681 | + } |
| 682 | + } |
| 683 | + return resolvedModules; |
| 684 | + } |
| 685 | +} |
| 686 | +
|
| 687 | +function compile(sourceFiles: string[], moduleSearchLocations: string[]): void { |
| 688 | + const options: ts.CompilerOptions = { |
| 689 | + module: ts.ModuleKind.AMD, |
| 690 | + target: ts.ScriptTarget.ES5 |
| 691 | + }; |
| 692 | + const host = createCompilerHost(options, moduleSearchLocations); |
| 693 | + const program = ts.createProgram(sourceFiles, options, host); |
| 694 | +
|
| 695 | + /// do something with program... |
| 696 | +} |
| 697 | +``` |
| 698 | +
|
| 699 | +### parserOptions.moduleResolver |
| 700 | +
|
| 701 | +> [source, https://www.npmjs.com/package/@typescript-eslint/parser](https://www.npmjs.com/package/@typescript-eslint/parser) |
| 702 | +
|
| 703 | +Default: `undefined` |
| 704 | +
|
| 705 | +This option allows you to provide a custom module resolution. The value should point to a JS file that default exports (`export default`, or `module.exports =`, or `export =`) a file with the following interface: |
| 706 | +
|
| 707 | +``` |
| 708 | +interface ModuleResolver { |
| 709 | + version: 1; |
| 710 | + resolveModuleNames( |
| 711 | + moduleNames: string[], |
| 712 | + containingFile: string, |
| 713 | + reusedNames: string[] | undefined, |
| 714 | + redirectedReference: ts.ResolvedProjectReference | undefined, |
| 715 | + options: ts.CompilerOptions, |
| 716 | + ): (ts.ResolvedModule | undefined)[]; |
| 717 | +} |
| 718 | +``` |
| 719 | +Refer to the TypeScript Wiki for an example on how to write the resolveModuleNames function. |
| 720 | +
|
| 721 | +Note that if you pass custom programs via options.programs this option will not have any effect over them (you can simply add the custom resolution on them directly). |
| 722 | +
|
599 | 723 | ## License |
600 | 724 |
|
601 | 725 | CC-SA-2.5 |
0 commit comments