Skip to content

Commit

Permalink
feat: 🎸 support @for directive
Browse files Browse the repository at this point in the history
  • Loading branch information
shufo committed Jul 23, 2020
1 parent 3850235 commit 5c6152b
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 8 deletions.
2 changes: 1 addition & 1 deletion __tests__/fixtures/commented.blade.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{--@foreach ($downloadOptions as $d => $dO)
{{--@foreach($downloadOptions as $d => $dO)
<tr>
<td>{{ $dO['description'] }}</td>
<td>{{ $dO['cost'] }}</td>
Expand Down
2 changes: 1 addition & 1 deletion __tests__/fixtures/formatted.commented.blade.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{--@foreach ($downloadOptions as $d => $dO)
{{--@foreach($downloadOptions as $d => $dO)
<tr>
<td>{{ $dO['description'] }}</td>
<td>{{ $dO['cost'] }}</td>
Expand Down
107 changes: 104 additions & 3 deletions __tests__/formatter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,13 @@ describe('formatter', () => {
'auth',
'component',
'empty',
'for',
'foreach',
'forelse',
'guest',
'if',
'isset',
'push',
'section',
'slot',
'switch',
'unless',
'verbatim',
'while',
Expand Down Expand Up @@ -541,4 +538,108 @@ describe('formatter', () => {
assert.equal(result, expected);
});
});

test('@for directive should work', async () => {
const content = [
`@for ($i=0;$i<=5;$i++)`,
`<div class="foo">`,
`</div>`,
`@endfor`,
``,
].join('\n');

const expected = [
`@for($i = 0; $i <= 5; $i++)`,
` <div class="foo">`,
` </div>`,
`@endfor`,
``,
].join('\n');

return new BladeFormatter().format(content).then((result) => {
assert.equal(result, expected);
});
});

test('@foreach directive should work', async () => {
const content = [
`@foreach($users as $user)`,
`<div class="foo">`,
`</div>`,
`@endforeach`,
``,
].join('\n');

const expected = [
`@foreach($users as $user)`,
` <div class="foo">`,
` </div>`,
`@endforeach`,
``,
].join('\n');

return new BladeFormatter().format(content).then((result) => {
assert.equal(result, expected);
});
});

test('@foreach directive should work with variable key', async () => {
const content = [
`@foreach($users["foo"] as $user)`,
`<div class="foo">`,
`</div>`,
`@endforeach`,
``,
].join('\n');

const expected = [
`@foreach($users['foo'] as $user)`,
` <div class="foo">`,
` </div>`,
`@endforeach`,
``,
].join('\n');

return new BladeFormatter().format(content).then((result) => {
assert.equal(result, expected);
});
});

test('@switch directive should work', async () => {
const content = [
`@switch($i)`,
`@case(1)`,
` First case...`,
` @break`,
``,
`@case(2)`,
` Second case...`,
` @break`,
``,
`@default`,
` Default case...`,
`@endswitch`,
``,
].join('\n');

const expected = [
`@switch($i)`,
` @case(1)`,
` First case...`,
` @break`,
``,
` @case(2)`,
` Second case...`,
` @break`,
``,
` @default`,
` Default case...`,
`@endswitch`,
``,
].join('\n');

return new BladeFormatter().format(content).then((result) => {
assert.equal(result, expected);
});
});
});
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"scripts": {
"test": "jest",
"lint": "eslint src -c .eslintrc.json --ext js",
"format": "prettier {src,__{tests,mocks}__}/**/*.js --write",
"fix": "prettier {src,__{tests,mocks}__}/**/*.js --write",
"check_formatted": "prettier **/*.js -c",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0"
},
Expand All @@ -26,10 +26,12 @@
"dependencies": {
"@prettier/plugin-php": "^0.14.0",
"chalk": "^4.1.0",
"detect-indent": "^6.0.0",
"esm": "^3.2.25",
"glob": "^7.1.4",
"js-beautify": "^1.10.2",
"lodash": "^4.17.19",
"php-parser": "^3.0.0-prerelease.9",
"prettier": "^2.0.5",
"vscode-oniguruma": "^1.3.1",
"vscode-textmate": "^4.2.2",
Expand All @@ -47,8 +49,7 @@
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-prettier": "^3.1.1",
"fs-extra": "^9.0.1",
"jest": "^26.1.0",
"php-parser": "^3.0.0-prerelease.9"
"jest": "^26.1.0"
},
"repository": {
"type": "git",
Expand Down
2 changes: 2 additions & 0 deletions src/formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ export default class Formatter {

const promise = new Promise((resolve) => resolve(data))
.then((content) => util.preserveOriginalPhpTagInHtml(content))
.then((content) => util.preserveDirectives(content))
.then((preserved) => beautify(preserved, options))
.then((content) => util.revertDirectives(content, this.options))
.then((beautified) => util.revertOriginalPhpTagInHtml(beautified));

return Promise.resolve(promise);
Expand Down
61 changes: 61 additions & 0 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const _ = require('lodash');
const fs = require('fs');
const chalk = require('chalk');
const prettier = require('prettier');
const detectIndent = require('detect-indent');
const { indentStartTokens } = require('./indent');

export const optional = (obj) => {
const chain = {
Expand Down Expand Up @@ -75,6 +77,25 @@ export function prettifyPhpContentWithUnescapedTags(content) {
return `<?php /*blade*/ ${p1} /*blade*/ ?>`;
});

const directives = _.without(indentStartTokens, '@switch').join('|');

const directiveRegexes = new RegExp(
`(?!\\/\\*.*?\\*\\/)(${directives})\\s*?\\((.*?)\\)`,
'gs',
);

prettified = _.replace(prettified, directiveRegexes, (match, p1, p2) => {
return prettier
.format(`<?php ${p1.substr('1')}(${p2}) ?>`, {
parser: 'php',
singleQuote: true,
phpVersion: '7.4',
})
.replace(/<\?php\s(.*?)\((.*?)\);*\s\?>\n/gs, (match2, j1, j2) => {
return `@${j1.trim()}(${j2.trim()})`;
});
});

prettified = prettier.format(prettified, {
parser: 'php',
printWidth: 1000,
Expand Down Expand Up @@ -151,6 +172,46 @@ export function revertOriginalPhpTagInHtml(content) {
return prettified;
}

export function unindent(directive, content, level, options) {
const lines = content.split('\n');
return _.map(lines, (line) => {
if (!line.match(/\w/)) {
return line;
}

const originalLineWhitespaces = detectIndent(line).amount;
const indentChar = optional(options).useTabs ? '\t' : ' ';
const indentSize = optional(options).indentSize || 4;
const whitespaces = originalLineWhitespaces - indentSize * level;

if (whitespaces < 0) {
return line;
}

return indentChar.repeat(whitespaces) + line.trimLeft();
}).join('\n');
}

export function preserveDirectives(content) {
return _.replace(
content,
/(@foreach[\s]*|@for[\s]*)\((.*?)\)(.*?)(@endforeach|@endfor)/gs,
(match, p1, p2, p3, p4) => {
return `<beautify start="${p1}" end="${p4}" exp="^^${p2}^^">${p3}</beautify>`;
},
);
}

export function revertDirectives(content, options) {
return _.replace(
content,
/<beautify start="(.*?)" end="(.*?)" exp="\^\^(.*?)\^\^">(.*?)<\/beautify>/gs,
(match, p1, p2, p3, p4) => {
return `${p1}(${p3})${unindent(p1, p4, 1, options)}${p2}`;
},
);
}

export function printDescription() {
const returnLine = '\n\n';
process.stdout.write(returnLine);
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1945,6 +1945,11 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=

detect-indent@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.0.0.tgz#0abd0f549f69fc6659a254fe96786186b6f528fd"
integrity sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==

detect-newline@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
Expand Down

0 comments on commit 5c6152b

Please sign in to comment.