How to use JSDoc to provide property types to styled.div? - styled-components

When I use VS Code, I can add a jsconfig.json file to get type assistance via IntelliSense. I'm not interested in switching to TypeScript, so I'm using JSDoc to annotate types where needed.
I found that I can add props to a given component like this:
const StyledNode = styled(
/** #type {React.ComponentType<React.ComponentProps<Box> & {level: number}>} */ (Box)
)`
margin-left: ${p => p.level * 3}em;
`
This is zero-cost: I'm getting type assistance when using StyledNode as well as when using level in the CSS.
However, if I want to style a regular div, I have to do
const StyledNode = styled(
/** #type {React.ComponentType<React.DomAttributes & {level: number}>} */
(React.forwardRef((p, ref) => <div ref={ref} {...p} />))
)`
margin-left: ${p => p.level * 3}em;
`
which doesn't seem like zero-cost to me. The problem is that I can't see a way to pass the type parameter to styled<type> via JSDoc.
What is the most optimal way to provide the parameter types to the css template functions in styled.div?

You can import import * as CSS from 'csstype' as global
and use jsdoc hack!
ex:
#param {CSS.Property.FlexDirection} [props.flexDirection] - descriptions
You can install the packages as Dev for avoid polluting, and using only inside jsdoc.
npm i csstype -D -S
is this help you ?

Related

Codeigniter 4: authfilter filter must have a matching alias defined

