@fulcro/transform-core 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -17,11 +17,6 @@
17
17
  * other.
18
18
  */
19
19
  export { createFileTransformer, type FileTransformer, type TransformCoreOptions, } from './program/index.js';
20
- export { type ExpressionContext, type ExpressionRewriter, type Replacement, rewriteSourceFile, type RewriteStatistics, } from './rewrite/file/index.js';
21
- export { isRewritable, type ProgramRewrite, type ProgramSource, rewriteToFixpoint, } from './rewrite/fixpoint/index.js';
22
- export { createLanguageServicePlugin, type LanguageServicePlugin, type PluginCreateInfo, } from './rewrite/languageService/index.js';
23
- export { createProgramTransformer, type ProgramTransformer, rewriteProgram, } from './rewrite/programTransformer/index.js';
24
- export { type RewrittenText } from './rewrite/text/index.js';
25
20
  export { type CallForm, type CallRewriter, IDENTIFIER_PATTERN, isOwnedCall, isTupleType, type RewriteContext, utilityModuleSegment, } from './shared/index.js';
26
21
  export { buildStructuralTest, type StructuralOptions, type TypeTest, } from './structural/index.js';
27
22
  export { createTransformer, type TransformerFactory, type TransformerOptions, } from './transformer/index.js';
package/dist/index.js CHANGED
@@ -18,19 +18,9 @@
18
18
  * other.
19
19
  */
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.createTransformer = exports.buildStructuralTest = exports.utilityModuleSegment = exports.isTupleType = exports.isOwnedCall = exports.IDENTIFIER_PATTERN = exports.rewriteProgram = exports.createProgramTransformer = exports.createLanguageServicePlugin = exports.rewriteToFixpoint = exports.isRewritable = exports.rewriteSourceFile = exports.createFileTransformer = void 0;
21
+ exports.createTransformer = exports.buildStructuralTest = exports.utilityModuleSegment = exports.isTupleType = exports.isOwnedCall = exports.IDENTIFIER_PATTERN = exports.createFileTransformer = void 0;
22
22
  var program_1 = require("./program/index.js");
23
23
  Object.defineProperty(exports, "createFileTransformer", { enumerable: true, get: function () { return program_1.createFileTransformer; } });
24
- var file_1 = require("./rewrite/file/index.js");
25
- Object.defineProperty(exports, "rewriteSourceFile", { enumerable: true, get: function () { return file_1.rewriteSourceFile; } });
26
- var fixpoint_1 = require("./rewrite/fixpoint/index.js");
27
- Object.defineProperty(exports, "isRewritable", { enumerable: true, get: function () { return fixpoint_1.isRewritable; } });
28
- Object.defineProperty(exports, "rewriteToFixpoint", { enumerable: true, get: function () { return fixpoint_1.rewriteToFixpoint; } });
29
- var languageService_1 = require("./rewrite/languageService/index.js");
30
- Object.defineProperty(exports, "createLanguageServicePlugin", { enumerable: true, get: function () { return languageService_1.createLanguageServicePlugin; } });
31
- var programTransformer_1 = require("./rewrite/programTransformer/index.js");
32
- Object.defineProperty(exports, "createProgramTransformer", { enumerable: true, get: function () { return programTransformer_1.createProgramTransformer; } });
33
- Object.defineProperty(exports, "rewriteProgram", { enumerable: true, get: function () { return programTransformer_1.rewriteProgram; } });
34
24
  var shared_1 = require("./shared/index.js");
35
25
  Object.defineProperty(exports, "IDENTIFIER_PATTERN", { enumerable: true, get: function () { return shared_1.IDENTIFIER_PATTERN; } });
36
26
  Object.defineProperty(exports, "isOwnedCall", { enumerable: true, get: function () { return shared_1.isOwnedCall; } });
@@ -1,6 +1,5 @@
1
1
  import { type UnpluginFactory, type UnpluginInstance } from 'unplugin';
2
2
  import { type TransformCoreOptions } from '../program/index.js';
3
- import { type ExpressionRewriter } from '../rewrite/file/index.js';
4
3
  import { type CallRewriter } from '../shared/index.js';
5
4
  /**
6
5
  * Bundler adapters for the Fulcro transformers.
@@ -55,14 +54,4 @@ export interface TransformerUnplugin {
55
54
  * @returns Every adapter `unplugin` can produce.
56
55
  */
57
56
  export declare const createTransformerUnplugin: (rewriters: readonly CallRewriter[], name: string) => TransformerUnplugin;
58
- /**
59
- * Builds the bundler adapters for a rewrite that happens before type checking
60
- * — one whose output is what the checker would read, such as the operators of
61
- * `@fulcro/types`.
62
- *
63
- * @param rewriter Rewriter of the package publishing the plugin.
64
- * @param name Name the plugin reports to the bundler.
65
- * @returns Every adapter `unplugin` can produce.
66
- */
67
- export declare const createRewriterUnplugin: (rewriter: ExpressionRewriter, name: string) => TransformerUnplugin;
68
57
  export {};
@@ -1,6 +1,5 @@
1
1
  import { createUnplugin, } from 'unplugin';
2
2
  import { createFileTransformer, } from '../program/index.js';
3
- import { createRewritingFileTransformer } from '../rewrite/fileTransformer/index.js';
4
3
  /**
5
4
  * Builds the bundler adapters for one set of rewriters.
6
5
  *
@@ -11,17 +10,7 @@ import { createRewritingFileTransformer } from '../rewrite/fileTransformer/index
11
10
  */
12
11
  export const createTransformerUnplugin = (rewriters, name) => createAdapters((options) => createFileTransformer(rewriters, options), name);
