Checking for a maximum level of indentation in Checkstyle - checkstyle

I want to ensure that my code does not exceed 5 levels of indentation, like so:
class Foo { // 0
void bar() { // 1
if () { // 2
if () { // 3
if () { // 4
if () { // 5
if () { // 6 - error
}
}
}
}
}
}
}
Looking through the Checkstyle documentation, I couldn't find a rule that specifically implements this. Does such a rule exist, or do I have to look into custom rules?

There is an issue still in "Open" state about this feature: https://github.com/checkstyle/checkstyle/issues/5487
Not exactly what you need, but you can achieve something similar using the NestedForDepth, NestedIfDepth and NestedTryDepth checks.

Related

Access a nested JSON object property via a single string

This line: let X = this.appGlobal.GetNavigationLanguage().data;
retuns JSON as you can see below.
I want to take NAV.REPORTS.BMAIL.TITLE.
Translate code (NAV.REPORTS.BMAIL.TITLE) is dynamically created.
X.NAV.REPORTS.BMAIL.TITLE => works
X['NAV']['REPORTS']['BMAIL']['TITLE'] => works
But keep in mind I have dynamically created translation code I need something like this:
let transCode = 'NAV.REPORTS.BMAIL.TITLE';
console.log(X[transCode]);
How I can achieve this?
test_data = {
NAV: {
REPORTS: {
BMAIL: {
TITLE: "hello"
}
}
}
}
let transCode = 'NAV.REPORTS.BMAIL.TITLE';
properties = transCode.split('.'); //--> ["NAV","REPORTS","BMAIL","TITLE"]
result = test_data
properties.forEach(function(property) {
result = result[property]
})
console.log(result) // --> hello
The short and evil route would be the following:
console.log(eval(`X.${transCode}`));
The less evil way is to use a recursive function call, this means you only look into the number of items in your string-path (rather than looping the whole collection).
const X = {
NAV: {
REPORTS: {
BMAIL: {
TITLE: 'Test'
}
}
}
}
const transCode = 'NAV.REPORTS.BMAIL.TITLE';
// Evil...
console.log(eval(`X.${transCode}`)); // Test
// Less Evil (but needs exception handling)...
function getData(input: any, splitPath: string[]) {
const level = splitPath.pop();
if (splitPath.length === 0) {
return input[level];
} else {
return getData(input[level], splitPath);
}
}
const result = getData(X, transCode.split('.').reverse());
console.log(result); // Test

Polymer 3 Mixin - Possible to implement host property in mixin like in Polymer 1 behaviors?

I am converting a Polymer 1 behavior to a Polymer 3 mixin.
With the Polymer 1 behaviors, I was able to place a host property in the behavior. Is that possible with Polymer 3 Mixins?
Polymer 1 behavior:
<script>
AccountBehavior = {
properties: {
tabactivated: Boolean
},
observers: ['_refreshActivePosts(tabactivated)'],
_refreshActivePosts: function(tabactivated) {
if (tabactivated) {
this.$.account.refreshAjax();
}
}
}
</script>
Not sure I can remember exactly what the old host property does. But I have this module which I wrote to find the host of an element
export default function domHost(self) {
let parent = self.parentNode;
while(parent && parent.nodeType !== 11) {
parent = parent.parentNode; //work up the hierarchy
}
return parent ? parent.host : self;
}
I use it quite a lot to add event listeners to my hosting element
something like this:-
connectedCallback() {
super.connectedCallback();
this.domHost = domHost(this);
this.domHost.addEventListener('pas-filelocation-request', this._gotRequest);
}
disconnectedCallback() {
super.disconnectedCallback();
this.domHost.removeEventListener('pas-filelocation-request', this._gotRequest);
}

What is the correct way to propagate changes from one LitElement to a child LitElement?

