Skip to content

Commit

Permalink
Merge d12f4b4 into b765378
Browse files Browse the repository at this point in the history
  • Loading branch information
tianyiw2013 committed Nov 11, 2022
2 parents b765378 + d12f4b4 commit ce93c87
Show file tree
Hide file tree
Showing 13 changed files with 597 additions and 25 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,26 @@
All notable changes to the "php-docblocker" extension will be documented in this file.

## [Unreleased]
- Supported variable docblock
```php
# Example

/** @var int $var */
$var = 1;

/** @var stdClass $object */
$object = new stdClass;

/** @var \Closure $callback */
$callback = function () {};
$callback = fn () => 1;

/** @var [type] $item */
foreach ($data as $item) {}

/** @var [type] $item */
while ($item = array_pop($data)) {}
```

## [2.7.0] - 2022-02-11
- Allow configuration of default type
Expand Down
24 changes: 24 additions & 0 deletions src/block/ForeachBlock.ts
@@ -0,0 +1,24 @@
import { Doc, Param } from "../doc";
import VariableBlock from "./VariableBlock";

/**
* Represents an var block for `foreach`
*/
export default class ForeachBlock extends VariableBlock
{

/**
* @inheritdoc
*/
protected pattern:RegExp = /^\s*foreach\s*\(.*?as\s+(\$[a-z_][a-z0-9_]*\s*=>\s*)?(\$[a-z_][a-z0-9_]*)\s*\)/im;

/**
* @inheritdoc
*/
public parse():Doc
{
let params = this.match();
return this.parseVar(params[2]);
}
}

46 changes: 46 additions & 0 deletions src/block/VariableBlock.ts
@@ -0,0 +1,46 @@
import { Block } from "../block";
import { Doc, Param } from "../doc";
import Config from "../util/config";
import TypeUtil from "../util/TypeUtil";

/**
* Represents an var block
*/
export default class VariableBlock extends Block
{

/**
* @inheritdoc
*/
protected pattern:RegExp = /^\s*(\$[a-z0-9_]+)\s*\=?\s*([^;]*)/im;

/**
* @inheritdoc
*/
public parse():Doc
{
let params = this.match();
return this.parseVar(params[1], params[2]);
}

/**
* parse
*
* @param key e.g.`$key`
* @param value
* @returns
*/
protected parseVar(key: string, value: any=undefined): Doc
{
let doc = new Doc(key.substring(1));
if (value) {
doc.var = TypeUtil.instance.getTypeFromValue(value);
} else {
doc.var = TypeUtil.instance.getDefaultType();
}
doc.inline = true;

return doc;
}
}

24 changes: 24 additions & 0 deletions src/block/WhileBlock.ts
@@ -0,0 +1,24 @@
import { Doc, Param } from "../doc";
import VariableBlock from "./VariableBlock";

/**
* Represents an var block for `while`
*/
export default class WhileBlock extends VariableBlock
{

/**
* @inheritdoc
*/
protected pattern:RegExp = /^\s*while\s*\((\$[a-z0-9_]+)\s*=(?!=)/im;

/**
* @inheritdoc
*/
public parse():Doc
{
let params = this.match();
return this.parseVar(params[1]);
}
}

34 changes: 24 additions & 10 deletions src/doc.ts
Expand Up @@ -26,6 +26,13 @@ export class Doc
*/
public params:Array<Param> = [];

/**
* Doc inline
*
* Currently only used for variable block.
*/
public inline:boolean = false;

/**
* Return tag
*
Expand Down Expand Up @@ -87,6 +94,9 @@ export class Doc
if (input.message !== undefined) {
this.message = input.message;
}
if (input.inline !== undefined) {
this.inline = input.inline;
}
if (input.params !== undefined && Array.isArray(input.params)) {
input.params.forEach(param => {
this.params.push(new Param(param.type, param.name));
Expand Down Expand Up @@ -222,22 +232,26 @@ export class Doc
templateArray.pop();
}

let templateString:string = templateArray.join("\n");
let templateString: string;
if (this.inline && templateArray.length === 3) {
templateString = "/** " + templateArray[2] + " \$" + templateArray[0] + " \${###} */";
} else {
templateString = templateArray.join("\n");
templateString = templateString.replace(/^$/gm, " *");
templateString = templateString.replace(/^(?!(\s\*|\/\*))/gm, " * $1");
if (Config.instance.get('autoClosingBrackets') == "never") {
templateString = "\n" + templateString + "\n */";
} else {
templateString = "/**\n" + templateString + "\n */";
}
}

let stop = 0;
templateString = templateString.replace(/###/gm, function():string {
stop++;
return stop + "";
});

templateString = templateString.replace(/^$/gm, " *");
templateString = templateString.replace(/^(?!(\s\*|\/\*))/gm, " * $1");

if (Config.instance.get('autoClosingBrackets') == "never") {
templateString = "\n" + templateString + "\n */";
} else {
templateString = "/**\n" + templateString + "\n */";
}

let snippet = new SnippetString(templateString);

return snippet;
Expand Down
18 changes: 18 additions & 0 deletions src/documenter.ts
Expand Up @@ -3,6 +3,9 @@ import FunctionBlock from "./block/function";
import Property from "./block/property";
import Class from "./block/class";
import {Doc, Param} from "./doc";
import VariableBlock from "./block/VariableBlock";
import ForeachBlock from "./block/ForeachBlock";
import WhileBlock from "./block/WhileBlock";

/**
* Check which type of docblock we need and instruct the components to build the
Expand Down Expand Up @@ -59,6 +62,21 @@ export default class Documenter
return cla.parse().build();
}

let variable = new VariableBlock(this.targetPosition, this.editor);
if (variable.test()) {
return variable.parse().build();
}

let foreach = new ForeachBlock(this.targetPosition, this.editor);
if (foreach.test()) {
return foreach.parse().build();
}

let while_ = new WhileBlock(this.targetPosition, this.editor);
if (while_.test()) {
return while_.parse().build();
}

return new Doc().build(true);
}
}
39 changes: 34 additions & 5 deletions src/util/TypeUtil.ts
Expand Up @@ -145,6 +145,11 @@ export default class TypeUtil {
return 'integer';
}
return 'int';
case 'real':
case 'double':
return 'float';
case 'unset':
return 'null';
default:
return name;
}
Expand All @@ -159,15 +164,13 @@ export default class TypeUtil {
*/
public getTypeFromValue(value:string):string
{
let result:Array<string>;

// Check for bool
// Check for bool `false` `true` `!exp`
if (value.match(/^\s*(false|true)\s*$/i) !== null || value.match(/^\s*\!/i) !== null) {
return this.getFormattedTypeByName('bool');
}

// Check for int
if (value.match(/^\s*([\d-]+)\s*$/) !== null) {
// Check for int `-1` `1` `1_000_000`
if (value.match(/^\s*(\-?\d[\d_]*)\s*$/) !== null) {
return this.getFormattedTypeByName('int');
}

Expand All @@ -176,6 +179,11 @@ export default class TypeUtil {
return 'float';
}

// Check for float `.1` `1.1` `-1.1` `0.1_000_1`
if (value.match(/^\s*(\-?[\d_\.]*)\s*$/) !== null) {
return 'float';
}

// Check for string
if (value.match(/^\s*(["'])/) !== null || value.match(/^\s*<<</) !== null) {
return 'string';
Expand All @@ -185,6 +193,27 @@ export default class TypeUtil {
if (value.match(/^\s*(array\(|\[)/) !== null) {
return 'array';
}

// Check for class
var match = value.match(/^\s*new\s+([a-z0-9_\\\|]+)/i);
if (match) {
if (match[1] === 'class') {
return 'object';
}
return match[1];
}

// Check for closure
var match = value.match(/^\s*function\s*\(/i) || value.match(/^\s*fn\s*\(/i);
if (match) {
return '\\Closure';
}

// Check for type casting
var match = value.match(/^\s*\(\s*(int|integer|bool|boolean|float|double|real|string|array|object|unset)\s*\)/i);
if (match) {
return this.getFormattedTypeByName(match[1]);
}

return this.getDefaultType();
}
Expand Down
9 changes: 7 additions & 2 deletions test/completions.test.ts
Expand Up @@ -21,6 +21,9 @@ suite("Completion tests", () => {
});

map.forEach(testData => {
if (testData.name === undefined) {
testData.name = testData.key;
}
test("Completion: " + testData.name, () => {
let pos:Position = testPositions[testData.key];
let result:any = completions.provideCompletionItems(
Expand All @@ -31,10 +34,12 @@ suite("Completion tests", () => {

let matched:Array<string> = [];
result.forEach(data => {
matched.push(data.label);
matched.push(data.insertText.value);
});
let actual = matched.join("\n");
let expected = testData.result.join("\n");

assert.deepEqual(testData.result, matched);
assert.deepEqual(actual, expected);
});
});
});
20 changes: 20 additions & 0 deletions test/fixtures/completions.php
Expand Up @@ -31,5 +31,25 @@ class Blah
{
}
////=> variable
/**
$var = null;
////=> foreach
/**
foreach ([] as $key => $value) {
////=> foreach-with-key
/**
foreach ([] as $value) {
////=> while
/**
while ($value = array_shift($arrs)) {
////=> while-no-var
/**
while ($value == true) {
////=> empty
/**

0 comments on commit ce93c87

Please sign in to comment.