jscodeshift TypeScript codemod - удалить общий тип, но сохранить обернутый тип

Сейчас я пытаюсь написать код, который удалит все $ReadOnly<T> общий из кодовой базы TypeScript, сохраняя только T (T являясь объектом / объединением)

Пока это то, что я придумал

module.exports = (fileInfo, api) => {
const j = api.jscodeshift
const source = j(fileInfo.source)

source
.find(j.TSTypeAliasDeclaration)
.find(j.TSTypeReference)
.filter(x => {
    return x.value.typeName.name === '$ReadOnly' && x.value.typeParameters.params[0].type === 'TSTypeLiteral'
})
.replaceWith(nodePath => {
    const members = []
    nodePath.value.typeParameters.params[0].members.forEach(x => {
        members.push(j.tsPropertySignature(x.key, x.typeAnnotation))
    })

    return j.tsTypeLiteral(members)
})

return source
    .toSource()
}

Идея состоит в том, чтобы изменить что-то вроде этого:

export type MyType = $ReadOnly<{
  someProps: string,
}>

К тому, что:

export type MyType = {
  someProps: string,
}

К сожалению, это то, что у меня получается, с дубликатом type ключевое слово:

export type type MyType = {
  someProps: string,
}

Есть идеи, что здесь могло пойти не так?

1 ответ

Его можно записать декларативно с putout кодом трансформатора (вы можете попробовать его в putout.cloudcmd.io ):

      // type-updater.js
const {replaceWith} = require('putout').operator;

module.exports.report = () => '$ReadOnly generic should be removed';

module.exports.match = () => ({
    'export type __a = __b': ({__b}, path) => {
        return __b.name === '$ReadOnly';
    }
});
    
module.exports.replace = () => ({
    'export type __a = __b': (vars, path) => {
        const typeAnnotationPath = path.get('declaration.typeAnnotation');
        const paramPath = typeAnnotationPath.get('typeParameters.params.0');
        
        replaceWith(typeAnnotationPath, paramPath);
        
        return path;
    },
});

Это Заменитель типа putout plugin.

Это изменит ввод:

      // fixture/update-type.js
export type MyType = $ReadOnly<{
  someProps: string,
}>
    
export type MyType2 = $WriteOnly<{
  someProps: string,
}>
    
export type MyType1 = {
  someProps: string,
}

На выходе:

      // fixture/update-type-fix.js
export type MyType = {
  someProps: string,
};
    
export type MyType2 = $WriteOnly<{
  someProps: string,
}>
    
export type MyType1 = {
  someProps: string,
}

Putoutимеет простой инструмент запуска тестов, поэтому вы можете протестировать его с помощью предопределенных приспособлений, используя:

      // type-updater.spec.js
const test = require('@putout/test')(__dirname, {
     'update-type': require('./type-updater'),
});

test('update-type: report', (t) => {
    t.report('update-type', '$ReadOnly generic should be removed');
});

test('update-type: transform', (t) => {
    t.transform('update-type');
    t.end();
});

Чтобы запустить это codemod сохраните это в ~/.putout и запустите свою кодовую базу с помощью:

      putout .

Или сохраните в каталоге your-project/codemods и запустите:

      putout --rulesdir codemods .
Другие вопросы по тегам