I have a LitElement that represents a file upload for multiple files.
This uses a sub-component that represents each file.
I'm struggling to find examples of the best practice for propagating changes into the sub component using LitElements as it appears to be very different from Polymer 3
Here's a cut down example of what I'm trying:
import './uploadFile.js';
class Upload extends LitElement {
...
static get properties() { return { files: Object } }
_render({files}) {
return html`
<input type="file" multiple onchange="...">
${this.renderFiles(files)}`
}
renderFiles(files) {
const filesTemplate = [];
for (var i = 0; i < files.length; i++) {
filesTemplate.push(html`
<upload-file file="${files[i]}"></upload-file>
`);
}
return filesTemplate;
}
}
When I update the status of a file the upload component re-renders but the upload-file component does not.
What am I doing wrong here? There aren't may examples of LitElement usage out there.
TIA
Best practice is "properties down, events up"; meaning that parent elements should share data with children by binding properties to them, and child elements should share data with parents by raising an event with relevant data in the detail of the event.
I can't comment on what you're doing wrong as I can't see how you're updating the status of the files, or your implementation of the child element.
One thing to be aware of is that because of dirty checking, lit-element can only observe changes to the top-level properties that you've listed in the properties getter, and not their sub-properties.
Something like
this.myObj = Object.assign({}, this.myObj, {thing: 'stuff'});
will trigger changes to an object and its sub-properties to render, while
this.myObj.thing='stuff';
will not.
To get sub-property changes to trigger a re-render, you would need to either request one with requestRender() or clone the whole object.
Here is some sample code showing a basic "properties down, events up" model:
Warning: lit-element is still pre-release and syntax will change.
parent-element.js
import { LitElement, html} from '#polymer/lit-element';
import './child-element.js';
class ParentElement extends LitElement {
static get properties(){
return {
myArray: Array
};
}
constructor(){
super();
this.myArray = [
{ val: 0, done: false },
{ val: 1, done: false },
{ val: 2, done: false },
{ val: 3, done: false }
];
}
_render({myArray}){
return html`
${myArray.map((i, index) => {
return html`
<child-element
on-did-thing="${(e) => this.childDidThing(index, i.val)}"
val="${i.val}"
done="${i.done}">
</child-element>
`})}
`;
}
childDidThing(index, val){
this.myArray[index].done=true;
/**
* Mutating a complex property (i.e changing one of its items or
* sub-properties) does not trigger a re-render, so we must
* request one:
*/
this.requestRender();
/**
* Alternative way to update a complex property and make
* sure lit-element observes the change is to make sure you
* never mutate (change sub-properties of) arrays and objects.
* Instead, rewrite the whole property using Object.assign.
*
* For an array, this could be (using ES6 object syntax):
*
* this.myArray =
* Object.assign([], [...this.myArray], {
* [index]: { val: val, done: true }
* });
*
*/
}
}
customElements.define('parent-element', ParentElement);
child-element.js
import { LitElement, html} from '#polymer/lit-element';
class ChildElement extends LitElement {
static get properties(){
return {
val: Number,
done: Boolean
};
}
_render({val, done}){
return html`
<div>
Value: ${val} Done: ${done}
<button on-click="${(e) => this.didThing(e)}">do thing</button>
</div>
`;
}
didThing(e){
var event = new CustomEvent('did-thing', { detail: { stuff: 'stuff'} });
this.dispatchEvent(event);
}
}
customElements.define('child-element', ChildElement);
Hope that helps.

How to change the mode dynamically in codemirror on encounter of a particular expression?

In the textarea whenever '<' is encountered the mode should be html and for '<#' or '<#' or '$', the mode should be ftl. In the code that I have written
function determineCodeMirrorType(cm) {
if (cm.getOption('mode') == 'text/ftl') {
checkAndSwitchToHTML(cm, cm.getValue());
} else if (cm.getOption('mode') == 'text/html') {
checkAndSwitchToFTL(cm, cm.getValue());
}
}
function checkAndSwitchToHTML(cm, val) {
if (/^\s*</.test(val)) {
cm.setOption("mode", "text/html");
}
}
function checkAndSwitchToFTL(cm, val) {
if (/[<#|<#|$]/.test(val)) {
cm.setOption("mode", "text/ftl");
}
}
function buildCMInstance(mode, value) {
var cm = CodeMirror.fromTextArea(document.getElementById("code"), {
mode:mode,
value:value,
lineNumbers:true,
onChange:function(cmInstance){
determineCodeMirrorType(cmInstance); //The call to this function is not made.
})
});
return cm;
}
$(document).ready(function(){
var cm = buildCMInstance("text/ftl")
});
I want to know is there any option that can be initiated which allows the code to change dynamically by making a call to the function "determineCodeMirrorType".
onChange does not exist in recent CodeMirror versions. You have to register the event handler by calling cm.on("change", function(cm, change) { .... }).

Jinja2 automatic creation of prefix whitespace

In StringTemplate - which I've used in some projects to emit C code - whitespace prefixes are automatically added in the output lines:
PrintCFunction(linesGlobal, linesLocal) ::= <<
void foo() {
if (someRuntimeFlag) {
<linesGlobal>
if (anotherRuntimeFlag) {
<linesLocal>
}
}
}
>>
When this template is rendered in StringTemplate, the whitespace
prefixing the multilined linesGlobal and linesLocal strings,
is copied for all the lines emitted. The generated C code is
e.g.:
void foo() {
if (someRuntimeFlag) {
int i;
i=1; // <=== whitespace prefix copied in 2nd
i++; // <=== and 3rd line
if (anotherRuntimeFlag) {
int j=i;
j++; // <=== ditto
}
}
}
I am new to Jinja2 - and tried to replicate this, to see if I can use Python/Jinja2 to do the same thing:
#!/usr/bin/env python
from jinja2 import Template
linesGlobal='\n'.join(['int i;', 'i=1;'])
linesLocal='\n'.join(['int j=i;', 'j++;'])
tmpl = Template(u'''\
void foo() {
if (someRuntimeFlag) {
{{linesGlobal}}
if (anotherRuntimeFlag) {
{{linesLocal}}
}
}
}
''')
print tmpl.render(
linesGlobal=linesGlobal,
linesLocal=linesLocal)
...but saw it produce this:
void foo() {
if (someRuntimeFlag) {
int i;
i=1;
if (anotherRuntimeFlag) {
int j=i;
j++;
}
}
}
...which is not what I want.
I managed to make the output emit proper whitespace prefixes with this:
...
if (someRuntimeFlag) {
{{linesGlobal|indent(8)}}
if (anotherRuntimeFlag) {
{{linesLocal|indent(12)}}
}
}
...but this is arguably bad, since I need to manually count whitespace
for every string I emit...
Surely Jinja2 offers a better way that I am missing?
There's no answer (yet), because quite simply, Jinja2 doesn't support this functionality.
There is, however, an open ticket for this feature - if you care about it, join the discussion there.