Skip to content

Commit

Permalink
Merge pull request #2 from roguib/path-resolver
Browse files Browse the repository at this point in the history
Path resolver
  • Loading branch information
roguib authored Aug 5, 2021
2 parents 6c898b5 + c32e690 commit 5543470
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 119 deletions.
12 changes: 3 additions & 9 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,11 @@
"request": "launch",
"name": "End to end execution",
"preLaunchTask": "npm: build:cjs",
"program": "./build/ng-vs-snippets",
"args":
[
"--dir",
"./src",
"--output",
"./.vscode"
],
"program": "./build/@roguib/ng-vs-snippets.js",
"args": ["--dir", "./src", "--output", "./.vscode"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true,
"disableOptimisticBPs": true
}
]
}
31 changes: 16 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,34 @@
# ng-vs-snippets
![ts](https://badgen.net/badge/Built%20With/TypeScript/blue) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![made-for-VSCode](https://img.shields.io/badge/Made%20for-VSCode-1f425f.svg)](https://code.visualstudio.com/) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com)


![ts](https://badgen.net/badge/Built%20With/TypeScript/blue) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![made-for-VSCode](https://img.shields.io/badge/Made%20for-VSCode-1f425f.svg)](https://code.visualstudio.com/) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com)

Automatic VS Code snippet file generation for Angular codebases. Seamlessly maintain up-to-date VS Code snippets of all of your code.

Currently, we support snippet generation from the following Angular elements:

<center>

| Element | Status |
|-----------|:-----------------------------------------:|
| Component | :white_check_mark: Supported |
| Directive | :construction_worker: Not yet supported |
| Pipe | :construction_worker: Not yet supported |
| Element | Status |
| --------- | :-------------------------------------: |
| Component | :white_check_mark: Supported |
| Directive | :construction_worker: Not yet supported |
| Pipe | :construction_worker: Not yet supported |

</center>

## Installation

Install ```ng-vs-snippets``` as a dev-dependency in your Angular project. To do so, run:
Install `ng-vs-snippets` as a dev-dependency in your Angular project. To do so, run:

```
npm i ng-vs-snippets --save-dev
npm i @roguib/ng-vs-snippets --save-dev
```

Create a ```package.json``` script to extract snippets from your codebase:
Create a `package.json` script to extract snippets from your codebase:

```json
"scripts": {
"ng-vs-snippets": "ng-vs-snippets --dir ./src --output ./.vscode",
"ng-vs-snippets": "ng-vs-snippets --dir . --output ./.vscode",
},
```

Expand All @@ -39,21 +38,23 @@ Execute the script by running:
npm run ng-vs-snippets
```

The script will generate a ```out.code-snippets``` file containing all the definitions. **Make sure you don't have any file with the same name** since the data contained in that file **is going to be replaced**.
The script will generate a `out.code-snippets` file containing all the definitions. **Make sure you don't have any file with the same name** since the data contained in that file **is going to be replaced**.

## Troubleshooting
Sometimes, due to VS Code configuration issues, snippets don't appear in the suggestion's dropdown. Make sure to specify, in VS Code ```settings.json``` configuration file the following properties:

Sometimes, due to VS Code configuration issues, snippets don't appear in the suggestion's dropdown. Make sure to specify, in VS Code `settings.json` configuration file the following properties:

```json
"editor.tabCompletion": "on",
"editor.snippetSuggestions": "top"
```
If this doesn't fix the problem, open the command palette and search for ```Preferences: Configure User Snippets``` to ensure the editor is considering the fille where your generated snippets are defined.

If this doesn't fix the problem, open the command palette and search for `Preferences: Configure User Snippets` to ensure the editor is considering the fille where your generated snippets are defined.

## Documentation

You can find the [full document design at this url]().

## Contributing

Pull requests are welcome :) Make sure to create an issue first so anyone's work is overlaped.
Pull requests are welcome :) Make sure to create an issue first so anyone's work is overlaped.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
"angular",
"vs snippets"
],
"main": "build/ng-vs-snippets.js",
"types": "build/ng-vs-snippets.d.ts",
"main": "build/@roguib/ng-vs-snippets.js",
"types": "build/@roguib/ng-vs-snippets.d.ts",
"bin": {
"ng-vs-snippets": "build/ng-vs-snippets.js"
"ng-vs-snippets": "build/@roguib/ng-vs-snippets.js"
},
"scripts": {
"build:cjs": "rollup -c",
"check": "tsc",
"run": "node ./build/index.js",
"run": "node ./build/@roguib/ng-vs-snippets.js",
"test": "npm run build:cjs && jest ./tests/*"
},
"dependencies": {
Expand Down
18 changes: 9 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
const fs = require("fs");
const path = require("path");
const readline = require("readline");
const argv = process.argv;
import * as walker from "./walker";
import * as parser from "./parser";
Expand All @@ -17,6 +15,9 @@ let config: ICLIConfig = {

const parseArgs = (args: string[]) => {
// TODO: Include multiple options

logger.log("args:", args);

while (args.length > 0) {
const arg = args.shift();

Expand Down Expand Up @@ -52,25 +53,24 @@ export const verifyArgs = () => {
if (config.outputDir == null) {
logger.err("No output directory specified. Aborting.");
}
}
};

export const run = async (args: string[]) => {
parseArgs(args);
verifyArgs();
// const config = parseArgs(args);

if (config.debug) {
logger.enableDebugger();
}

process.env.ROOT_PROJECT_PATH = config.workingDir || path.posix.resolve();

let candidateFilePaths: Array<string> = walker.walker(
config.workingDir || path.posix.resolve(),
process.env.ROOT_PROJECT_PATH as string,
[]
);
let fileData: Array<File> = parser.parser(candidateFilePaths);
generator.generator(
fileData,
config.outputDir as string
);
generator.generator(fileData, config.outputDir as string);
};

run(argv.slice(2, argv.length));
100 changes: 36 additions & 64 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const path = require("path");

import { File, Input, Output } from "./shared/IFile";
import logger from "./shared/logger";
import pathResolver from "./utils/path-resolver";

// selectors
const componentSelector = /export(\s+)class(\s+)[a-zA-Z0-9-_]+/g;
Expand Down Expand Up @@ -31,11 +32,11 @@ const regularOutputSelector = /@Output\(\)(\s+)[a-zA-Z0-9-_]+:(\s+)EventEmitter<

// other
const extendedClassSelector = /export(\s+)class(\s+)[a-zA-Z0-9-_]+(\s+)extends(\s+)[a-zA-Z0-9-_]+/g;
const extendedClassPathSelector = /import(\s+){(\s+)[a-zA-Z0-9-_]+(\s+)}(\s+)from(\s+)[\/A-Za-z0-9."'_-]+/g;
const extendedClassPathSelector = /import(\s+){(\s+)[a-zA-Z0-9-_]+(\s+)}(\s+)from(\s+)[\/\@A-Za-z0-9."'_-]+/g;
// TODO: class implementation with inputs/outputs defined

// TODO: Test in in other OS (github actions)
// TODO: Read files synchronously
// TODO: Test in other OS (github actions)
// TODO: Read files asynchronously to improve performance?
export const parser = (filePaths: Array<string>): Array<File> => {
let result: Array<File> = [];
// a temporal variable used for storing @Inputs/@Outputs declared on a parent class
Expand All @@ -61,8 +62,7 @@ export const parser = (filePaths: Array<string>): Array<File> => {
continue;
}

let fileNameData: Array<string> =
file?.match(componentSelector) || [];
let fileNameData: Array<string> = file?.match(componentSelector) || [];
if (fileNameData.length === 0) {
logger.warn("Component tag not defined by any class.");
continue;
Expand Down Expand Up @@ -93,15 +93,14 @@ export const parser = (filePaths: Array<string>): Array<File> => {
// Input() foo: 'type1' | 'type2'
let inputs: Array<Input> = [];
let inputsData: Array<string> =
file?.match(
regularInputLiteralTypeSelector
) || [];
file?.match(regularInputLiteralTypeSelector) || [];
for (let input of inputsData) {
logger.log('inputs parsed:', inputsData);
logger.log("inputs parsed:", inputsData);
let tmp: Array<string> = input.replace(/(\s)+/g, " ").split(" ");
let type = tmp
.slice(2, tmp.length)
.join()
.replace(/\"/g, "'")
.replace(";", "")
.replace(/,/g, "");
inputs.push({
Expand All @@ -113,13 +112,9 @@ export const parser = (filePaths: Array<string>): Array<File> => {

// @Input() variableName: type; and @Input() variableName: number = 9;
inputsData = [];
inputsData =
file?.match(
regularInputWithTypeSelector
) || [];
inputsData = file?.match(regularInputWithTypeSelector) || [];
for (let input of inputsData) {
let tmp: Array<string> = input.replace(/(\s+)/g, " ").split(" ");
logger.log("input data", inputsData);
inputs.push({
inputName: tmp[1].replace(":", ""),
type: tmp[2].replace(";", ""),
Expand All @@ -129,16 +124,11 @@ export const parser = (filePaths: Array<string>): Array<File> => {

inputsData = [];
// @Input('inputName') varName: type; and @Input("inputName") varName: type
inputsData =
file?.match(
customNameInputWithTypeSelector
) || [];
inputsData = file?.match(customNameInputWithTypeSelector) || [];
for (let input of inputsData) {
let tmp: Array<string> = input.replace(/(\s+)/g, " ").split(" ");
const inputName = (tmp[0].match(/('|")[a-zA-Z0-9-_]+('|")/g) || [])[0].replace(
/'|"/g,
""
);
const inputName = (tmp[0].match(/('|")[a-zA-Z0-9-_]+('|")/g) ||
[])[0].replace(/'|"/g, "");
inputs.push({
inputName,
type: tmp[2].replace(";", ""),
Expand All @@ -149,10 +139,7 @@ export const parser = (filePaths: Array<string>): Array<File> => {
// @Input('inputNameC') varName = 'adv';
// @Input("inputNameD") varName = 2354;
inputsData = [];
inputsData =
file?.match(
setterInputCustomNameSelector
) || [];
inputsData = file?.match(setterInputCustomNameSelector) || [];
for (let input of inputsData) {
let tmp: Array<string> = input.replace(/(\s+)/g, " ").split(" ");
const inputName = (tmp[0].match(/('|")[a-zA-Z0-9-_]+('|")/g) || [
Expand All @@ -167,10 +154,7 @@ export const parser = (filePaths: Array<string>): Array<File> => {

//@Input() set foo(value) {}
inputsData = [];
inputsData =
file?.match(
setterInputSelector
) || [];
inputsData = file?.match(setterInputSelector) || [];
for (let input of inputsData) {
let tmp: Array<string> = input.replace(/(\s+)/g, " ").split(" ");
const inputName = tmp[2].replace(/(\s+)/g, "").split("(")[0];
Expand All @@ -183,10 +167,7 @@ export const parser = (filePaths: Array<string>): Array<File> => {

//@Input() set foo(value: type) {}
inputsData = [];
inputsData =
file?.match(
setterInputWithTypeSelector
) || [];
inputsData = file?.match(setterInputWithTypeSelector) || [];
for (let input of inputsData) {
let tmp: Array<string> = input.replace(/(\s+)/g, " ").split(" ");
const inputName = tmp[2].replace(/(\s+)/g, "").split("(")[0];
Expand All @@ -200,18 +181,15 @@ export const parser = (filePaths: Array<string>): Array<File> => {

//@Input() set foo(value: 'type1' | 'type2') {}
inputsData = [];
inputsData =
file?.match(
setterInputLiteralTypeSelector
) || [];
inputsData = file?.match(setterInputLiteralTypeSelector) || [];
for (let input of inputsData) {
let tmp: Array<string> = input.replace(/(\s+)/g, " ").split(" ");
const inputName = tmp[2].replace(/(\s+)/g, "").split("(")[0];
const type = tmp
.slice(3, tmp.length)
.join()
.replace(/'|"|\)/g, "")
.replace(/,/g, " ");
.slice(3, tmp.length)
.join()
.replace(/'|"|\)/g, "")
.replace(/,/g, " ");
inputs.push({
inputName,
type,
Expand Down Expand Up @@ -239,10 +217,7 @@ export const parser = (filePaths: Array<string>): Array<File> => {

let outputs: Array<Output> = [];
// only @Output() buttonClick: EventEmitter<any> = new EventEmitter(); for now
let outputsData: Array<string> =
file?.match(
regularOutputSelector
) || [];
let outputsData: Array<string> = file?.match(regularOutputSelector) || [];
for (let output of outputsData) {
let tmp: Array<string> = output.replace(/(\s+)/g, " ").split(" ");
outputs.push({
Expand All @@ -257,33 +232,23 @@ export const parser = (filePaths: Array<string>): Array<File> => {
logger.log("Outputs detected:", outputs);

let extendedClassPath;
if (
file?.match(
extendedClassSelector
)
) {
if (file?.match(extendedClassSelector)) {
// we should see if the extended class is in tmp and if not extract the inputs defined inside
let matchExtendedClass: Array<string> =
file?.match(
extendedClassSelector
) || [];
file?.match(extendedClassSelector) || [];
// resolve the path of the class
let extendedClass: string = matchExtendedClass[0]
.replace(/(\s+)/g, " ")
.split(" ")[4];
logger.log("extendedClassName:", extendedClass);
let matchExtendedClassPath: Array<string> =
file?.match(
extendedClassPathSelector
) || [];
// TODO: Document this in notes. Notice that by using path.join(path.dirname(fullComponentClassPath), relative path of the base path from ComponentClassPath) resolves into the full path of the base path
extendedClassPath = path.join(
path.dirname(filePath),
file?.match(extendedClassPathSelector) || [];

extendedClassPath = pathResolver.resolve(
filePath,
matchExtendedClassPath[0]
.replace(/(\s+)/g, " ")
.replace(/"/g, "")
.split(" ")[5] + ".ts"
);

logger.log("path:", extendedClassPath);
}

Expand All @@ -297,8 +262,15 @@ export const parser = (filePaths: Array<string>): Array<File> => {
extendedClassFilepath: extendedClassPath || undefined,
});
} else {
/**
* TODO: Instead of working with relative paths and converting them
* to absolute when needed, we can start the exec by transforming every
* relative path to absolute, and then clean up the resolve calls in the program
* that transforms the code into an spaguetti one. Also it could help by reducing
* the amount of times we call path.join(path.posix.resolve(), path);
*/
tmp.push({
fileLocation: filePath,
fileLocation: path.resolve(filePath),
inputs: inputs,
outputs: outputs,
extendedClassFilepath: undefined,
Expand Down
Loading

0 comments on commit 5543470

Please sign in to comment.