13
12
  /**
14
- * Builds the bundler adapters for a rewrite that happens before type checking
15
- * — one whose output is what the checker would read, such as the operators of
16
- * `@fulcro/types`.
17
- *
18
- * @param rewriter Rewriter of the package publishing the plugin.
19
- * @param name Name the plugin reports to the bundler.
20
- * @returns Every adapter `unplugin` can produce.
21
- */
22
- export const createRewriterUnplugin = (rewriter, name) => createAdapters((options) => createRewritingFileTransformer(rewriter, options), name);
23
- /**
24
- * Builds the adapters around whichever core a package uses.
13
+ * Builds the adapters around the core of a package.
25
14
  *
26
15
  * @param build Builds the core for a set of options.
27
16
  * @param name Name the plugin reports to the bundler.
package/package.json CHANGED
@@ -1,62 +1,62 @@
1
- {
2
- "name": "@fulcro/transform-core",
3
- "version": "0.10.0",
4
- "description": "Shared machinery behind the Fulcro compile time transformers. Installed for you; not meant to be depended on directly.",
5
- "keywords": [
6
- "typescript",
7
- "transformer",
8
- "ts-patch",
9
- "unplugin",
10
- "compiler"
11
- ],
12
- "license": "ISC",
13
- "author": "diguu <rodrigogeribola@hotmail.com>",
14
- "main": "./dist/index.js",
15
- "types": "./dist/index.d.ts",
16
- "exports": {
17
- ".": {
18
- "types": "./dist/index.d.ts",
19
- "default": "./dist/index.js"
20
- },
21
- "./unplugin": {
22
- "types": "./dist/unplugin/index.d.mts",
23
- "default": "./dist/unplugin/index.mjs"
24
- },
25
- "./package.json": "./package.json"
26
- },
27
- "files": [
28
- "dist"
29
- ],
30
- "sideEffects": false,
31
- "scripts": {
32
- "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
33
- "typecheck": "tsc --noEmit -p tsconfig.json",
34
- "prepublishOnly": "npm run build"
35
- },
36
- "dependencies": {
37
- "unplugin": "^3.3.0"
38
- },
39
- "peerDependencies": {
40
- "typescript": ">=5.3.3 <7"
41
- },
42
- "peerDependenciesMeta": {
43
- "typescript": {
44
- "optional": true
45
- }
46
- },
47
- "publishConfig": {
48
- "access": "public"
49
- },
50
- "engines": {
51
- "node": ">=22"
52
- },
53
- "repository": {
54
- "type": "git",
55
- "url": "git+https://github.com/DigUu-RL/fulcro.git",
56
- "directory": "packages/transform-core"
57
- },
58
- "homepage": "https://github.com/DigUu-RL/fulcro/tree/main/packages/transform-core#readme",
59
- "bugs": {
60
- "url": "https://github.com/DigUu-RL/fulcro/issues"
61
- }
62
- }
1
+ {
2
+ "name": "@fulcro/transform-core",
3
+ "version": "0.11.0",
4
+ "description": "Shared machinery behind the Fulcro compile time transformers. Installed for you; not meant to be depended on directly.",
5
+ "keywords": [
6
+ "typescript",
7
+ "transformer",
8
+ "ts-patch",
9
+ "unplugin",
10
+ "compiler"
11
+ ],
12
+ "license": "ISC",
13
+ "author": "diguu <rodrigogeribola@hotmail.com>",
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ },
21
+ "./unplugin": {
22
+ "types": "./dist/unplugin/index.d.mts",
23
+ "default": "./dist/unplugin/index.mjs"
24
+ },
25
+ "./package.json": "./package.json"
26
+ },
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "sideEffects": false,
31
+ "scripts": {
32
+ "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
33
+ "typecheck": "tsc --noEmit -p tsconfig.json",
34
+ "prepublishOnly": "npm run build"
35
+ },
36
+ "dependencies": {
37
+ "unplugin": "^3.3.0"
38
+ },
39
+ "peerDependencies": {
40
+ "typescript": ">=5.3.3 <7"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "typescript": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "engines": {
51
+ "node": ">=22"
52
+ },
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "git+https://github.com/DigUu-RL/fulcro.git",
56
+ "directory": "packages/transform-core"
57
+ },
58
+ "homepage": "https://github.com/DigUu-RL/fulcro/tree/main/packages/transform-core#readme",
59
+ "bugs": {
60
+ "url": "https://github.com/DigUu-RL/fulcro/issues"
61
+ }
62
+ }
@@ -1,74 +0,0 @@
1
- import typescript from 'typescript';
2
- import { type RewrittenText } from '../text/index.js';
3
- /**
4
- * One file rewritten before type checking.
5
- *
6
- * The call rewriters of `@/shared` run after the checker, on a tree whose types
7
- * are already settled, and replace a call by a node. This is the other kind:
8
- * it replaces **text**, before the checker has run on it, so that what it emits
9
- * is what gets type checked. That is the only way to give a type a meaning the
10
- * checker would otherwise refuse — `decimal * decimal` is a type error until it
11
- * has become `decimal.multiply(decimal)`.
12
- *
13
- * The rewriter is asked about each node, outermost first, and answers with the
14
- * text that replaces it, in which child nodes may appear to be rendered in turn.
15
- * Everything it does not claim is copied verbatim, so the output differs from
16
- * the input only where something was rewritten.
17
- */
18
- /** Everything a rewriter needs to decide about one node. */
19
- export interface ExpressionContext {
20
- /** Checker of the program the file belongs to. */
21
- readonly checker: typescript.TypeChecker;
22
- /** The file being rewritten. */
23
- readonly sourceFile: typescript.SourceFile;
24
- /**
25
- * The line breaks the original text has between two offsets, as a string
26
- * of newlines.
27
- *
28
- * Put into the synthesized text between two operands, it keeps every line
29
- * of the file where it was — so an error the checker reports on the
30
- * rewritten text still names the line the author wrote.
31
- */
32
- readonly lineBreaks: (start: number, end: number) => string;
33
- }
34
- /**
35
- * What replaces a node: synthesized text and child nodes, in order. A node is
36
- * rendered in turn — itself rewritten where the rewriter claims it — and may
37
- * appear more than once.
38
- */
39
- export type Replacement = readonly (string | typescript.Node)[];
40
- /** Rewrites the nodes of one kind of construct, before type checking. */
41
- export interface ExpressionRewriter {
42
- /**
43
- * Module the rewritten code refers to, imported under
44
- * {@link ExpressionRewriter.namespace} in every file that was rewritten.
45
- */
46
- readonly module: string;
47
- /** Local name the module is imported under. */
48
- readonly namespace: string;
49
- /**
50
- * Rewrites one node.
51
- *
52
- * @param node Node being considered.
53
- * @param context The file and its checker.
54
- * @returns The replacement, or `null` to keep the node and look inside it.
55
- */
56
- readonly rewrite: (node: typescript.Node, context: ExpressionContext) => Replacement | null;
57
- }
58
- /** How much a rewrite looked at, for the suites that count it. */
59
- export interface RewriteStatistics {
60
- /** Nodes the rewriter was asked about. */
61
- visited: number;
62
- /** Nodes it replaced. */
63
- rewritten: number;
64
- }
65
- /**
66
- * Rewrites one source file.
67
- *
68
- * @param sourceFile File to rewrite, from a program whose checker is given.
69
- * @param checker Checker of that program.
70
- * @param rewriter What to rewrite.
71
- * @param statistics Counters to add to, when the caller keeps them.
72
- * @returns The rewritten text and its map, or `null` when nothing was claimed.
73
- */
74
- export declare const rewriteSourceFile: (sourceFile: typescript.SourceFile, checker: typescript.TypeChecker, rewriter: ExpressionRewriter, statistics?: RewriteStatistics) => RewrittenText | null;
@@ -1,124 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.rewriteSourceFile = void 0;
7
- const typescript_1 = __importDefault(require("typescript"));
8
- const text_1 = require("../text/index.js");
9
- /**
10
- * Where the namespace import goes: on the first line of the first statement,
11
- * before it and without a line break, so no line of the file moves. At the end
12
- * of the file would keep the lines too, but a CommonJS emit leaves a `require`
13
- * where the import was written, and code above it would run first.
14
- *
15
- * @param sourceFile File being rewritten.
16
- * @returns The offset to insert at.
17
- */
18
- const importOffset = (sourceFile) => {
19
- const [first] = sourceFile.statements;
20
- return first === undefined ? sourceFile.end : first.getStart(sourceFile);
21
- };
22
- /**
23
- * Rewrites one source file.
24
- *
25
- * @param sourceFile File to rewrite, from a program whose checker is given.
26
- * @param checker Checker of that program.
27
- * @param rewriter What to rewrite.
28
- * @param statistics Counters to add to, when the caller keeps them.
29
- * @returns The rewritten text and its map, or `null` when nothing was claimed.
30
- */
31
- const rewriteSourceFile = (sourceFile, checker, rewriter, statistics) => {
32
- const original = sourceFile.text;
33
- const output = (0, text_1.createTextBuilder)(original);
34
- const context = {
35
- checker,
36
- sourceFile,
37
- lineBreaks: (start, end) => '\n'.repeat(original.slice(start, end).split('\n').length - 1),
38
- };
39
- const importDeclaration = `import * as ${rewriter.namespace} from '${rewriter.module}'; `;
40
- let cursor = 0;
41
- let rewroteAny = false;
42
- /**
43
- * Copies original text from the cursor up to an offset.
44
- *
45
- * @param end Offset to copy up to.
46
- */
47
- const advance = (end) => {
48
- output.copy(cursor, end);
49
- cursor = Math.max(cursor, end);
50
- };
51
- const render = (node) => {
52
- if (statistics !== undefined)
53
- statistics.visited++;
54
- const replacement = rewriter.rewrite(node, context);
55
- if (replacement === null) {
56
- typescript_1.default.forEachChild(node, (child) => {
57
- advance(child.getStart(sourceFile));
58
- render(child);
59
- });
60
- return;
61
- }
62
- rewroteAny = true;
63
- if (statistics !== undefined)
64
- statistics.rewritten++;
65
- const start = node.getStart(sourceFile);
66
- advance(start);
67
- const close = output.open(start, node.end);
68
- for (const part of replacement) {
69
- if (typeof part === 'string') {
70
- output.write(part);
71
- }
72
- else {
73
- // A child is rendered from its own start, independently of the
74
- // cursor: it may be written twice, and in any order.
75
- const saved = cursor;
76
- cursor = part.getStart(sourceFile);
77
- render(part);
78
- output.copy(cursor, part.end);
79
- cursor = saved;
80
- }
81
- }
82
- close();
83
- cursor = node.end;
84
- };
85
- typescript_1.default.forEachChild(sourceFile, (child) => {
86
- advance(child.getStart(sourceFile));
87
- render(child);
88
- });
89
- advance(sourceFile.end);
90
- if (!rewroteAny)
91
- return null;
92
- // A second pass over an already rewritten file finds the import there and
93
- // must not add another. The import is only known to be needed once the
94
- // walk is over, so it is spliced in afterwards rather than written in
95
- // passing.
96
- if (original.includes(importDeclaration))
97
- return output.build();
98
- return withImport(output.build(), importOffset(sourceFile), importDeclaration);
99
- };
100
- exports.rewriteSourceFile = rewriteSourceFile;
101
- /**
102
- * Inserts the namespace import into a rewritten text, extending its map.
103
- *
104
- * @param rewritten The rewritten text, without the import.
105
- * @param originalOffset Where, in the original, the import goes.
106
- * @param declaration The import declaration, with its trailing space.
107
- * @returns The text with the import and a map that accounts for it.
108
- */
109
- const withImport = (rewritten, originalOffset, declaration) => {
110
- const at = rewritten.toGenerated(originalOffset);
111
- const length = declaration.length;
112
- return {
113
- text: rewritten.text.slice(0, at) + declaration + rewritten.text.slice(at),
114
- toOriginal: (generated) => generated < at
115
- ? rewritten.toOriginal(generated)
116
- : generated < at + length
117
- ? originalOffset
118
- : rewritten.toOriginal(generated - length),
119
- toGenerated: (original) => {
120
- const position = rewritten.toGenerated(original);
121
- return position < at ? position : position + length;
122
- },
123
- };
124
- };
@@ -1,10 +0,0 @@
1
- import { type FileTransformer, type TransformCoreOptions } from '../../program/index.js';
2
- import { type ExpressionRewriter } from '../file/index.js';
3
- /**
4
- * Creates the bundler core of a rewriter.
5
- *
6
- * @param rewriter What to rewrite.
7
- * @param options Options of the core.
8
- * @returns A transformer any bundler adapter can drive.
9
- */
10
- export declare const createRewritingFileTransformer: (rewriter: ExpressionRewriter, options?: TransformCoreOptions) => FileTransformer;
@@ -1,131 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.createRewritingFileTransformer = void 0;
40
- const fs = __importStar(require("node:fs"));
41
- const path = __importStar(require("node:path"));
42
- const typescript_1 = __importDefault(require("typescript"));
43
- const program_1 = require("../../program/index.js");
44
- const fixpoint_1 = require("../fixpoint/index.js");
45
- /**
46
- * The bundler integration of a rewrite that has to happen before type
47
- * checking.
48
- *
49
- * A bundler never type checks — esbuild and swc erase the types — so an error
50
- * the checker would raise on `decimal * decimal` never stops it. What it does
51
- * need is the rewrite itself, and that needs the whole program: whether `c + d`
52
- * in one file is claimable depends on how `c` was declared in another. So the
53
- * first file to arrive rewrites the whole program to a fixed point, and every
54
- * file after it is answered from that until some file changes.
55
- */
56
- /** Extensions carrying TypeScript this transformer is responsible for. */
57
- const HANDLED_EXTENSIONS = ['.ts', '.mts', '.cts', '.tsx'];
58
- /**
59
- * Creates the bundler core of a rewriter.
60
- *
61
- * @param rewriter What to rewrite.
62
- * @param options Options of the core.
63
- * @returns A transformer any bundler adapter can drive.
64
- */
65
- const createRewritingFileTransformer = (rewriter, options = {}) => {
66
- const root = options.root ?? process.cwd();
67
- let host;
68
- let service;
69
- let rewrite;
70
- /** What the bundler last handed over for each file, before any rewrite. */
71
- const originals = new Map();
72
- const handles = (id) => {
73
- const fileName = id.split('?')[0];
74
- if (!HANDLED_EXTENSIONS.includes(path.extname(fileName)))
75
- return false;
76
- return !fileName.includes('node_modules');
77
- };
78
- /**
79
- * Puts every rewritten file back to its original text, so the next rewrite
80
- * starts from what the author wrote rather than from its own output.
81
- *
82
- * @param programHost The host holding the texts.
83
- */
84
- const restore = (programHost) => {
85
- for (const fileName of rewrite?.files.keys() ?? []) {
86
- const text = originals.get(fileName) ??
87
- (fs.existsSync(fileName)
88
- ? fs.readFileSync(fileName, 'utf8')
89
- : undefined);
90
- if (text !== undefined)
91
- programHost.update(fileName, text);
92
- }
93
- rewrite = undefined;
94
- };
95
- const transform = (id, code) => {
96
- if (!handles(id))
97
- return null;
98
- const fileName = (0, program_1.toCompilerPath)(id.split('?')[0]);
99
- if (host === undefined || service === undefined) {
100
- host = new program_1.ProgramHost((0, program_1.parseTsconfig)(root, options.tsconfig), root);
101
- service = typescript_1.default.createLanguageService(host, typescript_1.default.createDocumentRegistry());
102
- }
103
- if (originals.get(fileName) !== code) {
104
- originals.set(fileName, code);
105
- restore(host);
106
- host.update(fileName, code);
107
- }
108
- if (rewrite === undefined) {
109
- const programHost = host;
110
- const languageService = service;
111
- rewrite = (0, fixpoint_1.rewriteToFixpoint)({
112
- program: () => {
113
- const program = languageService.getProgram();
114
- if (program === undefined) {
115
- throw new Error(`The language service produced no program for ${root}.`);
116
- }
117
- return program;
118
- },
119
- update: (name, text) => programHost.update(name, text),
120
- }, rewriter);
121
- }
122
- const sourceFile = service
123
- .getProgram()
124
- ?.getSourceFile(fileName);
125
- if (sourceFile !== undefined && !(0, fixpoint_1.isRewritable)(sourceFile))
126
- return null;
127
- return rewrite.files.get(fileName)?.text ?? null;
128
- };
129
- return { handles, transform };
130
- };
131
- exports.createRewritingFileTransformer = createRewritingFileTransformer;
@@ -1,56 +0,0 @@
1
- import typescript from 'typescript';
2
- import { type ExpressionRewriter, type RewriteStatistics } from '../file/index.js';
3
- import { type RewrittenText } from '../text/index.js';
4
- /**
5
- * Rewriting a whole program until nothing more is claimed.
6
- *
7
- * One pass is not enough, because rewriting changes what the checker infers.
8
- * `const c = a + b` types `c` as `number` in the original — the checker has no
9
- * idea `+` means anything else — so a later `c + d` looks like arithmetic on a
10
- * plain number and is left alone. Once the first line reads
11
- * `const c = T.add(a, b)`, `c` has the type `T.add` returns, and the second
12
- * line is claimable. So the program is rewritten, re-checked, and rewritten
13
- * again until a pass claims nothing — each pass can only claim sites the one
14
- * before could not, so the loop ends, and a bound on it makes sure it does.
15
- *
16
- * Where the program comes from is the caller's: a fresh `createProgram` for
17
- * `tsc`, a language service for a bundler or an editor. This only needs to ask
18
- * for the current program and to hand text back.
19
- */
20
- /** Something that holds a program and can have its files replaced. */
21
- export interface ProgramSource {
22
- /** The program as it stands, with every text handed back so far. */
23
- readonly program: () => typescript.Program;
24
- /**
25
- * Replaces the text of a file for the next {@link ProgramSource.program}.
26
- *
27
- * @param fileName File, as the program spells it.
28
- * @param text Its new text.
29
- */
30
- readonly update: (fileName: string, text: string) => void;
31
- }
32
- /** The outcome of rewriting a program. */
33
- export interface ProgramRewrite {
34
- /** Each rewritten file, mapped back to its original text. */
35
- readonly files: ReadonlyMap<string, RewrittenText>;
36
- /** Passes it took, the last one claiming nothing. */
37
- readonly passes: number;
38
- /** Nodes considered and replaced, over every pass. */
39
- readonly statistics: RewriteStatistics;
40
- }
41
- /**
42
- * Tells whether a file is the consumer's own source, which is all a rewrite
43
- * touches: never a declaration file, never a dependency.
44
- *
45
- * @param sourceFile File of the program.
46
- * @returns `true` when it may be rewritten.
47
- */
48
- export declare const isRewritable: (sourceFile: typescript.SourceFile) => boolean;
49
- /**
50
- * Rewrites a program to a fixed point.
51
- *
52
- * @param source Where the program comes from.
53
- * @param rewriter What to rewrite.
54
- * @returns The rewritten files and what it took.
55
- */
56
- export declare const rewriteToFixpoint: (source: ProgramSource, rewriter: ExpressionRewriter) => ProgramRewrite;
@@ -1,61 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.rewriteToFixpoint = exports.isRewritable = void 0;
4
- const file_1 = require("../file/index.js");
5
- const text_1 = require("../text/index.js");
6
- /**
7
- * Passes after which the loop stops whether or not it has settled. Each pass
8
- * resolves one more step of inference through a chain of declarations, and a
9
- * program needing more than this has a chain of `const` declarations longer
10
- * than anyone writes — its remaining sites are left as the checker sees them,
11
- * and report their own type errors.
12
- */
13
- const MAXIMUM_PASSES = 16;
14
- /**
15
- * Tells whether a file is the consumer's own source, which is all a rewrite
16
- * touches: never a declaration file, never a dependency.
17
- *
18
- * @param sourceFile File of the program.
19
- * @returns `true` when it may be rewritten.
20
- */
21
- const isRewritable = (sourceFile) => !sourceFile.isDeclarationFile &&
22
- !sourceFile.fileName.includes('/node_modules/');
23
- exports.isRewritable = isRewritable;
24
- /**
25
- * Rewrites a program to a fixed point.
26
- *
27
- * @param source Where the program comes from.
28
- * @param rewriter What to rewrite.
29
- * @returns The rewritten files and what it took.
30
- */
31
- const rewriteToFixpoint = (source, rewriter) => {
32
- const files = new Map();
33
- const statistics = { visited: 0, rewritten: 0 };
34
- let passes = 0;
35
- while (passes < MAXIMUM_PASSES) {
36
- passes++;
37
- const program = source.program();
38
- const checker = program.getTypeChecker();
39
- const changed = [];
40
- for (const sourceFile of program.getSourceFiles()) {
41
- if (!(0, exports.isRewritable)(sourceFile))
42
- continue;
43
- const rewritten = (0, file_1.rewriteSourceFile)(sourceFile, checker, rewriter, statistics);
44
- if (rewritten !== null)
45
- changed.push([sourceFile.fileName, rewritten]);
46
- }
47
- if (changed.length === 0)
48
- break;
49
- // Handed back only once the pass is over, so every file of a pass is
50
- // read against the same program.
51
- for (const [fileName, rewritten] of changed) {
52
- const previous = files.get(fileName);
53
- files.set(fileName, previous === undefined
54
- ? rewritten
55
- : (0, text_1.composeRewrites)(previous, rewritten));
56
- source.update(fileName, rewritten.text);
57
- }
58
- }
59
- return { files, passes, statistics };
60
- };
61
- exports.rewriteToFixpoint = rewriteToFixpoint;