Giter Site home page Giter Site logo

intellij-string-concat-heredoc-plugin's Introduction

intellij-string-concat-heredoc-plugin

Build Version Downloads

Template ToDo list

Convert PHP string concatenations to Heredoc syntax, extracting variables where needed. e.g.

// $safeHTML = ... (any string)
echo '<div>' . escape_chars($dangerousInput) . $safeHTML '</div>'

will convert it to

// $safeHTML = ... (any string)
$extractedVar1 = escape_chars($dangerousInput);
echo <<<HTML
<div>{$extractedVar1}{$safeHTML}</div>
HTML;

This specific section is a source for the plugin.xml file which will be extracted by the Gradle during the build process.

To keep everything working, do not remove <!-- ... --> sections.

Installation

  • Using IDE built-in plugin system:

    Settings/Preferences > Plugins > Marketplace > Search for "intellij-string-concat-heredoc-plugin" > Install Plugin

  • Manually:

    Download the latest release and install it manually using Settings/Preferences > Plugins > โš™๏ธ > Install plugin from disk...


Plugin based on the IntelliJ Platform Plugin Template.

intellij-string-concat-heredoc-plugin's People

Contributors

tognitos avatar actions-user avatar

Watchers

 avatar

intellij-string-concat-heredoc-plugin's Issues

Add test cases for echo with commas with expected co nverted values

Initial text was
// TODO: add a converted echo

Currently

There are tests for echo with commas only to verify whether the intention is available.
The functionality to convert the echo with commas statements to HEREDOC has not been implemented yet, as of 12/02/2024.

Todo 1

Add test scenarios for echo with commas with before and after templates.

Why?

I want to have the functionality of converting echo with commas to HEREDOC. This is a step in the right direction following TDD principles.

Wrong escaping of double quotes when they are contained within single-quoted strings (either '' or NOWDOC)

Currently

<?php
$name = 'Matteo';
$result = 'My name is "' . $name . '"';

will be converted to

$name = 'Matteo';
$result = <<<HEREDOC_DELIMITER
My name is \"$name\";
HEREDOC_DELIMITER;

This is not an unnecessary escaping, but a wrong one that would produce 2 different strings.
image

Causes

