Last active
June 27, 2024 09:47
-
-
Save PhiLhoSoft/2854f64f758478129179648560d47b1d to your computer and use it in GitHub Desktop.
VSCode Macros (exceedsystem.vscode-macros) for Angular refactoring
This file contains hidden or 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
const vscode = require('vscode'); | |
/* | |
* VSCode Macros (exceedsystem.vscode-macros) for Angular refactoring. | |
* | |
* Macro configuration settings | |
* { | |
* [name: string]: { ... Name of the macro | |
* no: number, ... Order of the macro | |
* func: () => string | undefined ... Name of the body of the macro function; if returning a string, it is shown in a notification. | |
* } | |
* } | |
*/ | |
module.exports.macroCommands = { | |
ConvertInjection: { | |
no: 1, | |
func: convertInjection, | |
}, | |
}; | |
/** | |
* Convert a classical Angular injection in a constructor to the modern version with inject(). | |
* | |
* You have to move the line out of the constructor, as a field declaration, of course. | |
*/ | |
function convertInjection() { | |
const editor = vscode.window.activeTextEditor; | |
if (!editor) { | |
// Return an error message if necessary. For example when focus when running the macro isn't on an editor. | |
return 'Editor is not opening.'; | |
} | |
const document = editor.document; | |
const line = document.lineAt(editor.selection.active.line); | |
// Would be cleaner to do a semantic analysis, but it would need an external library (?) and some knowledge yet to learn. | |
// So I use a regexp matching the most common patterns found in our code. | |
const changedLine = line.text.replace( | |
// Match the starting indentation, an optional injection token, an optional indicator of optional injection, | |
// the visibility keyword (mandatory, we work on injected fields only), the optional override keyword, | |
// the optional (but mandatory in our code!) readonly keyword, | |
// then the declared identifier itself, perhaps followed by a question mark if optional, and the type separator (colon), | |
// followed by the type, potentially with a generic type (simple only in our code), and a final comma. | |
/^(?<indentation>\s+)(?:@Inject\((?<token>\w+)\) )?(?<optional>@Optional\(\) )?(?<visibility>private|public|protected) ?(?<override>override)? ?(?<ro>readonly)? ?(?<identifier>\w+)(?<opt>\?)?: (?<type>\w+)(?<generic><\w+>)?,$/, | |
// The matched string, positional parameters (ignored, I don't want to rely on order alone), offset of match, the target (ie. line.text), | |
// and a Record with the capture names as keys (the "(?<name>" pattern) and the captured parts as values (undefined if optional & not found). | |
(match, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, offset, target, g) => { | |
// We reorder the parts, using the names, detecting missing optional parts. | |
return `${ | |
g.indentation}${ | |
// public being the default, we omit it at field / method declaration level. | |
g.visibility !== 'public' ? g.visibility + ' ' : ''}${ | |
g.override ? 'override ' : ''}${g.ro ? 'readonly ' : ''}${ | |
g.identifier}${ | |
g.generic || g.token ? `: ${g.type}${g.generic ?? ''}${g.optional ? ' | null' : ''}` : ''} = inject(${ | |
g.token ?? g.type}${ | |
g.optional ? ', { optional: true }' : ''});`; | |
}, | |
); | |
editor.edit((edit) => { | |
edit.replace(line.range, changedLine); | |
}); | |
// Go to next line to allow quick chaining of these commands. | |
vscode.commands.executeCommand('cursorMove', { to: 'down', by: 'wrappedLine', value: 1 }); | |
} |
Author
PhiLhoSoft
commented
Jun 27, 2024
/** Convert `styleUrls: ['one-item'],` to `styleUrl: 'one-item',`. */
function convertStyleUrls() {
const editor = vscode.window.activeTextEditor;
if (!editor) {
// Return an error message if necessary. For example when focus when running the macro isn't on an editor.
return 'Editor is not opening.';
}
const document = editor.document;
const line = document.lineAt(editor.selection.active.line);
const changedLine = line.text.replace(
/^(?<indentation>\s+)styleUrls: \['(?<path>[\w./-]+)'\],$/,
(match, _1, _2, offset, target, g) => {
return `${g.indentation}styleUrl: '${g.path}',`;
},
);
editor.edit((edit) => {
edit.replace(line.range, changedLine);
});
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment