backstage
1/*
2* Copyright 2020 The Backstage Authors
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16
17import { relative as relativePath } from 'path';18import { spawn } from 'child_process';19import { OptionValues } from 'commander';20import { findPaths } from '@backstage/cli-common';21import { platform } from 'os';22import { ExitCodeError } from './errors';23
24// eslint-disable-next-line no-restricted-syntax
25const paths = findPaths(__dirname);26
27export function createCodemodAction(name: string) {28return async (dirs: string[], opts: OptionValues) => {29const transformPath = relativePath(30process.cwd(),31paths.resolveOwn('transforms', `${name}.js`),32);33
34const args = [35'--parser=tsx',36'--extensions=tsx,js,ts,tsx',37'--transform',38transformPath,39'--ignore-pattern=**/node_modules/**',40];41
42if (opts.dry) {43args.push('--dry');44}45
46if (dirs.length) {47args.push(...dirs);48} else {49args.push('.');50}51
52console.log(`Running jscodeshift with these arguments: ${args.join(' ')}`);53
54let command;55if (platform() === 'win32') {56command = 'jscodeshift';57} else {58// jscodeshift ships a slightly broken bin script with windows59// line endings so we need to execute it using node rather than60// letting the `#!/usr/bin/env node` take care of it61command = process.argv0;62args.unshift(require.resolve('.bin/jscodeshift'));63}64
65const child = spawn(command, args, {66stdio: 'inherit',67shell: true,68env: {69...process.env,70FORCE_COLOR: 'true',71},72});73
74if (typeof child.exitCode === 'number') {75if (child.exitCode) {76throw new ExitCodeError(child.exitCode, name);77}78return;79}80
81await new Promise<void>((resolve, reject) => {82child.once('error', error => reject(error));83child.once('exit', code => {84if (code) {85reject(new ExitCodeError(code, name));86} else {87resolve();88}89});90});91};92}
93