I'm new to Codeigniter 4.
I'm developing something localy (Win10/XAMPP) and everything works fine. I uploaded code to linux hosting and suddenly I got error: authfilter filter must have a matching alias defined. 'authfilter' was an allias name in Config/Filters file. Than I noticed that allias is lowercased filter class name, so I changed allias to authfil and now I am getting error: Class 'App\Filters\AuthFilter' not found (SYSTEMPATH/Filters/Filters.php at line 167).
Can anyone explain to me what makes the difference; same code, Windows vs. Linux.
My App/Config/Filters contains following code:
namespace Config;
use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Filters\CSRF;
use CodeIgniter\Filters\DebugToolbar;
use CodeIgniter\Filters\Honeypot;
use CodeIgniter\Filters\InvalidChars;
use CodeIgniter\Filters\SecureHeaders;
use App\Filters\FilterInterface;
use App\Filters\AuthFilter;
class Filters extends BaseConfig
{
/**
* Configures aliases for Filter classes to
* make reading things nicer and simpler.
*
* #var array
*/
public $aliases = [
'csrf' => CSRF::class,
'toolbar' => DebugToolbar::class,
'honeypot' => Honeypot::class,
'invalidchars' => InvalidChars::class,
'secureheaders' => SecureHeaders::class,
'authfil' => \App\Filters\AuthFilter::class,
];
/**
* List of filter aliases that are always
* applied before and after every request.
*
* #var array
*/
public $globals = [
'before' => [
// 'honeypot',
// 'csrf',
// 'invalidchars',
'authfil' ///=> ['except' => 'auth/login']
],
'after' => [
'toolbar',
// 'honeypot',
// 'secureheaders',
],
];
My routes looks like:
$routes->group('auth', ['filter' => 'authfil'],['namespace' => 'IonAuth\Controllers'], function ($routes) {
$routes->get('/', 'Auth::index');
$routes->add('login', 'Auth::login');
$routes->get('logout', 'Auth::logout');
...
}
Thanx in advance,
Siniša
P.S. I put: use App\Filters\AuthFilter to SYSTEMPATH/Filters/Filters.php but with no success. I also tried to add filter to the route, and all combinations that I can think of before I post the question.
The fact is, my project is quite large and today, after few months of working, I find out that I should use filters for login check instead of put login check inside initController function... InitController function is a strange approach to me, instead of using standard OOP concepts (constructors). However, there is a reason for everything, even if it's not obvious to me :).

Adding dynamic properties to typescript namespace in a declarations file

I am trying to create a #types package for a JavaScript library by submitting a PR to the DefinetlyTyped repository. The shape of the JavaScript library for which i am providing said types is as follows.
const COMMANDS = [
"about", "authorize", "backend", "cat", "check", "checksum", "cleanup",
"config", "config create", "config delete", "config disconnect", "config dump",
"config edit", "config file", "config password", "config providers",
/* A lot more commands which have been ommitted here */
];
const api = function(...args) {
// Omitting irrelevant implementation
}
const promises = api.promises = function(...args) {
// Omitting irrelevant implementation
}
COMAMNDS.forEach(command => {
Object.defineProperty(api, commandName, {
value: function(...args) {
return api(commandName, ...args);
}
});
Object.defineProperty(api.promises, command, {
value: function(...args) {
return promises(commandName, ...args);
}
});
});
module.exports = api;
Another constraint to bear in mind is that because of the use of module.exports above the checks for DefinitelyTyped insist that i make use of export = api syntax as opposed to the export default api syntax, (kindly please give this consideration inside the answers that you provide). The following has been my attempt thus far.
/// <reference types="node" />
import { ChildProcess } from "child_process";
declare const COMMANDS: [
"about", "authorize", "backend", "cat", "check", "checksum", "cleanup",
"config", "config create", "config delete", "config disconnect", "config dump",
"config edit", "config file", "config password", "config providers",
/* A lot more commands which have been ommitted here */
];
type CommandsUnion = typeof COMMANDS[number];
declare function api(
...args: (string | Object)[]
): ChildProcess;
declare namespace api {
type PromiseApiFn = (
...args: (string | Object)[]
) => Promise<Buffer>;
const promises: PromiseApiFn & {
[Command in CommandsUnion]: PromiseApiFn
};
}
export = api;
As you can gather from the above declaration file. I have failed to add the properties on api that are present in the COMMANDS array. This is the principal blocker that I am experiencing. Can you please suggest a work around for this or perhaps a different way to go about providing declarations for this library such that this issue does not arise.
Note, this edit introduces some annoyances I wrote about avoiding in explanations from the first revision of this answer. My original answer used ES module syntax in the declaration file, which is apparently unsupported by DefinitelyTyped (see the quoted documentation at the end of this answer).
It seems like you have a lot of it figured out. I'm going to address the outstanding concerns separately — however — here's a link to the TS Playground with the full example: TS Playground
For reference, here's a link to the source JS file that you shared with me in a comment, but the link is pinned to the version at the latest commit at the time of writing this answer: https://github.com/sntran/rclone.js/blob/8bd4e08afed96f44bd287e34068dfbf071095c9f/rclone.js
import type { ChildProcess } from 'node:child_process';
// ^^^^
I'm not 100% positive that it matters in a declaration file (since it deals with only types, not data), but it's always a good idea to use type modifiers on type imports.
type Command = (
| 'about' // Get quota information from the remote.
| 'authorize' // Remote authorization.
| 'backend' // Run a backend specific command.
| 'cat' // Concatenates any files and sends them to stdout.
| 'check' // Checks the files in the source and destination match.
// --- snip ---
| 'sync' // Make source and dest identical, modifying destination only.
| 'test' // Run a test command.
| 'touch' // Create new file or change file modification time.
| 'tree' // List the contents of the remote in a tree like fashion.
| 'version' // Show the version number.
);
This is the string literal union in your question, but without the data structure (which is unused). Note that I kept the inline comments from the module. Consumers might reference your types (but never the source code), so including those comments in your declaration file would be very helpful in that case. A declaration file is a documentation file that's in a format that is readable by the TS compiler.
type FnStringOrObjectArgs<R> = (...args: (string | object)[]) => R;
type ApiFn = FnStringOrObjectArgs<ChildProcess>;
// Expands to: (...args: (string | object)[]) => ChildProcess
type PromisesFn = FnStringOrObjectArgs<Promise<Buffer>>;
// Expands to: (...args: (string | object)[]) => Promise<Buffer>
The FnStringOrObjectArgs<R> utility produces the base function signature used by this module. The other function types are derived from it generically. You'll see type utilities like this in other libraries: they can help cut down on repetition when you have modular/derived types. This module doesn't have many types, so it's not really necessary, but I wanted to mention the pattern.
Note: I chose arbitrary names for those types — the names you choose are obviously up to you.
Now, for the type of api:
/**
* Spawns a rclone process to execute with the supplied arguments.
*
* The last argument can also be an object with all the flags.
*
* Options for the child process can also be passed into this last argument,
* and they will be picked out.
*
* #param args arguments for the API call.
* #returns the rclone subprocess.
*/
declare const api: ApiFn & Record<Command, ApiFn> & {
/** Promise-based API. */
promises: PromisesFn & Record<Command, PromisesFn>;
};
TS consumers won't get the JSDoc from the source JS file, so including it is essential.
Below I'll discuss mapped types using the type utility Record<Keys, Type>:
First, let's look at the type of the promises property:
PromisesFn & Record<Command, PromisesFn>
The PromisesFn type was defined above, so this type is the intersection (&) of that function and an object whose keys are of type Command and whose values are of type PromisesFn. This results in the following behavior:
api.promises.about; // PromisesFn
api.promises.authorize; // PromisesFn
api.promises.backend; // PromisesFn
// ...etc.
and we can try to use them without error:
api.promises('authorize', 'something'); // Promise<Buffer>
api.promises.authorize('something'); // Promise<Buffer>
api.promises('authorize', {value: 'something'}); // Promise<Buffer>
api.promises.authorize({value: 'something'}); // Promise<Buffer>
Trying these invocations cause diagnostic errors:
api.promises('authorize', 100); /*
~~~
Argument of type 'number' is not assignable to parameter of type 'string | object'.(2345) */
api.promises.authorize(100); /*
~~~
Argument of type 'number' is not assignable to parameter of type 'string | object'.(2345) */
which is great: exactly as intended!
Now, with that done, understanding the type of api is trivial:
ApiFn & Record<Command, ApiFn> & {
/** Promise-based API. */
promises: PromisesFn & Record<Command, PromisesFn>;
}
It's the intersection of
ApiFn, and
an object with Command keys which have ApiFn values, and
an object with the property promises which has a value of the type PromisesFn & Record<Command, PromisesFn>
Let's check a few properties:
api.about; // ApiFn
api.authorize; // ApiFn
and invocations:
api('authorize', 'something'); // ChildProcess
api.authorize('something'); // ChildProcess
api('authorize', {value: 'something'}); // ChildProcess
api.authorize({value: 'something'}); // ChildProcess
looks good.
Now, for the exports. This is where it might seem a bit complicated (it is).
The JS module is in CommonJS format and uses this syntax for its exports:
module.exports = api;
This pattern cannot be represented statically because it creates a module which is in the shape of api itself: it has all the dynamically-assigned and typed properties of api, and is also a function.
The syntax to export this is archaic, but simple:
export = api;
Note that it also prevents writing other export statements in your file, even exporting of types — and my current understanding is that complex object types like api in this example, which is created from utility expressions, can't participate in declaration merging, so I don't know of a way to include the type alises in the exports. (Maybe someone else can comment with a solution to that.)
Here's more detail from the TS handbook on module declaration files and default exports:
One style of exporting in CommonJS is to export a function. Because a function is also an object, then extra fields can be added and are included in the export.
function getArrayLength(arr) {
return arr.length;
}
getArrayLength.maxInterval = 12;
module.exports = getArrayLength;
Which can be described with:
export default function getArrayLength(arr: any[]): number;
export const maxInterval: 12;
Note that using export default in your .d.ts files requires esModuleInterop: true to work. If you can’t have esModuleInterop: true in your project, such as when you’re submitting a PR to Definitely Typed, you’ll have to use the export= syntax instead. This older syntax is harder to use but works everywhere. Here’s how the above example would have to be written using export=:
declare function getArrayLength(arr: any[]): number;
declare namespace getArrayLength {
declare const maxInterval: 12;
}
export = getArrayLength;
See Module: Functions for details of how that works, and the Modules reference page.

How to use php variable instead .twig file? [duplicate]

I'm working on application written in symfony2 and I want to send email after some action/event... the problem is, that the users can define something like "email templates" which are stores in db like simple string, for example: "This is some email from {{ user }}" and I need to render body for that email which should use that template...
In symfony documentation from this link: https://symfony.com/doc/2.0/cookbook/email/email.html#sending-emails the method for render view is $this->renderView and it expects the path to file such as "bundle:controller:file.html.twig", but my template is simple string from database...
How can I render it?
Twig_Loader_String is deprecated and was always designed for internal use anyway. The usage of this loader is strongly discouraged.
From the API doc:
This loader should NEVER be used. It only exists for Twig internal
purposes. When using this loader with a cache mechanism, you should
know that a new cache key is generated each time a template content
"changes" (the cache key being the source code of the template). If
you don't want to see your cache grows out of control, you need to
take care of clearing the old cache file by yourself.
Also check out this issue: https://github.com/symfony/symfony/issues/10865
The best way I know to load a template from a String source are:
From a controller:
$template = $this->get('twig')->createTemplate('Hello {{ name }}');
$template->render(array('name'=>'World'));
as described here: http://twig.sensiolabs.org/doc/recipes.html#loading-a-template-from-a-string
From a twig template:
{{ include(template_from_string("Hello {{ name }}", {'name' : 'Peter'})) }}
as described here: http://twig.sensiolabs.org/doc/functions/template_from_string.html
Note, that the 'template_from_string' - function is not available by default and needs to be loaded. In symfony you would do this by adding a new service:
# services.yml
services:
appbundle.twig.extension.string:
class: Twig_Extension_StringLoader
tags:
- { name: 'twig.extension' }
This should work. Replace "Hello {{ name }}" with your template text, and fill the array that is passed into the render function with any variables that you need.
$env = new \Twig_Environment(new \Twig_Loader_String());
echo $env->render(
"Hello {{ name }}",
array("name" => "World")
);
Here's a solution that works with Symfony 4 (and possibly older versions as well, although I haven't tested it) and allows you to work with templates stored in the database the same way you would work with templates in the filesystem.
This answer assumes you're using Doctrine, but is relatively easy to adapt if you're using another database library.
Create the Template entity
This is an example class that uses annotations, but you can use whatever configuration method you're already using.
src/Entity/Template.php
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Table(name="templates")
* #ORM\Entity
*/
class Template
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(type="string", nullable=false)
*/
private $filename;
/**
* #var string
*
* #ORM\Column(type="text", nullable=false)
*/
private $source;
/**
* #var \DateTime
*
* #ORM\Column(type="datetime", nullable=false)
*/
private $last_updated;
}
The bare minimum fields are filename and source, but it's a very good idea to include last_updated or you'll lose the benefits of caching.
Create a DatabaseLoader class
src/Twig/Loader/DatabaseLoader.php
<?php
namespace App\Twig\Loader;
use App\Entity\Template;
use Doctrine\ORM\EntityManagerInterface;
use Twig_Error_Loader;
use Twig_LoaderInterface;
use Twig_Source;
class DatabaseLoader implements Twig_LoaderInterface
{
protected $repo;
public function __construct(EntityManagerInterface $em)
{
$this->repo = $em->getRepository(Template::class);
}
public function getSourceContext($name)
{
if (false === $template = $this->getTemplate($name)) {
throw new Twig_Error_Loader(sprintf('Template "%s" does not exist.', $name));
}
return new Twig_Source($template->getSource(), $name);
}
public function exists($name)
{
return (bool)$this->getTemplate($name);
}
public function getCacheKey($name)
{
return $name;
}
public function isFresh($name, $time)
{
if (false === $template = $this->getTemplate($name)) {
return false;
}
return $template->getLastUpdated()->getTimestamp() <= $time;
}
/**
* #param $name
* #return Template|null
*/
protected function getTemplate($name)
{
return $this->repo->findOneBy(['filename' => $name]);
}
}
The class is relatively simple. getTemplate looks up the template filename from the database, and the rest of the methods use getTemplate to implement the interface that Twig needs.
Add the DatabaseLoader to your service config
config/services.yaml
services:
App\Twig\Loader\DatabaseLoader:
tags:
- { name: twig.loader }
Now you can use your database templates in the same way as filesystem templates.
Rendering from a controller:
return $this->render('home.html.twig');
Including from another Twig template (which can be in the database or filesystem):
{{ include('welcome.html.twig') }}
Rendering to a string (where $twig is an instance of Twig\Environment)
$html = $twig->render('email.html.twig')
In each of these cases, Twig will check the database first. If getTemplate in your DatabaseLoader returns null, Twig will then check the filesystem. If the template isn't available in the database or the filesystem, Twig will throw a Twig_Error_Loader.
Clone the native twig service and replace the filesystem loader with the native twig string loader:
<service id="my.twigstring" class="%twig.class%">
<argument type="service" id="my.twigstring.loader" />
<argument>%twig.options%</argument>
</service>
<service id="my.twigstring.loader" class="Twig_Loader_String"></service>
Usage example from within a controller:
$this->get('my.twigstring')->render('Hello {{ name }}', array('name' => 'Fabien'));
The best way to do it is to use template_from_string twig function.
{{ include(template_from_string("Hello {{ name }}")) }}
{{ include(template_from_string(page.template)) }}
See documentation of template_from_string
See why it is not a good idea to use Twig_Loader_Chain or Twig_Loader_String for that purpose on this github issue by stof.
As of Twig 1.10, the Twig Engine doesn't support rendering strings. But there is a bundle available which adds this behavior called TwigstringBundle.
It adds the $this->get('twigstring') service wich you can use to render your strings.
(As September '19, the current version of Twig is 2.X, and version 3 is around the corner; so this is only applies to very old versions of Twig).
This work for me:
$loader = new \Twig\Loader\ArrayLoader([
'Temp_File.html' => 'Hello {{ name }}!',
]);
$twig = new \Twig\Environment($loader);
echo $twig->render('Temp_File.html', ['name' => 'Fabien']);
https://twig.symfony.com/doc/2.x/api.html
FYI, This feature was suggested to be added in the core of Twig as of 1.11.0, but will be needed to be activated by the developper.
With Symfony 2.2 you can use the Twig_Chain_Loader
How to register another (custom) Twig loader in Symfony2 environment?
I recently had to implement a CMS used by multiple parties where each party could completely customize their templates. To achieve this I implemented a custom Twig Loader.
The most difficult part was coming up with a naming convention for the templates guaranteed not to overlap with any existing templates, for example <organisation_slug>!AppBundle:template.html.twig.
In case the template was not customised, the template AppBundle:template.html.twig would have to be loaded as fallback template.
However, this is not possible with the Chain Loader (AFAIK) because there the template name cannot be modified. Therefore I had to inject the default loader (i.e. the loader chain) into my loader and use it to load the fallback template.
Another solution would be to pass the request stack or the session to the template loader, making it possible to automatically detect the organisation, but this is difficult because the security component depends on the templating subsystem, causing circular dependency issues.
$message = \Swift_Message::newInstance()
->setSubject('Hello Email')
->setFrom('send#example.com')
->setTo('recipient#example.com')
->setBody('hai its a sample mail')
;
$this->get('mailer')->send($message);

Find a div in a block render in Symfony

I am doing a site with symfony 4. I start on this framework and I have a problem of design on my site.
I've been looking for where it might come from, but I can not find the code I'd like to remove.
The part of the code I would like to remove is the following because the result is pretty ugly:
I can not find this in my code:
in my controller :
/**
* #return Response
*/
public function newLetterAction(Request $request): Response
{
$form = $this->createForm(CustomerNewsletterType::class, new Customer());
$form->handleRequest($request);
$facebook = $this->manager->getRepository(ExternalUrl::class)->findOneByCode('facebook');
$instagram = $this->manager->getRepository(ExternalUrl::class)->findOneByCode('instagram');
return $this->templatingEngine->renderResponse('#SyliusShop/Homepage/_newsletter.html.twig', [
'facebook' => $facebook,
'instagram' => $instagram,
'form' => $form->createView(),
'rova_refonte' => (in_array($this->container->get('request_stack')->getMasterRequest()->attributes->get('_route'),["sylius_shop_homepage"]) ? true : false)
]);
}
in my formType :
class CustomerNewsletterType extends AbstractResourceType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', EmailType::class, [
'label' => 'app.ui.newsletter',
'attr' => [
'placeholder' => 'app.ui.email'
]
])
;
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix(): string
{
return 'app_customer_newsletter';
}
}
in my twig:
{{ render(controller('app.controller.shop_homepage:newLetterAction')) }}
if anyone could tell me how to find the code, it would help me a lot.
Thank you
Everything is done under the hood when you call $form->createView().
To sum up, every type of field into the form has a base rendering using twig blocks (so does the form itself), which can be overriden. This is what is called the form theme, there's a base one which is usually this one in the twig-bridge.
You can create new themes, extend the existing one, or event create just what you need for a specific form (hint : the getBlockPrefix function in your form type is used for this).
You can find all the documentation about the form rendering here :
https://symfony.com/doc/current/form/form_customization.html
Most functions described in this documentation are in fact calling twig blocks of form themes, and you can find the documentation about this here :
https://symfony.com/doc/current/form/form_themes.html
Keep in mind: Removing such a class / div might break existing CSS, error rendering or everything done in javascript targeting this class.
Most likely you use a bootstrap 3/4 form theme and there works standard form_row template layout.
To customize current form/another form elements, use "How to Work with Form Themes" tutorial.

