From ad1db987b55b45f8e152da0ff72996f3bf8bb2bb Mon Sep 17 00:00:00 2001 From: Convly Date: Mon, 7 Mar 2022 11:11:50 +0100 Subject: [PATCH] Add typescript utils to the utils (commands, tools, compilers) --- .../core/strapi/lib/utils/import-default.js | 9 +++++ packages/core/strapi/lib/utils/index.js | 2 + .../lib/utils/typescript/commands/build.js | 18 +++++++++ .../lib/utils/typescript/commands/develop.js | 18 +++++++++ .../lib/utils/typescript/commands/index.js | 9 +++++ .../lib/utils/typescript/compilers/basic.js | 38 +++++++++++++++++++ .../lib/utils/typescript/compilers/index.js | 9 +++++ .../lib/utils/typescript/compilers/watch.js | 37 ++++++++++++++++++ .../lib/utils/typescript/copy-resources.js | 12 ++++++ .../lib/utils/typescript/format-host.js | 15 ++++++++ .../lib/utils/typescript/get-config-path.js | 9 +++++ .../core/strapi/lib/utils/typescript/index.js | 23 +++++++++++ .../utils/typescript/is-typescript-project.js | 11 ++++++ .../utils/typescript/report-diagnostics.js | 19 ++++++++++ .../typescript/resolve-config-options.js | 23 +++++++++++ 15 files changed, 252 insertions(+) create mode 100644 packages/core/strapi/lib/utils/import-default.js create mode 100644 packages/core/strapi/lib/utils/typescript/commands/build.js create mode 100644 packages/core/strapi/lib/utils/typescript/commands/develop.js create mode 100644 packages/core/strapi/lib/utils/typescript/commands/index.js create mode 100644 packages/core/strapi/lib/utils/typescript/compilers/basic.js create mode 100644 packages/core/strapi/lib/utils/typescript/compilers/index.js create mode 100644 packages/core/strapi/lib/utils/typescript/compilers/watch.js create mode 100644 packages/core/strapi/lib/utils/typescript/copy-resources.js create mode 100644 packages/core/strapi/lib/utils/typescript/format-host.js create mode 100644 packages/core/strapi/lib/utils/typescript/get-config-path.js create mode 100644 packages/core/strapi/lib/utils/typescript/index.js create mode 100644 packages/core/strapi/lib/utils/typescript/is-typescript-project.js create mode 100644 packages/core/strapi/lib/utils/typescript/report-diagnostics.js create mode 100644 packages/core/strapi/lib/utils/typescript/resolve-config-options.js diff --git a/packages/core/strapi/lib/utils/import-default.js b/packages/core/strapi/lib/utils/import-default.js new file mode 100644 index 0000000000..d59626d113 --- /dev/null +++ b/packages/core/strapi/lib/utils/import-default.js @@ -0,0 +1,9 @@ +'use strict'; + +const __importDefault = + (this && this.__importDefault) || + function(mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; + +module.exports = __importDefault; diff --git a/packages/core/strapi/lib/utils/index.js b/packages/core/strapi/lib/utils/index.js index 6d4ea2a031..f4888ac7c0 100644 --- a/packages/core/strapi/lib/utils/index.js +++ b/packages/core/strapi/lib/utils/index.js @@ -3,9 +3,11 @@ const openBrowser = require('./open-browser'); const isInitialized = require('./is-initialized'); const getDirs = require('./get-dirs'); +const ts = require('./typescript'); module.exports = { isInitialized, openBrowser, getDirs, + ts, }; diff --git a/packages/core/strapi/lib/utils/typescript/commands/build.js b/packages/core/strapi/lib/utils/typescript/commands/build.js new file mode 100644 index 0000000000..bc6833c718 --- /dev/null +++ b/packages/core/strapi/lib/utils/typescript/commands/build.js @@ -0,0 +1,18 @@ +'use strict'; + +const compilers = require('../compilers'); +const getConfigPath = require('../get-config-path'); +const copyResources = require('../copy-resources'); + +/** + * @param {string} dir + */ +module.exports = async dir => { + console.log('Compiling TypeScript files...'); + + const configPath = getConfigPath(dir); + + compilers.basic.run(configPath); + + await copyResources(dir); +}; diff --git a/packages/core/strapi/lib/utils/typescript/commands/develop.js b/packages/core/strapi/lib/utils/typescript/commands/develop.js new file mode 100644 index 0000000000..1c1fc4382d --- /dev/null +++ b/packages/core/strapi/lib/utils/typescript/commands/develop.js @@ -0,0 +1,18 @@ +'use strict'; + +const compilers = require('../compilers'); +const getConfigPath = require('../get-config-path'); +const copyResources = require('../copy-resources'); + +/** + * @param {string} dir + */ +module.exports = async dir => { + console.log('Compiling TypeScript files and watching for files change...'); + + const configPath = getConfigPath(dir); + + compilers.watch.run(configPath); + + await copyResources(dir); +}; diff --git a/packages/core/strapi/lib/utils/typescript/commands/index.js b/packages/core/strapi/lib/utils/typescript/commands/index.js new file mode 100644 index 0000000000..30e4d9bffc --- /dev/null +++ b/packages/core/strapi/lib/utils/typescript/commands/index.js @@ -0,0 +1,9 @@ +'use strict'; + +const build = require('./build'); +const develop = require('./develop'); + +module.exports = { + build, + develop, +}; diff --git a/packages/core/strapi/lib/utils/typescript/compilers/basic.js b/packages/core/strapi/lib/utils/typescript/compilers/basic.js new file mode 100644 index 0000000000..e56d98c66b --- /dev/null +++ b/packages/core/strapi/lib/utils/typescript/compilers/basic.js @@ -0,0 +1,38 @@ +'use strict'; + +const ts = require('typescript'); + +const reportDiagnostics = require('../report-diagnostics'); +const resolveConfigOptions = require('../resolve-config-options'); + +module.exports = { + /** + * Default TS -> JS Compilation for Strapi + * @param {string} tsConfigPath + */ + run(tsConfigPath) { + // Parse the tsconfig.json file & resolve the configuration options + const { fileNames, options, projectReferences } = resolveConfigOptions(tsConfigPath); + + const program = ts.createProgram({ + rootNames: fileNames, + projectReferences, + options, + }); + + const emitResults = program.emit(); + + const diagnostics = ts.sortAndDeduplicateDiagnostics( + ts.getPreEmitDiagnostics(program).concat(emitResults.diagnostics) + ); + + if (diagnostics.length > 0) { + reportDiagnostics(diagnostics); + } + + // If the compilation failed, exit early + if (emitResults.emitSkipped) { + process.exit(1); + } + }, +}; diff --git a/packages/core/strapi/lib/utils/typescript/compilers/index.js b/packages/core/strapi/lib/utils/typescript/compilers/index.js new file mode 100644 index 0000000000..730e223b45 --- /dev/null +++ b/packages/core/strapi/lib/utils/typescript/compilers/index.js @@ -0,0 +1,9 @@ +'use strict'; + +const basic = require('./basic'); +const watch = require('./watch'); + +module.exports = { + basic, + watch, +}; diff --git a/packages/core/strapi/lib/utils/typescript/compilers/watch.js b/packages/core/strapi/lib/utils/typescript/compilers/watch.js new file mode 100644 index 0000000000..0240f006a0 --- /dev/null +++ b/packages/core/strapi/lib/utils/typescript/compilers/watch.js @@ -0,0 +1,37 @@ +'use strict'; + +const ts = require('typescript'); + +const reportDiagnostics = require('../report-diagnostics'); +const formatHost = require('../format-host'); +const resolveConfigOptions = require('../resolve-config-options'); + +/** + * Prints a diagnostic every time the watch status changes. + * This is mainly for messages like "Starting compilation" or "Compilation completed". + */ +const reportWatchStatusChanged = diagnostic => { + console.info(ts.formatDiagnostic(diagnostic, formatHost)); +}; + +module.exports = { + run(configPath) { + const createProgram = ts.createSemanticDiagnosticsBuilderProgram; + + const { fileNames, options, projectReferences, watchOptions } = resolveConfigOptions( + configPath + ); + const host = ts.createWatchCompilerHost( + fileNames, + options, + ts.sys, + createProgram, + reportDiagnostics, + reportWatchStatusChanged, + projectReferences, + watchOptions + ); + + ts.createWatchProgram(host); + }, +}; diff --git a/packages/core/strapi/lib/utils/typescript/copy-resources.js b/packages/core/strapi/lib/utils/typescript/copy-resources.js new file mode 100644 index 0000000000..8196bdca66 --- /dev/null +++ b/packages/core/strapi/lib/utils/typescript/copy-resources.js @@ -0,0 +1,12 @@ +'use strict'; + +const path = require('path'); +const fse = require('fs-extra'); + +const DEFAULT_RESOURCES_PATHS = ['public', 'favicon.ico', 'package.json']; + +module.exports = async (dir, resources = DEFAULT_RESOURCES_PATHS) => { + await Promise.all( + resources.map(resourceName => fse.copy(resourceName, path.join(dir, 'dist', resourceName))) + ); +}; diff --git a/packages/core/strapi/lib/utils/typescript/format-host.js b/packages/core/strapi/lib/utils/typescript/format-host.js new file mode 100644 index 0000000000..7b33c20e3b --- /dev/null +++ b/packages/core/strapi/lib/utils/typescript/format-host.js @@ -0,0 +1,15 @@ +'use strict'; + +const ts = require('typescript'); +const { identity } = require('lodash/fp'); + +/** + * @type {ts.FormatDiagnosticsHost} + */ +const formatHost = { + getCanonicalFileName: identity, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getNewLine: () => ts.sys.newLine, +}; + +module.exports = formatHost; diff --git a/packages/core/strapi/lib/utils/typescript/get-config-path.js b/packages/core/strapi/lib/utils/typescript/get-config-path.js new file mode 100644 index 0000000000..65bea4427c --- /dev/null +++ b/packages/core/strapi/lib/utils/typescript/get-config-path.js @@ -0,0 +1,9 @@ +'use strict'; + +const ts = require('typescript'); + +const DEFAULT_FILE_NAME = 'tsconfig.json'; + +module.exports = (dir, filename = DEFAULT_FILE_NAME) => { + return ts.findConfigFile(dir, ts.sys.fileExists, filename); +}; diff --git a/packages/core/strapi/lib/utils/typescript/index.js b/packages/core/strapi/lib/utils/typescript/index.js new file mode 100644 index 0000000000..74ca65bea3 --- /dev/null +++ b/packages/core/strapi/lib/utils/typescript/index.js @@ -0,0 +1,23 @@ +'use strict'; + +const isTypeScriptProject = require('./is-typescript-project'); +const getConfigPath = require('./get-config-path'); +const reportDiagnostics = require('./report-diagnostics'); +const resolveConfigOptions = require('./resolve-config-options'); +const copyResources = require('./copy-resources'); +const formatHost = require('./format-host'); + +const compilers = require('./compilers'); +const commands = require('./commands'); + +module.exports = { + isTypeScriptProject, + getConfigPath, + reportDiagnostics, + resolveConfigOptions, + copyResources, + formatHost, + + compilers, + commands, +}; diff --git a/packages/core/strapi/lib/utils/typescript/is-typescript-project.js b/packages/core/strapi/lib/utils/typescript/is-typescript-project.js new file mode 100644 index 0000000000..56ca57222e --- /dev/null +++ b/packages/core/strapi/lib/utils/typescript/is-typescript-project.js @@ -0,0 +1,11 @@ +'use strict'; + +const fse = require('fs-extra'); + +const getConfigPath = require('./get-config-path'); + +module.exports = (dir, filename = undefined) => { + const filePath = getConfigPath(dir, filename); + + return fse.pathExists(filePath); +}; diff --git a/packages/core/strapi/lib/utils/typescript/report-diagnostics.js b/packages/core/strapi/lib/utils/typescript/report-diagnostics.js new file mode 100644 index 0000000000..09b6de8432 --- /dev/null +++ b/packages/core/strapi/lib/utils/typescript/report-diagnostics.js @@ -0,0 +1,19 @@ +'use strict'; + +const ts = require('typescript'); + +const formatHost = require('./format-host'); + +/** + * Report one or several diagnostic to the console + * @param {ts.Diagnostic[] | ts.Diagnostic} diagnostics + */ +module.exports = diagnostics => { + const formattedDiagnostics = ts.formatDiagnosticsWithColorAndContext( + Array.isArray(diagnostics) ? diagnostics : [diagnostics], + formatHost + ); + + console.error(formattedDiagnostics); + console.info(`Found ${diagnostics.length} error(s).${ts.sys.newLine}`); +}; diff --git a/packages/core/strapi/lib/utils/typescript/resolve-config-options.js b/packages/core/strapi/lib/utils/typescript/resolve-config-options.js new file mode 100644 index 0000000000..89c3d76cc6 --- /dev/null +++ b/packages/core/strapi/lib/utils/typescript/resolve-config-options.js @@ -0,0 +1,23 @@ +'use strict'; + +const ts = require('typescript'); + +const logDiagnostics = require('./report-diagnostics'); + +module.exports = configPath => { + // Parse the tsconfig.json file and resolve every file name & compiler options + const { errors, ...configOptions } = ts.getParsedCommandLineOfConfigFile( + configPath, + undefined, + ts.sys + ); + + // If there are errors in the tsconfig.json + // file, report them and exit early + if (errors.length > 0) { + logDiagnostics(errors); + process.exit(1); + } + + return configOptions; +};