1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.emitDownleveledDeclarations = exports.TYPES_COMPAT = void 0;
|
4 | const node_fs_1 = require("node:fs");
|
5 | const node_os_1 = require("node:os");
|
6 | const node_path_1 = require("node:path");
|
7 | const downlevel_dts_1 = require("downlevel-dts");
|
8 | const log4js = require("log4js");
|
9 | const semver_1 = require("semver");
|
10 | const ts = require("typescript");
|
11 | exports.TYPES_COMPAT = '.types-compat';
|
12 | const LOG = log4js.getLogger('jsii/compiler');
|
13 | const TS_VERSION = new semver_1.SemVer(`${ts.versionMajorMinor}.0`);
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | const DOWNLEVEL_BREAKPOINTS = ['3.9'].map((ver) => new semver_1.SemVer(`${ver}.0`));
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 | function emitDownleveledDeclarations({ packageJson, projectRoot, tsc }) {
|
35 | const compatRoot = (0, node_path_1.join)(projectRoot, ...(tsc?.outDir != null ? [tsc?.outDir] : []), exports.TYPES_COMPAT);
|
36 | (0, node_fs_1.rmSync)(compatRoot, { force: true, recursive: true });
|
37 | const rewrites = new Set();
|
38 | for (const breakpoint of DOWNLEVEL_BREAKPOINTS) {
|
39 | if (TS_VERSION.compare(breakpoint) <= 0) {
|
40 |
|
41 |
|
42 | continue;
|
43 | }
|
44 | const rewriteSet = new Map();
|
45 | let needed = false;
|
46 |
|
47 | const workdir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), `downlevel-dts-${breakpoint}-${(0, node_path_1.basename)(projectRoot)}-`));
|
48 | try {
|
49 | (0, downlevel_dts_1.main)(projectRoot, workdir, breakpoint.version);
|
50 | const projectOutDir = tsc?.outDir != null ? (0, node_path_1.join)(projectRoot, tsc.outDir) : projectRoot;
|
51 | const workOutDir = tsc?.outDir != null ? (0, node_path_1.join)(workdir, tsc.outDir) : workdir;
|
52 | for (const dts of walkDirectory(workOutDir)) {
|
53 | const original = (0, node_fs_1.readFileSync)((0, node_path_1.join)(projectOutDir, dts), 'utf-8');
|
54 | const downleveledPath = (0, node_path_1.join)(workOutDir, dts);
|
55 | const downleveled = (0, node_fs_1.readFileSync)(downleveledPath, 'utf-8');
|
56 | needed || (needed = !semanticallyEqualDeclarations(original, downleveled));
|
57 | rewriteSet.set(dts, downleveledPath);
|
58 | }
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 | if (needed) {
|
66 | rewrites.add(`${breakpoint.major}.${breakpoint.minor}`);
|
67 | const versionSuffix = `ts${breakpoint.major}.${breakpoint.minor}`;
|
68 | const compatDir = (0, node_path_1.join)(compatRoot, versionSuffix);
|
69 | if (!(0, node_fs_1.existsSync)(compatDir)) {
|
70 | (0, node_fs_1.mkdirSync)(compatDir, { recursive: true });
|
71 | try {
|
72 |
|
73 | (0, node_fs_1.writeFileSync)((0, node_path_1.join)(compatRoot, '.npmignore'), '\n', 'utf-8');
|
74 |
|
75 | (0, node_fs_1.writeFileSync)((0, node_path_1.join)(compatRoot, '.gitignore'), '*\n', 'utf-8');
|
76 | }
|
77 | catch {
|
78 |
|
79 | }
|
80 | }
|
81 | for (const [dts, downleveledPath] of rewriteSet) {
|
82 | const rewritten = (0, node_path_1.join)(compatDir, dts);
|
83 |
|
84 | (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(rewritten), { recursive: true });
|
85 |
|
86 | (0, node_fs_1.copyFileSync)(downleveledPath, rewritten);
|
87 | }
|
88 | }
|
89 | }
|
90 | finally {
|
91 |
|
92 | (0, node_fs_1.rmSync)(workdir, { force: true, recursive: true });
|
93 | }
|
94 | }
|
95 | let typesVersions;
|
96 | for (const version of rewrites) {
|
97 |
|
98 | typesVersions ?? (typesVersions = {});
|
99 | const from = [...(tsc?.outDir != null ? [tsc?.outDir] : []), '*'].join('/');
|
100 | const to = [...(tsc?.outDir != null ? [tsc?.outDir] : []), exports.TYPES_COMPAT, `ts${version}`, '*'].join('/');
|
101 |
|
102 | typesVersions[`<=${version}`] = { [from]: [to, `${to}/index.d.ts`] };
|
103 | }
|
104 |
|
105 | if (JSON.stringify(packageJson.typesVersions) === JSON.stringify(typesVersions)) {
|
106 |
|
107 | return;
|
108 | }
|
109 | LOG.info('The required `typesVersions` configuration has changed. Updating "package.json" accordingly...');
|
110 |
|
111 | const newPackageJson = Object.entries(packageJson).reduce((obj, [key, value]) => {
|
112 |
|
113 | if (key === 'typesVersions') {
|
114 | if (typesVersions != null) {
|
115 | obj[key] = typesVersions;
|
116 | }
|
117 | }
|
118 | else {
|
119 | obj[key] = value;
|
120 |
|
121 |
|
122 | if (key === 'types' && typesVersions != null && !('typesVersions' in packageJson)) {
|
123 | obj.typesVersions = typesVersions;
|
124 | }
|
125 | }
|
126 | return obj;
|
127 | }, {});
|
128 |
|
129 |
|
130 | if (!('typesVersions' in newPackageJson)) {
|
131 | newPackageJson.typesVersions = typesVersions;
|
132 | }
|
133 | const packageJsonFile = (0, node_path_1.join)(projectRoot, 'package.json');
|
134 |
|
135 | const [, indent] = (0, node_fs_1.readFileSync)(packageJsonFile, 'utf-8').match(/^(\s*)"/m) ?? [null, 2];
|
136 | (0, node_fs_1.writeFileSync)(packageJsonFile, `${JSON.stringify(newPackageJson, undefined, indent)}\n`, 'utf-8');
|
137 | }
|
138 | exports.emitDownleveledDeclarations = emitDownleveledDeclarations;
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 | function semanticallyEqualDeclarations(left, right) {
|
148 |
|
149 | const normalizeDeclarations = (code) => {
|
150 | const sourceFile = ts.createSourceFile('index.d.ts', code, ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
|
151 | const printer = ts.createPrinter({
|
152 | newLine: ts.NewLineKind.LineFeed,
|
153 | noEmitHelpers: true,
|
154 | omitTrailingSemicolon: false,
|
155 | removeComments: true,
|
156 | });
|
157 | let normalized = printer.printFile(sourceFile);
|
158 |
|
159 |
|
160 | const REFERENCES_TYPES_NODE = '/// <reference types="node" />';
|
161 | while (normalized.startsWith(`${REFERENCES_TYPES_NODE}\n${REFERENCES_TYPES_NODE}`)) {
|
162 | normalized = normalized.slice(REFERENCES_TYPES_NODE.length + 1);
|
163 | }
|
164 | return normalized;
|
165 | };
|
166 | left = normalizeDeclarations(left);
|
167 | right = normalizeDeclarations(right);
|
168 | return left === right;
|
169 | }
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 | function* walkDirectory(dir, root = dir) {
|
178 | for (const file of (0, node_fs_1.readdirSync)(dir)) {
|
179 | const filePath = (0, node_path_1.join)(dir, file);
|
180 | if ((0, node_fs_1.statSync)(filePath).isDirectory()) {
|
181 |
|
182 | yield* walkDirectory(filePath, root);
|
183 | }
|
184 | else if (file.toLowerCase().endsWith('.d.ts')) {
|
185 |
|
186 | yield (0, node_path_1.relative)(root, filePath);
|
187 | }
|
188 | }
|
189 | }
|
190 |
|
\ | No newline at end of file |