import * as path from "path"; import * as fs from "fs"; import readdirp, { EntryInfo } from "readdirp"; const inputFolder = path.resolve("dist/nativescript-core"); const outputFolder = path.resolve("dist/tns-core-modules"); const testImports: string[] = []; // List of definition files that don't need to be exported. const dtsBlacklist = [ "module.d.ts", "nativescript-error.d.ts", "references.d.ts", "tns-core-modules.d.ts" ]; // List of modules that should be re-exported despite they are private const privateModulesWhitelist = [ "ui/styling/style-scope" //Reason: nativescript-dev-webpack generates code that imports this module ] // There are few module using the "export default" syntax // They should be handled differently when re-exporting const modulesWithDefaultExports = [ "utils/lazy" ]; function traverseInputDir(fileFilter: string[], callback: (entry: EntryInfo) => void) { return new Promise((resolve, reject) => { readdirp(inputFolder, { fileFilter, directoryFilter: (di: EntryInfo) => { return !di.path.startsWith("node_modules") && !di.path.startsWith("platforms"); } }) .on("data", callback) .on("error", reject) .on("end", resolve); }); } function processPackageJsonFile(entry: EntryInfo) { const dirPath = path.dirname(entry.path); const outputFilePath = path.join(outputFolder, entry.path); ensureDirectoryExistence(outputFilePath); const json = require(entry.fullPath); if (json.main) { (fs).copyFileSync(entry.fullPath, outputFilePath); logFileCreated(outputFilePath); addTestImport(dirPath); const mainFile = path.join(dirPath, json.main); createReExportFile(mainFile, ".ts"); addTestImport(mainFile); } } function processDefinitionFile(entry: EntryInfo) { if (dtsBlacklist.includes(entry.path)) { return; } const relativeFilePathNoExt = entry.path.replace(/\.d\.ts$/, ""); // Re-export everything from d.ts file createReExportFile(relativeFilePathNoExt, ".d.ts"); // This might be only a definitions file. // So check if there is ts/js files before creating TS file with re-exports const baseFile = path.join(inputFolder, relativeFilePathNoExt); if (fs.existsSync(baseFile + ".ts") || fs.existsSync(baseFile + ".js") || (fs.existsSync(baseFile + ".android.ts") && fs.existsSync(baseFile + ".ios.ts")) || (fs.existsSync(baseFile + ".android.js") && fs.existsSync(baseFile + ".ios.js"))) { createReExportFile(relativeFilePathNoExt, ".ts"); addTestImport(relativeFilePathNoExt); } } function processTypeScriptFile(entry: EntryInfo) { const relativeFilePathNoExt = entry.path.replace(/\.ts$/, ""); createReExportFile(relativeFilePathNoExt, ".ts"); addTestImport(relativeFilePathNoExt); } function createReExportFile(pathNoExt: string, ext: ".ts" | ".d.ts") { const outputFile = path.join(outputFolder, pathNoExt + ext); if (!fs.existsSync(outputFile)) { ensureDirectoryExistence(outputFile); let content = `export * from "@nativescript/core/${pathNoExt}";` if (modulesWithDefaultExports.includes(pathNoExt)) { content = `import defExport from "@nativescript/core/${pathNoExt}";\n`; content += `export default defExport;` } fs.writeFileSync(outputFile, content); logFileCreated(outputFile); } } function ensureDirectoryExistence(filePath: string) { const dirname = path.dirname(filePath); if (fs.existsSync(dirname)) { return true; } ensureDirectoryExistence(dirname); fs.mkdirSync(dirname); } function logFileCreated(file: string) { console.log(`CREATED: ${file}`); } function addTestImport(moduleName: string) { testImports.push(moduleName); } function generateTestFile() { const uniqueImports = Array.from(new Set(testImports)).sort(); const output: string[] = []; output.push(`/* tslint:disable */`); output.push(`import { compare, report } from "./module-compare";\n\n`); uniqueImports.forEach((name) => { const moduleName = name.replace(/[\.\/\-]/g, "_"); const compatName = `module_${moduleName}_compat`; const coreName = `module_${moduleName}_core`; output.push(`import * as ${coreName} from "@nativescript/core/${name}";`); output.push(`import * as ${compatName} from "tns-core-modules/${name}";`); output.push(`compare("${name}", ${coreName}, ${compatName});\n`); }); output.push(`\n`); output.push(`report();`); const testFilePath = path.resolve("dist/generated-tests/tests.ts"); ensureDirectoryExistence(testFilePath); fs.writeFileSync(testFilePath, output.join("\n"), "utf8"); (fs).copyFileSync(path.resolve("build/generated-compat-checks/module-compare.ts"), path.resolve("dist/generated-tests/module-compare.ts")); console.log(`Compat tests generated: ${testFilePath}`); } function generateExportsForPrivateModules() { privateModulesWhitelist.forEach(pathNoExt => { createReExportFile(pathNoExt, ".ts"); addTestImport(pathNoExt); }) } (async () => { console.log(" ------> GENERATING FILES FORM PACKAGE.JSON"); // Traverse all package.json files and create: // * .ts file with re-exports for the package.json/main // * .d.ts file with re-exports for the package.json/types await traverseInputDir(["package.json"], processPackageJsonFile); console.log(" ------> GENERATING FILES FORM DEFINITIONS"); // Traverse all d.ts files and create // * .d.ts file with re-exports for definitions for the .d.ts // * .ts file with re-exports for the corresponding ts/js file (is such exists) await traverseInputDir(["*.d.ts"], processDefinitionFile); console.log(" ------> GENERATING FILES FROM TYPESCRIPT"); // Traverse all ts files which are not platform specific and create // * .ts file with re-exports for the corresponding ts file await traverseInputDir(["*(? { console.log("Error generating tns-core-modules files: " + e); });