This is caused by the intention PhpReplaceQuotesIntention, specifically the static method createLiteralWithChangedQuotes.
Initially I thought that using this would be a good idea, but it assumes that the destination quotes will be double quotes. For this reason, in this situation, it escapes the double quotes coming from the single quotes string, which is not necessary and wrong because HEREDOC can contain double quotes directly (that's the main purpose of it).

Todo 1

Fix the wrong escaping of double quotes contained within single-quotes strings.

Possible solutions

Use some variation of PhpStringUtil.escapeText directly, without going through the PhpReplaceQuotesIntention.
Last time I've checked, many methods/functions were exposed as public.

Set ideDir based on whether a CI job is running the runIde command

Initial text was

// TODO: find a way to understand whether you're in a ci job, then you would not do any of this

Currently

file("/Applications/PhpStorm.app/Contents").let {
    if (it.isFile) {
        ideDir.set(it)
    } else {
        println("Could not find file at path ${it.path} : Are you inside a CI job?")
    }
}

Locally I want to test using PhpStorm.
When running the CI job, there is no local PhpStorm installation.

Todo 1

Find a way to set the ideDir property based on whether a CI job is executing the task.

Why?

It seems wrong to try to set an execution environment only if present. If it weren't for the log message in the else statement, it would almost be like suppressing an unexpected error.

Possible solutions

In an unrelated post from the official Gradle website, there is an example on how to distinguish between CI builds and developer builds.

To cite:

Most CI servers (e.g. Jenkins) will set standard environment variables and the standard technique is to set a tag conditional to the presence of one of those variables in the build.

This refers to tagging for build scans, but the same approach could be applied to set the ideDir property conditionally.

Todo 2 (optional)

Find a way to get a PhpStorm installation on the CI server, and configure ideDIr accordingly

Why?

Ideally, this plugin would work on the community edition of IntelliJ which supports PHP, namely PhpStorm.

Use a auto-detected delimiter for the generated HEREDOC, and/or let the user pick a delimiter themselves.

Initial text was

// TODO : let user pick delimiter, or choose based on interpreted content (e.g. HTML or JS or SQL)

Currently

The HEREDOC delimiter is statically set to HEREDOC_DELIMITER

Todo 1

Auto-assign a certain type of delimiter based on the detected content of the concatenated HEREDOC string.

Why?

IntelliJ also has a different way of parsing HEREDOC strings based on whether they are contained in specific delimiter names.
For example, naming a delimiter JS, will cause the IDE to understand that that contained is Javascript code, and therefore provide intelligent suggestions, recognize function references, etc... .
Same applies for SQL, HTML (maybe CSS, speculating).

Possible solutions

Solution 1

Maybe there is already some inspection that determines the possible content type/language of a string.

Solution 2

Add a set of rules to determine the content type of a HEREDOC string, e.g.

  • if it contains tag names, is HTML
  • if it contains css selectors , is CSS
  • if it contains document or window access, then is JS
  • if it contains SQL instructions like SELECT, DELETE, INSERT INTO, etc..., then it is SQL

Todo 2

Let user pick delimiter.
Regardless of having chosen a delimiter automatically, just highlight the delimiter with a refactoring (renaming) intention, so that the user can either press enter or rename the delimiter to any of their preferences.

Do not add curly braces if variable name will be followed by characters which are not valid within variable names

Currently

Some generated HEREDOC might look like :

$locale = 'EN';
return <<<HEREDOC_DELIMITER
<img src="https://bla.com/images/image_{$locale}.png" />
HEREDOC_DELIMITER;

The curly braces are superfluous.
In fact, even the IDE itself suggests replacing them and colours them grey.
image

Todo 1

Do not have unnecessary curly braces within the generated HEREDOC string.

Why?

For some people it might be polluting and unnecessary.

Possible approaches

Approach 1 : execute the "unnecessary curly braces" intention on the generated HEREDOC statement

Execute the available intention on the generated HEREDOC.

Approach 2 : understand whether the text following a variable will start with characters which can be contained within a variable name

This is basically what the intention above already does.
It sounds complicated for how the HEREDOC string is constructed.
A sort of "look ahead" or "lazy evaluating" would be necessary to decide whether the variable interpolation string will need the curly braces.
Approach 1 is probably the ideal to avoid re-inventing the wheel.

Plugin settings to display intentions only when minimum requisites are fulfilled (length, amount of concatenations, ....)

Initial text was
// TODO: add plugin settings to display intention with minimum amount of concatenation expressions and/or echo commas

Currently

The intention to convert string concatenation or echo with commas to HEREDOC is always displayed, as long as there is a concatenation expression with an evaluation expression, or as long as there is an echo with commas.

Todo 1

Add plugin settings to configure when to display intention.

Possible approaches

  1. Have minimum amount of concatenation expressions, being configurable
  2. Have a minimum amount of expressions in an echo with commas
  3. Evaluate length of pure string that would be stored in the HEREDOC statement (e.g. if min. 50 pure string chars)
  4. Evaluate whether the string will contain \n, and therefore might be practical to have a HEREDOC string instead
  5. Any combination of the above

Why?

It probably does not make sense to show the possibility to convert to HEREDOC, when only very small concatenation expressions (or echo with commas) are present.
However the user should have the possibility of deciding based on code-style rules in their repository.

Feature: HEREDOC conversion also for comma-separated echo statements

TLDR

Also allow to convert echo statements with comma-separated values to echo statements with HEREDOC syntax

// ... given
$gender = 'male';
$name = 'Matteo';
function getSalutation(string $gender): string { return $gender === 'male' ? 'Mr' : 'Mrs'; }

/*
* To be converted: echo with comma-separated expressions
* <pre>Mr. Matteo</pre>
*/
echo '<pre>', getSalutation($gender), ' ', $name, '</pre>'; 


// converted, from echo with comma-separated, to echo with HEREDOC
$getSalutation = 'Mr.'; // in HEREDOC, need to have extracted expressions to variables
echo <<<DELIMITER
<pre>$getSalutation $name</pre>
DELIMITER;

Background

In PHP, a common practice is/was to output to a buffer a bunch of expressions separated by comma.
This is still very prevalent in both legacy and recent code-bases, and I consider it to be an ugly malpractice, in MOST of the cases (nothing wrong in keeping it simple for small cases with a little amount of comma-separated expressions).

Gotchas

This one can be tricky. Echo with comma-separated values acts slightly different from concatenation expressions within an echo statement.
Concatenation expressions first accumulate all the returned expression results, and then output them to the buffer.

Take this example

// given
function getCandPrintB(): string {
  echo 'b'; // (!)
  return 'c';
}

echo 'a', getCandPrintB(), 'd'; // outputs: 'abcd'

If we just simply convert it to a concatenation, we will get the wrong result

echo 'a' . getCandPrintB() . 'd'; // outputs: 'bacd'

'b' is the first thing to be printed out, because the rest is printed out only when the full concatenated string is built.

Who would do this?

Sadly, a lot of people. Usually, functions which output to the buffer themselves, do not have a return value.

Solutions

Do not convert to HEREDOC if echo with commas contains a function call

Just avoid the hassle in the first place. If we see a function call, we do not display the HEREDOC intention.

Convert to HERDOC anyway

We could also decide to not care at all, whether the result would have the same output, and push the responsibility of testing to the developers themselves.
However, it feels wrong to offer automated conversions which might break your code.

Convert to HEREDOC anyway, but wrap function calls between ob_start() and ob_get_clean()

This would allow us to catch the output of the function calls, and the result.
Then, in the HEREDOC string, we just need to add both values we have caught.

For example

// ...
ob_start(); // new temporary buffer
$fnCallReturn = getCandPrintB(); // will return 'c', and print 'b' to the new temporary buffer
$fnCallOutput = ob_get_clean(); // close temporary buffer, and save 'c' into $fnCallOutput

// will print abcd
echo <<<DELIMITER
a{$fnCallOutput}{$fnCallReturn}d;
>>>;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.