-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add CLI to transpile dependencies to ES5
- Loading branch information
Showing
11 changed files
with
909 additions
and
190 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import * as fs from 'fs'; | ||
import * as path from 'path'; | ||
import * as ts from 'typescript'; | ||
import { copyFolder, getFilesWithExt } from './file-util'; | ||
import { warn } from './log'; | ||
import { getPackageJson } from './package-util'; | ||
|
||
export const ES5_DIR_NAME = '_origami-es5'; | ||
export const ES2015_DIR_NAME = '_origami-es2015'; | ||
|
||
export function getEs5Dir(packagePath: string): string { | ||
return path.join(packagePath, ES5_DIR_NAME); | ||
} | ||
|
||
export function getEs2015Dir(packagePath: string): string { | ||
return path.join(packagePath, ES2015_DIR_NAME); | ||
} | ||
|
||
export interface CompileOptions { | ||
force?: boolean; | ||
} | ||
|
||
export async function compile( | ||
packagePath: string, | ||
opts: CompileOptions = {} | ||
): Promise<boolean> { | ||
try { | ||
if ( | ||
!needsCompile(packagePath) || | ||
(isCompiled(packagePath) && !opts.force) | ||
) { | ||
return false; | ||
} | ||
|
||
const jsFiles = await getFilesWithExt('.js', packagePath, { | ||
excludeDir: [ES5_DIR_NAME, ES2015_DIR_NAME] | ||
}); | ||
if (!jsFiles.length) { | ||
return false; | ||
} | ||
|
||
await copyFolder(packagePath, getEs2015Dir(packagePath), { | ||
include: jsFiles, | ||
excludeDir: [ES5_DIR_NAME, ES2015_DIR_NAME] | ||
}); | ||
const program = ts.createProgram(jsFiles, { | ||
allowJs: true, | ||
importHelpers: true, | ||
module: ts.ModuleKind.ES2015, | ||
moduleResolution: ts.ModuleResolutionKind.NodeJs, | ||
noEmitOnError: true, | ||
outDir: getEs5Dir(packagePath), | ||
skipLibCheck: true, | ||
target: ts.ScriptTarget.ES5 | ||
}); | ||
|
||
const emitResult = program.emit(); | ||
if (emitResult.emitSkipped) { | ||
const allDiagnostics = ts | ||
.getPreEmitDiagnostics(program) | ||
.concat(emitResult.diagnostics); | ||
let errorMessage = ''; | ||
allDiagnostics.forEach(diag => { | ||
const message = ts.flattenDiagnosticMessageText( | ||
diag.messageText, | ||
ts.sys.newLine | ||
); | ||
if (diag.file) { | ||
const pos = ts.getLineAndCharacterOfPosition(diag.file, diag.start!); | ||
errorMessage += `${diag.file.fileName}:${pos.line + | ||
1}:${pos.character + 1} ${message}`; | ||
} else { | ||
errorMessage += message; | ||
} | ||
}); | ||
|
||
throw new Error(errorMessage); | ||
} | ||
|
||
return true; | ||
} catch (error) { | ||
warn('Failed to compile()'); | ||
throw error; | ||
} | ||
} | ||
|
||
function needsCompile(packagePath: string): boolean { | ||
const packageJson = getPackageJson(packagePath); | ||
return ![ | ||
'es2015', | ||
'esm2015', | ||
'esm5', | ||
'fesm2015', | ||
'fesm5', | ||
'esm2015', | ||
'module' | ||
].some(key => key in packageJson); | ||
} | ||
|
||
function isCompiled(packagePath: string): boolean { | ||
return fs.existsSync(getEs5Dir(packagePath)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import * as fs from 'fs'; | ||
import * as path from 'path'; | ||
import * as util from 'util'; | ||
import { warn } from './log'; | ||
|
||
const existsAsync = util.promisify(fs.exists); | ||
const mkdirAsync = util.promisify(fs.mkdir); | ||
const readdirAsync = util.promisify(fs.readdir); | ||
const readFileAsync = util.promisify(fs.readFile); | ||
const statAsync = util.promisify(fs.stat); | ||
const writeFileAsync = util.promisify(fs.writeFile); | ||
|
||
export interface CopyFolderSyncOptions { | ||
excludeDir?: string[]; | ||
include?: string[]; | ||
} | ||
|
||
export async function copyFolder( | ||
fromDir: string, | ||
toDir: string, | ||
opts: CopyFolderSyncOptions = {} | ||
): Promise<void> { | ||
try { | ||
if (!(await existsAsync(toDir))) { | ||
await mkdirAsync(toDir); | ||
} | ||
|
||
const names = await readdirAsync(fromDir); | ||
for (let name of names) { | ||
if (opts.excludeDir && opts.excludeDir.indexOf(name) > -1) { | ||
continue; | ||
} | ||
|
||
const fileOrFolder = path.join(fromDir, name); | ||
const target = path.join(toDir, name); | ||
if ((await statAsync(fileOrFolder)).isDirectory()) { | ||
if (!(await existsAsync(target))) { | ||
await mkdirAsync(target); | ||
} | ||
|
||
await copyFolder(fileOrFolder, target, opts); | ||
} else if (!opts.include || opts.include.indexOf(fileOrFolder) > -1) { | ||
await writeFileAsync(target, await readFileAsync(fileOrFolder)); | ||
} | ||
} | ||
} catch (error) { | ||
warn('Failed to copyFolder()'); | ||
throw error; | ||
} | ||
} | ||
|
||
export interface GetFilesWithExtOptions { | ||
excludeDir?: string[]; | ||
} | ||
|
||
export async function getFilesWithExt( | ||
ext: string, | ||
directory: string, | ||
opts: GetFilesWithExtOptions = {}, | ||
allFiles: string[] = [] | ||
): Promise<string[]> { | ||
try { | ||
const directoryName = path.basename(directory); | ||
if (opts.excludeDir && opts.excludeDir.indexOf(directoryName) > -1) { | ||
return []; | ||
} | ||
|
||
const files = await readdirAsync(directory); | ||
for (let file of files) { | ||
const absolutePath = path.resolve(directory, file); | ||
if ((await statAsync(absolutePath)).isDirectory()) { | ||
await getFilesWithExt(ext, absolutePath, opts, allFiles); | ||
} else if (path.extname(absolutePath) === ext) { | ||
allFiles.push(absolutePath); | ||
} | ||
} | ||
|
||
return allFiles; | ||
} catch (error) { | ||
warn('Failed to getFilesWithExt()'); | ||
throw error; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import chalk, { Chalk } from 'chalk'; | ||
|
||
export function info(message: string) { | ||
log(message, chalk.white); | ||
} | ||
|
||
export function warn(message: string) { | ||
log(message, chalk.yellow); | ||
} | ||
|
||
export function error(message: string, fatal?: boolean) { | ||
log(message, chalk.red); | ||
if (fatal) { | ||
process.exit(1); | ||
} | ||
} | ||
|
||
export function getPrefix(): string { | ||
return chalk.cyan('Origami: '); | ||
} | ||
|
||
function log(message: string, color: Chalk) { | ||
console.log(getPrefix() + color(message)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import * as fs from 'fs'; | ||
import * as glob from 'glob'; | ||
import * as path from 'path'; | ||
|
||
export function getPackagePaths(patterns: string[]): string[] { | ||
const paths: string[] = []; | ||
patterns.forEach(pattern => { | ||
paths.push(...glob.sync(pattern)); | ||
}); | ||
|
||
return paths.filter(p => isPackagePath(p)).map(p => path.resolve(p)); | ||
} | ||
|
||
export function isPackagePath(packagePath: string): boolean { | ||
return ( | ||
fs.existsSync(packagePath) && | ||
fs.statSync(packagePath).isDirectory() && | ||
fs.existsSync(getPackageJsonPath(packagePath)) | ||
); | ||
} | ||
|
||
export function getPackageJsonPath(packagePath: string): string { | ||
return path.join(packagePath, 'package.json'); | ||
} | ||
|
||
export function getPackageJson(packagePath: string): any { | ||
return JSON.parse(fs.readFileSync(getPackageJsonPath(packagePath), 'utf8')); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { compile, getEs2015Dir, getEs5Dir } from './compile'; | ||
import { copyFolder } from './file-util'; | ||
|
||
export interface PrepareOptions { | ||
es5: boolean; | ||
force?: boolean; | ||
} | ||
|
||
export async function prepare( | ||
packagePath: string, | ||
opts: PrepareOptions | ||
): Promise<void> { | ||
await compile(packagePath, opts); | ||
if (opts.es5) { | ||
await copyFolder(getEs5Dir(packagePath), packagePath); | ||
} else { | ||
await copyFolder(getEs2015Dir(packagePath), packagePath); | ||
} | ||
} |
Oops, something went wrong.