JSDoc3 & NodeJS link to types from modules

I try to find how to let JSDoc3 automatically generate links to classes from other modules.
I find it hard to explain in words, so let me give some examples. The following script generates the expected output:
/**
* #constructor
*/
var SomeClass = function(){}
/**
* #param {SomeClass} someParam description
*/
var someFunc = function(someParam){}
That is, JSDoc3 correctly generates a link from the parameter list of someFunc to the class description of SomeClass. However, when I put SomeClass in an external module I can't seem to let JSDoc3 generate the links:
/**
* #file SomeClass.js
* #module SomeClass
*/
/**
* #constructor
*/
exports.SomeClass(){}
/**
* #file main.js
*/
var SomeClass = require('./SomeClass');
/**
* #param {SomeClass} someParam description
*/
function someFunc(someParam){}
Now JSDoc3 correctly generates the documentation for both files, but it doesn't link the parameter type of someFunc to the page of SomeClass. I tried replacing #param {SomeClass} with:
#param {SomeClass.SomeClass}
#param {SomeClass/SomeClass}
#param {#link SomeClass}
#param {#link SomeClass.SomeClass}
#param {#link SomeClass/SomeClass}
But none of these worked: in all cases the documentation simply shows the text inside the curly brackets (even when I used #link).
How can I let JSDoc3 correctly generate links to the external modules?
Use the module: prefix when referencing modules. If the module's return value is the class itself, then use module:SomeClass. If it is a property of the module, use module:SomeClass.SomeClass. The #link tag shouldn't be necessary if jsdoc can find a reference to the existing class documentation.
Use typeof import
/**
* #param {typeof import("puppeteer").Browser} browser
*/
Docs here

Resources