1import * as fs from "fs";
2import * as path from "path";
3import * as os from "os";
4import * as childProcess from "child_process";
5import url from "url";
6
7const __filename = url.fileURLToPath(new URL(import.meta.url));
8const __dirname = path.dirname(__filename);
9
10main();
11function main() {
12    const [, progName, tscRoot, definitelyTypedRoot] = process.argv;
13    if (process.argv.length !== 4) {
14        if (process.argv.length < 2) {
15            throw new Error("Expected at least 2 argv elements.");
16        }
17        console.log("Usage:");
18        console.log(`    node ${path.relative(__dirname, progName)} [TypeScript Repo Root] [DefinitelyTyped Repo Root]`);
19        return;
20    }
21
22    const tscPath = path.resolve(tscRoot, "built", "local", "tsc.js");
23    const rwcTestPath = path.resolve(tscRoot, "internal", "cases", "rwc");
24    const resolvedDefinitelyTypedRoot = path.resolve(definitelyTypedRoot);
25
26    console.log(`Resolved TypeScript Compiler Path: '${tscPath}'.`);
27    console.log(`Resolved TypeScript RWC Path: '${rwcTestPath}'.`);
28    console.log(`Resolved DefinitelyTyped Repo Root: '${resolvedDefinitelyTypedRoot}'.`);
29    importDefinitelyTypedTests(tscPath, rwcTestPath, resolvedDefinitelyTypedRoot);
30}
31
32/**
33 * @param {string} path
34 * @param {string} endingString
35 * @returns {boolean}
36 */
37function filePathEndsWith(path, endingString) {
38    const pathLen = path.length;
39    const extLen = endingString.length;
40    return pathLen > extLen && path.substr(pathLen - extLen, extLen).toLocaleLowerCase() === endingString.toLocaleLowerCase();
41}
42
43/**
44 * @param {string} source
45 * @param {string} destination
46 */
47function copyFileSync(source, destination) {
48    const text = fs.readFileSync(source);
49    fs.writeFileSync(destination, text);
50}
51
52/**
53 * @param {string} tscPath
54 * @param {string} rwcTestPath
55 * @param {string} testCaseName
56 * @param {string[]} testFiles
57 * @param {string | undefined} responseFile
58 */
59function importDefinitelyTypedTest(tscPath, rwcTestPath, testCaseName, testFiles, responseFile) {
60    let cmd = "node " + tscPath + " --module commonjs " + testFiles.join(" ");
61    if (responseFile) {
62        cmd += " @" + responseFile;
63    }
64
65    const testDirectoryName = testCaseName + "_" + Math.floor((Math.random() * 10000) + 1);
66    const testDirectoryPath = path.join(os.tmpdir(), testDirectoryName);
67    if (fs.existsSync(testDirectoryPath)) {
68        throw new Error("Could not create test directory");
69    }
70    fs.mkdirSync(testDirectoryPath);
71
72    childProcess.exec(cmd, {
73        maxBuffer: 1 * 1024 * 1024,
74        cwd: testDirectoryPath
75    }, (error, stdout, stderr) => {
76        console.log("importing " + testCaseName + " ...");
77        console.log(cmd);
78
79        if (error) {
80            console.log("importing " + testCaseName + " ...");
81            console.log(cmd);
82            console.log("==> error " + JSON.stringify(error));
83            console.log("==> stdout " + String(stdout));
84            console.log("==> stderr " + String(stderr));
85            console.log("\r\n");
86            return;
87        }
88
89        // copy generated file to output location
90        const outputFilePath = path.join(testDirectoryPath, "iocapture0.json");
91        const testCasePath = path.join(rwcTestPath, "DefinitelyTyped_" + testCaseName + ".json");
92        copyFileSync(outputFilePath, testCasePath);
93
94        //console.log("output generated at: " + outputFilePath);
95
96        if (!fs.existsSync(testCasePath)) {
97            throw new Error("could not find test case at: " + testCasePath);
98        }
99        else {
100            fs.unlinkSync(outputFilePath);
101            fs.rmdirSync(testDirectoryPath);
102            //console.log("testcase generated at: " + testCasePath);
103            //console.log("Done.");
104        }
105        //console.log("\r\n");
106
107    }).on("error", (error) => {
108        console.log("==> error " + JSON.stringify(error));
109        console.log("\r\n");
110    });
111}
112
113/**
114 * @param {string} tscPath
115 * @param {string} rwcTestPath
116 * @param {string} definitelyTypedRoot
117 */
118function importDefinitelyTypedTests(tscPath, rwcTestPath, definitelyTypedRoot) {
119    fs.readdir(definitelyTypedRoot, (err, subDirectories) => {
120        if (err) {
121            throw err;
122        }
123
124        // When you just want to test the script out on one or two files,
125        // just add a line like the following:
126        //
127        //   .filter(d => d.indexOf("sipml") >= 0 )
128        subDirectories
129            .filter(d => ["_infrastructure", "node_modules", ".git"].indexOf(d) < 0)
130            .filter(i => fs.statSync(path.join(definitelyTypedRoot, i)).isDirectory())
131            .forEach(d => {
132                const directoryPath = path.join(definitelyTypedRoot, d);
133                fs.readdir(directoryPath, (err, files) => {
134                    if (err) {
135                        throw err;
136                    }
137
138                    /** @type {string[]} */
139                    const tsFiles = [];
140                    /** @type {string[]} */
141                    const testFiles = [];
142                    /** @type {string | undefined} */
143                    let paramFile;
144
145                    for (const filePath of files.map(f => path.join(directoryPath, f))) {
146                        if (filePathEndsWith(filePath, ".ts")) {
147                            tsFiles.push(filePath);
148
149                            if (filePathEndsWith(filePath, "-tests.ts")) {
150                                testFiles.push(filePath);
151                            }
152                        }
153                        else if (filePathEndsWith(filePath, ".tscparams")) {
154                            paramFile = filePath;
155                        }
156                    }
157
158                    if (testFiles.length === 0) {
159                        // no test files but multiple d.ts's, e.g. winjs
160                        const regexp = new RegExp(d + "(([-][0-9])|(\\.d\\.ts))");
161                        if (tsFiles.length > 1 && tsFiles.every(t => filePathEndsWith(t, ".d.ts") && regexp.test(t))) {
162                            for (const fileName of tsFiles) {
163                                importDefinitelyTypedTest(tscPath, rwcTestPath, path.basename(fileName, ".d.ts"), [fileName], paramFile);
164                            }
165                        }
166                        else {
167                            importDefinitelyTypedTest(tscPath, rwcTestPath, d, tsFiles, paramFile);
168                        }
169                    }
170                    else {
171                        for (const fileName of tsFiles) {
172                            importDefinitelyTypedTest(tscPath, rwcTestPath, path.basename(fileName, "-tests.ts"), [fileName], paramFile);
173                        }
174                    }
175                });
176            });
177    });
178}
179