Fwd: withBreak blocks

classic Classic list List threaded Threaded
18 messages Options
Reply | Threaded
Open this post in threaded view
|

Fwd: withBreak blocks

sagiv ben giat
I hope I'm on the right medium for this, I would like to propose a language feature.
withBreak blocks

Well the name might not be the best, but it's just my way to be the most clear about this feature proposal.

I often find my self doing this in my code:

const doWork = () => {
  // try catch omitted for brevity
  const response = fetchData();
  do {
    if (response.error) {
      log(response.message);
      break;
    }
    if (!response.data) {
      log("No data");
      break;
    }
    if (!response.data.todos) {
      log("No Todos");
      break;
    }
    return action({ data: response.data });
  } while (false);
};

I'm doing this instead of doing bunch of  if / else if / else blocks or ugly nested if blocks.
 What i would like to have is a block that will let me break without being in a loop context.  
Something like this:
withBreak {
  if (response.error) {
    log(response.message);
    break;
  }
  if (!response.data) {
    log("No data");
    break;
  }
  if (!response.data.todos) {
    log("No Todos");
    break;
  }
  return action({ data: response.data });
}

This can be a synthetic sugar for do{}while(false)  behind the scenes.

Best regards, 

Sagiv B.G


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: withBreak blocks

Jacob Pratt
Perhaps I'm missing something, but why wouldn't an `else if` work here?

jhpratt

On Sat, Feb 17, 2018 at 4:02 PM, sagiv ben giat <[hidden email]> wrote:
I hope I'm on the right medium for this, I would like to propose a language feature.
withBreak blocks

Well the name might not be the best, but it's just my way to be the most clear about this feature proposal.

I often find my self doing this in my code:

const doWork = () => {
  // try catch omitted for brevity
  const response = fetchData();
  do {
    if (response.error) {
      log(response.message);
      break;
    }
    if (!response.data) {
      log("No data");
      break;
    }
    if (!response.data.todos) {
      log("No Todos");
      break;
    }
    return action({ data: response.data });
  } while (false);
};

I'm doing this instead of doing bunch of  if / else if / else blocks or ugly nested if blocks.
 What i would like to have is a block that will let me break without being in a loop context.  
Something like this:
withBreak {
  if (response.error) {
    log(response.message);
    break;
  }
  if (!response.data) {
    log("No data");
    break;
  }
  if (!response.data.todos) {
    log("No Todos");
    break;
  }
  return action({ data: response.data });
}

This can be a synthetic sugar for do{}while(false)  behind the scenes.

Best regards, 

Sagiv B.G


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: withBreak blocks

sagiv ben giat
`else if` would work but it will look kinda nasty if you have deeply nested validations.
Keep in mind my example was a small and simple.
It's the same as using async await vs .then etc...

 
שגיב בן גיאט
Sagiv ben giat

On Sat, Feb 17, 2018 at 11:09 PM, Jacob Pratt <[hidden email]> wrote:
Perhaps I'm missing something, but why wouldn't an `else if` work here?

jhpratt

On Sat, Feb 17, 2018 at 4:02 PM, sagiv ben giat <[hidden email]> wrote:
I hope I'm on the right medium for this, I would like to propose a language feature.
withBreak blocks

Well the name might not be the best, but it's just my way to be the most clear about this feature proposal.

I often find my self doing this in my code:

const doWork = () => {
  // try catch omitted for brevity
  const response = fetchData();
  do {
    if (response.error) {
      log(response.message);
      break;
    }
    if (!response.data) {
      log("No data");
      break;
    }
    if (!response.data.todos) {
      log("No Todos");
      break;
    }
    return action({ data: response.data });
  } while (false);
};

I'm doing this instead of doing bunch of  if / else if / else blocks or ugly nested if blocks.
 What i would like to have is a block that will let me break without being in a loop context.  
Something like this:
withBreak {
  if (response.error) {
    log(response.message);
    break;
  }
  if (!response.data) {
    log("No data");
    break;
  }
  if (!response.data.todos) {
    log("No Todos");
    break;
  }
  return action({ data: response.data });
}

This can be a synthetic sugar for do{}while(false)  behind the scenes.

Best regards, 

Sagiv B.G


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: withBreak blocks

Oriol _
In reply to this post by sagiv ben giat
This is so close to your proposal, and already works right now:

```js
block: {
  if (response.error) {
    log(response.message);
    break block;
  }
  if (!response.data) {
    log("No data");
    break block;
  }
  if (!response.data.todos) {
    log("No Todos");
    break block;
  }
  return action({ data: response.data });
}
```

- Oriol

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: withBreak blocks

Peter Jaszkowiak
Also, you can just use `return` if you're in a function:

```
const doWork = () => {
  // try catch omitted for brevity
  const response = fetchData();
   
  if (response.error) {
    log(response.message);
    return;
  }
  if (!response.data) {
    log("No data");
    return;
  }
  if (!response.data.todos) {
    log("No Todos");
    return;
  }

  return action({ data: response.data });
};
```

On Sat, Feb 17, 2018 at 2:17 PM, Oriol _ <[hidden email]> wrote:
This is so close to your proposal, and already works right now:

```js
block: {
  if (response.error) {
    log(response.message);
    break block;
  }
  if (!response.data) {
    log("No data");
    break block;
  }
  if (!response.data.todos) {
    log("No Todos");
    break block;
  }
  return action({ data: response.data });
}
```

- Oriol

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: withBreak blocks

sagiv ben giat
In reply to this post by Oriol _
Yeah, i just thought labels will become deprecated at some point and never thought of using them. 
good point though :)

 
שגיב בן גיאט
Sagiv ben giat

On Sat, Feb 17, 2018 at 11:17 PM, Oriol _ <[hidden email]> wrote:
This is so close to your proposal, and already works right now:

```js
block: {
  if (response.error) {
    log(response.message);
    break block;
  }
  if (!response.data) {
    log("No data");
    break block;
  }
  if (!response.data.todos) {
    log("No Todos");
    break block;
  }
  return action({ data: response.data });
}
```

- Oriol

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: withBreak blocks

sagiv ben giat
In reply to this post by Peter Jaszkowiak
That's not what i'm looking for. 
I may want to do some more things inside the function besides validations.

Sagiv b.g

On Sat, Feb 17, 2018 at 11:19 PM, Peter Jaszkowiak <[hidden email]> wrote:
Also, you can just use `return` if you're in a function:

```
const doWork = () => {
  // try catch omitted for brevity
  const response = fetchData();
   
  if (response.error) {
    log(response.message);
    return;
  }
  if (!response.data) {
    log("No data");
    return;
  }
  if (!response.data.todos) {
    log("No Todos");
    return;
  }

  return action({ data: response.data });
};
```

On Sat, Feb 17, 2018 at 2:17 PM, Oriol _ <[hidden email]> wrote:
This is so close to your proposal, and already works right now:

```js
block: {
  if (response.error) {
    log(response.message);
    break block;
  }
  if (!response.data) {
    log("No data");
    break block;
  }
  if (!response.data.todos) {
    log("No Todos");
    break block;
  }
  return action({ data: response.data });
}
```

- Oriol

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: withBreak blocks

Jacob Pratt
Can you provide a clear use case that can't (or shouldn't) be covered by what others have mentioned?

jhpratt

On Sat, Feb 17, 2018 at 4:23 PM, sagiv ben giat <[hidden email]> wrote:
That's not what i'm looking for. 
I may want to do some more things inside the function besides validations.

Sagiv b.g

On Sat, Feb 17, 2018 at 11:19 PM, Peter Jaszkowiak <[hidden email]> wrote:
Also, you can just use `return` if you're in a function:

```
const doWork = () => {
  // try catch omitted for brevity
  const response = fetchData();
   
  if (response.error) {
    log(response.message);
    return;
  }
  if (!response.data) {
    log("No data");
    return;
  }
  if (!response.data.todos) {
    log("No Todos");
    return;
  }

  return action({ data: response.data });
};
```

On Sat, Feb 17, 2018 at 2:17 PM, Oriol _ <[hidden email]> wrote:
This is so close to your proposal, and already works right now:

```js
block: {
  if (response.error) {
    log(response.message);
    break block;
  }
  if (!response.data) {
    log("No data");
    break block;
  }
  if (!response.data.todos) {
    log("No Todos");
    break block;
  }
  return action({ data: response.data });
}
```

- Oriol

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Re: withBreak blocks

sagiv ben giat
In reply to this post by sagiv ben giat
The label suggestion kinda nails it, though i was sure i read somewhere that labels should not be used anymore. 


Sagiv B.G

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Re: withBreak blocks

sagiv ben giat
In reply to this post by sagiv ben giat
> Can you provide a clear use case that can't (or shouldn't) be covered by what others have mentioned?

Actually es-lint won't allow it:
eslint.org/docs/rules/no-labels


Sagiv B.G

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Re: withBreak blocks

Peter Jaszkowiak
What kind of argument is that? ESlint isn't a JavaScript runtime, it is fully configurable, and I don't see how it's at all relevant.

On Feb 17, 2018 14:52, "sagiv ben giat" <[hidden email]> wrote:
> Can you provide a clear use case that can't (or shouldn't) be covered by what others have mentioned?

Actually es-lint won't allow it:
eslint.org/docs/rules/no-labels


Sagiv B.G

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Re: withBreak blocks

sagiv ben giat
In reply to this post by sagiv ben giat
What kind of argument is that? ESlint isn't a JavaScript runtime, it is fully configurable, and I don't see how it's at all relevant. 

I know ESLint can be configured, it was just an example for how `label`  statements are considered as poor design of code.



Sagiv B.G

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Re: withBreak blocks

李白|字一日
you can simply put these value handler pairs into an array.


const a = [[0, function(){}], [1, function(){}]];
let i = 0;

while (a[i++][0]) {
a[i - 1][1]()
break;
}


2018-02-18 5:58 GMT+08:00 sagiv ben giat <[hidden email]>:
What kind of argument is that? ESlint isn't a JavaScript runtime, it is fully configurable, and I don't see how it's at all relevant. 

I know ESLint can be configured, it was just an example for how `label`  statements are considered as poor design of code.



Sagiv B.G

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Re: withBreak blocks

Jordan Harband
Your proposal is conceptually the same as a labelled break statement (ie, GOTO); if you want to follow the advice to avoid labels, I suspect it would apply to your proposal as well.

On Sat, Feb 17, 2018 at 4:44 PM, 李白|字一日 <[hidden email]> wrote:
you can simply put these value handler pairs into an array.


const a = [[0, function(){}], [1, function(){}]];
let i = 0;

while (a[i++][0]) {
a[i - 1][1]()
break;
}


2018-02-18 5:58 GMT+08:00 sagiv ben giat <[hidden email]>:
What kind of argument is that? ESlint isn't a JavaScript runtime, it is fully configurable, and I don't see how it's at all relevant. 

I know ESLint can be configured, it was just an example for how `label`  statements are considered as poor design of code.



Sagiv B.G

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: withBreak blocks

kai zhu
On Feb 18, 2018, at 4:52 AM, sagiv ben giat <[hidden email]> wrote:

Can you provide a clear use case that can't (or shouldn't) be covered by what others have mentioned?

@sagiv, if you need guidance by use-case/example, here’s a real-world example [1] of a validator “god” function (with 100% code-coverage [2]) that encapsulates most of the logic for validating user-inputs against the full swagger/openapi 2.0 spec [3].  attached screenshot showing how its used from browser-console (works just as well in nodejs).

and yes, the code-sample makes use of break statements in:
1. a recursive while loop to dereference schema pointers [4]
2. in switch/case blocks which are conceptually similar to what you want to do


```javascript
/*
 * real-world example of swagger-validator from
 */

/*jslint
    bitwise: true,
    browser: true,
    maxerr: 8,
    maxlen: 100,
    node: true,
    nomen: true,
    regexp: true,
    stupid: true
*/

local.validateBySwaggerSchema = function (options) {
/*
 * this function will validate options.data against the swagger options.schema
 * according to the spec defined at:
 */
    var $ref,
        circularList,
        data,
        dataReadonlyRemove2,
        ii,
        oneOf,
        schema,
        test,
        tmp;
    if (!options.schema) {
        return;
    }
    data = options.data;
    options.dataReadonlyRemove = options.dataReadonlyRemove || [{}, '', null];
    dataReadonlyRemove2 = options.dataReadonlyRemove[2] || {};
    schema = options.schema;
    circularList = [];
    while (true) {
        // dereference schema.schema
        while (schema.schema) {
            schema = schema.schema;
        }
        // dereference schema.oneOf
        oneOf = (data && schema.oneOf) || [];
        for (ii = 0; ii < oneOf.length; ii += 1) {
            tmp = String(oneOf[ii] && oneOf[ii].$ref)
                .replace('<a href="http://json-schema.org/draft-04/schema#', '#" class="">http://json-schema.org/draft-04/schema#', '#');
            switch (tmp + ' ' + (!local.isNullOrUndefined(data.$ref) || data.in)) {
            case '#/definitions/bodyParameter body':
            case '#/definitions/formDataParameterSubSchema formData':
            case '#/definitions/headerParameterSubSchema header':
            case '#/definitions/jsonReference true':
            case '#/definitions/pathParameterSubSchema path':
            case '#/definitions/queryParameterSubSchema query':
                schema = local.swaggerSchemaJson.definitions[tmp.split('/')[2]];
                break;
            default:
                switch (tmp) {
                case '#/definitions/bodyParameter':
                case '#/definitions/jsonReference':
                    schema = oneOf[ii ^ 1];
                    break;
                }
            }
            if (!schema.oneOf) {
                break;
            }
        }
        // dereference schema.$ref
        $ref = schema && schema.$ref;
        if (!$ref) {
            break;
        }
        test = circularList.indexOf($ref) < 0;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'schemaDeferenceCircular',
            prefix: options.prefix,
            schema: schema
        });
        circularList.push($ref);
        tmp = $ref.split('/').slice(-2);
        schema = $ref.indexOf('http://json-schema.org/draft-04/schema#/') === 0
            ? local.swaggerSchemaJson[tmp[0]]
            : options.swaggerJson[tmp[0]];
        schema = schema && schema[tmp[1]];
        test = schema;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'schemaDeference',
            prefix: options.prefix,
            schema: options.schema
        });
    }
    if (options.modeDereference) {
        if (options.modeDereferenceDepth > 1) {
            schema = local.jsonCopy(schema);
            Object.keys(schema.properties || {}).forEach(function (key) {
                schema.properties[key] = local.validateBySwaggerSchema({
                    // dereference property
                    modeDereference: true,
                    modeDereferenceDepth: options.modeDereferenceDepth - 1,
                    prefix: options.prefix.concat(['properties', key]),
                    schema: schema.properties[key],
                    swaggerJson: options.swaggerJson
                });
            });
        }
        return schema;
    }
    // validate schema.default
    if (options.modeDefault) {
        data = schema.default;
    }
    // validate semanticRequired
    test = options.modeDefault ||
        !local.isNullOrUndefined(data) ||
        schema.required !== true ||
        schema['x-swgg-notRequired'];
    local.throwSwaggerError(!test && {
        data: data,
        errorType: 'semanticRequired',
        prefix: options.prefix,
        schema: schema
    });
    if (local.isNullOrUndefined(data)) {
        return;
    }
    // validate semanticRequiredArrayItems
    test = !options.modeSchema || local.schemaPType(data) !== 'array' ||
        (typeof local.schemaPItems(data) === 'object' && local.schemaPItems(data));
    local.throwSwaggerError(!test && {
        errorType: 'semanticRequiredArrayItems',
        prefix: options.prefix,
        schema: data
    });
    // remove readOnly property
    if (schema.readOnly) {
        delete options.dataReadonlyRemove[0][options.dataReadonlyRemove[1]];
    }
    // optimization - validate schema.type first
    // 5.5.2. type
    switch (local.schemaPType(schema)) {
    case 'array':
        test = Array.isArray(data);
        break;
    case 'boolean':
        test = typeof data === 'boolean';
        break;
    case 'file':
        test = !options.modeSchema;
        break;
    case 'integer':
        test = Number.isFinite(data) && Math.floor(data) === data;
        switch (schema.format) {
        case 'int32':
            break;
        case 'int64':
            break;
        }
        break;
    case 'number':
        test = Number.isFinite(data);
        switch (schema.format) {
        case 'double':
            break;
        case 'float':
            break;
        }
        break;
    case 'string':
        test = typeof data === 'string' ||
            (!options.modeSchema && schema.format === 'binary');
        switch (test && !options.modeSchema && schema.format) {
        // Clarify 'byte' format #50
        case 'byte':
            test = !(/[^\n\r\+\/0-9\=A-Za-z]/).test(data);
            break;
        case 'date':
        case 'date-time':
            test = JSON.stringify(new Date(data)) !== 'null';
            break;
        case 'email':
            test = local.regexpEmailValidate.test(data);
            break;
        case 'json':
            test = local.tryCatchOnError(function () {
                JSON.parse(data);
                return true;
            }, local.nop);
            break;
        case 'phone':
            test = local.regexpPhoneValidate.test(data);
            break;
        }
        break;
    default:
        test = options.modeSchema || typeof data === 'object';
        break;
    }
    local.throwSwaggerError(!test && {
        data: data,
        errorType: 'itemType',
        prefix: options.prefix,
        schema: schema,
        typeof: typeof data
    });
    tmp = typeof data;
    if (tmp === 'object' && Array.isArray(data)) {
        tmp = 'array';
    }
    switch (tmp) {
    // 5.1. Validation keywords for numeric instances (number and integer)
    case 'number':
        // 5.1.1. multipleOf
        test = typeof schema.multipleOf !== 'number' || data % schema.multipleOf === 0;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'numberMultipleOf',
            prefix: options.prefix,
            schema: schema
        });
        // 5.1.2. maximum and exclusiveMaximum
        test = typeof schema.maximum !== 'number' || (schema.exclusiveMaximum
            ? data < schema.maximum
            : data <= schema.maximum);
        local.throwSwaggerError(!test && {
            data: data,
            errorType: schema.exclusiveMaximum
                ? 'numberExclusiveMaximum'
                : 'numberMaximum',
            prefix: options.prefix,
            schema: schema
        });
        // 5.1.3. minimum and exclusiveMinimum
        test = typeof schema.minimum !== 'number' || (schema.exclusiveMinimum
            ? data > schema.minimum
            : data >= schema.minimum);
        local.throwSwaggerError(!test && {
            data: data,
            errorType: schema.exclusiveMinimum
                ? 'numberExclusiveMinimum'
                : 'numberMinimum',
            prefix: options.prefix,
            schema: schema
        });
        break;
    // 5.2. Validation keywords for strings
    case 'string':
        // 5.2.1. maxLength
        test = typeof schema.maxLength !== 'number' || data.length <= schema.maxLength;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'stringMaxLength',
            prefix: options.prefix,
            schema: schema
        });
        // 5.2.2. minLength
        test = typeof schema.minLength !== 'number' || data.length >= schema.minLength;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'stringMinLength',
            prefix: options.prefix,
            schema: schema
        });
        // 5.2.3. pattern
        test = !schema.pattern || new RegExp(schema.pattern).test(data);
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'stringPattern',
            prefix: options.prefix,
            schema: schema
        });
        break;
    // 5.3. Validation keywords for arrays
    case 'array':
        // 5.3.1. additionalItems and items
        // swagger disallows array items
        data.forEach(function (element, ii) {
            // recurse - schema.additionalItems and schema.items
            local.validateBySwaggerSchema({
                data: element,
                dataReadonlyRemove: [dataReadonlyRemove2, ii, dataReadonlyRemove2[ii]],
                modeSchema: options.modeSchema,
                prefix: options.prefix.concat([ii]),
                schema: local.schemaPItems(schema) || schema.additionalItems,
                swaggerJson: options.swaggerJson
            });
        });
        // 5.3.2. maxItems
        test = typeof schema.maxItems !== 'number' || data.length <= schema.maxItems;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'arrayMaxItems',
            prefix: options.prefix,
            schema: schema
        });
        // 5.3.3. minItems
        test = typeof schema.minItems !== 'number' || data.length >= schema.minItems;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'arrayMinItems',
            prefix: options.prefix,
            schema: schema
        });
        // 5.3.4. uniqueItems
        test = !schema.uniqueItems || data.every(function (element) {
            tmp = element;
            return data.indexOf(element) === data.lastIndexOf(element);
        });
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'arrayUniqueItems',
            prefix: options.prefix,
            schema: schema,
            tmp: tmp
        });
        break;
    // 5.4. Validation keywords for objects
    case 'object':
        // 5.4.1. maxProperties
        test = typeof schema.maxProperties !== 'number' ||
            Object.keys(data).length <= schema.maxProperties;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'objectMaxProperties',
            prefix: options.prefix,
            schema: schema
        });
        // 5.4.2. minProperties
        test = typeof schema.minProperties !== 'number' ||
            Object.keys(data).length >= schema.minProperties;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'objectMinProperties',
            prefix: options.prefix,
            schema: schema
        });
        // 5.4.3. required
        local.normalizeValue('list', schema.required).forEach(function (key) {
            test = !local.isNullOrUndefined(data[key]);
            local.throwSwaggerError(!test && {
                data: data,
                errorType: 'objectRequired',
                key: key,
                prefix: options.prefix,
                schema: schema
            });
        });
        // 5.4.4. additionalProperties, properties and patternProperties
        Object.keys(data).forEach(function (key) {
            tmp = null;
            if (schema.properties && schema.properties[key]) {
                tmp = true;
                // recurse - schema.properties
                local.validateBySwaggerSchema({
                    data: data[key],
                    dataReadonlyRemove: [
                        dataReadonlyRemove2,
                        key,
                        dataReadonlyRemove2[key]
                    ],
                    modeSchema: options.modeSchema,
                    prefix: options.prefix.concat([key]),
                    schema: schema.properties[key],
                    swaggerJson: options.swaggerJson
                });
            }
            Object.keys(schema.patternProperties || {}).forEach(function (rgx) {
                if (new RegExp(rgx).test(key)) {
                    tmp = true;
                    // recurse - schema.patternProperties
                    local.validateBySwaggerSchema({
                        data: data[key],
                        modeSchema: options.modeSchema,
                        prefix: options.prefix.concat([key]),
                        schema: schema.patternProperties[rgx],
                        swaggerJson: options.swaggerJson
                    });
                }
            });
/*
* validate
* 5.4.4.4. If "additionalProperties" has boolean value false
*
* In this case, validation of the instance depends on the property set of
* "properties" and "patternProperties". In this section, the property names of
* "patternProperties" will be called regexes for convenience.
*
* The first step is to collect the following sets:
*
* s
* The property set of the instance to validate.
* p
* The property set from "properties".
* pp
* The property set from "patternProperties".
* Having collected these three sets, the process is as follows:
*
* remove from "s" all elements of "p", if any;
* for each regex in "pp", remove all elements of "s" which this regex matches.
* Validation of the instance succeeds if, after these two steps, set "s" is empty.
*/
            test = tmp || schema.additionalProperties !== false;
            local.throwSwaggerError(!test && {
                data: data,
                errorType: 'objectAdditionalProperties',
                key: key,
                prefix: options.prefix,
                schema: schema
            });
            // recurse - schema.additionalProperties
            local.validateBySwaggerSchema({
                data: data[key],
                modeSchema: options.modeSchema,
                prefix: options.prefix.concat([key]),
                schema: schema.additionalProperties,
                swaggerJson: options.swaggerJson
            });
        });
        // 5.4.5. dependencies
        Object.keys(schema.dependencies || {}).forEach(function (key) {
            if (local.isNullOrUndefined(data[key])) {
                return;
            }
            // 5.4.5.2.1. Schema dependencies
            // recurse - schema.dependencies
            local.validateBySwaggerSchema({
                data: data[key],
                modeSchema: options.modeSchema,
                prefix: options.prefix.concat([key]),
                schema: schema.dependencies[key],
                swaggerJson: options.swaggerJson
            });
            // 5.4.5.2.2. Property dependencies
            local.normalizeValue('list', schema.dependencies[key]).every(function (key2) {
                test = !local.isNullOrUndefined(data[key2]);
                local.throwSwaggerError(!test && {
                    data: data,
                    errorType: 'objectDependencies',
                    key: key,
                    key2: key2,
                    prefix: options.prefix,
                    schema: schema
                });
            });
        });
        break;
    }
    // 5.5. Validation keywords for any instance type
    // 5.5.1. enum
    tmp = schema.enum || (!options.modeSchema && (local.schemaPItems(schema) || {}).enum);
    test = !tmp || (Array.isArray(data)
        ? data
        : [data]).every(function (element) {
        return tmp.indexOf(element) >= 0;
    });
    local.throwSwaggerError(!test && {
        data: data,
        errorType: 'itemEnum',
        prefix: options.prefix,
        schema: schema,
        tmp: tmp
    });
    // 5.5.2. type
    local.nop();
    // 5.5.3. allOf
    (schema.allOf || []).forEach(function (element) {
        // recurse - schema.allOf
        local.validateBySwaggerSchema({
            data: data,
            prefix: options.prefix,
            modeSchema: options.modeSchema,
            schema: element,
            swaggerJson: options.swaggerJson
        });
    });
    // 5.5.4. anyOf
    tmp = null;
    test = !schema.anyOf || schema.anyOf.some(function (element) {
        local.tryCatchOnError(function () {
            // recurse - schema.anyOf
            local.validateBySwaggerSchema({
                data: data,
                modeSchema: options.modeSchema,
                prefix: options.prefix,
                schema: element,
                swaggerJson: options.swaggerJson
            });
            return true;
        }, local.nop);
        tmp = tmp || local.utility2._debugTryCatchError;
        return !tmp;
    });
    local.throwSwaggerError(!test && {
        data: data,
        errorType: 'itemOneOf',
        prefix: options.prefix,
        schema: schema,
        tmp: tmp
    });
    // 5.5.5. oneOf
    tmp = !schema.oneOf
        ? 1
        : 0;
    (schema.oneOf || []).some(function (element) {
        local.tryCatchOnError(function () {
            // recurse - schema.oneOf
            local.validateBySwaggerSchema({
                data: data,
                modeSchema: options.modeSchema,
                prefix: options.prefix,
                schema: element,
                swaggerJson: options.swaggerJson
            });
            tmp += 1;
        }, local.nop);
        return tmp > 1;
    });
    test = tmp === 1;
    local.throwSwaggerError(!test && {
        data: data,
        errorType: 'itemOneOf',
        prefix: options.prefix,
        schema: schema,
        tmp: tmp
    });
    // 5.5.6. not
    test = !schema.not || !local.tryCatchOnError(function () {
        // recurse - schema.not
        local.validateBySwaggerSchema({
            data: data,
            modeSchema: options.modeSchema,
            prefix: options.prefix,
            schema: schema.not,
            swaggerJson: options.swaggerJson
        });
        return true;
    }, local.nop);
    local.throwSwaggerError(!test && {
        data: data,
        errorType: 'itemNot',
        prefix: options.prefix,
        schema: schema
    });
    // 5.5.7. definitions
    local.nop();
    // validate data.$ref
    if (schema === local.swaggerSchemaJson.definitions.jsonReference) {
        local.validateBySwaggerSchema({
            modeDereference: true,
            modeSchema: options.modeSchema,
            prefix: options.prefix,
            schema: data,
            swaggerJson: options.swaggerJson
        });
    }
    return schema;
};

```

```javascript
/*
 * output from running code inside browser-console
 */
var mySchema = {
    required: ['myBoolean'],
    properties: {
        myArrayOfStrings: { items: { type: 'string' }, type: 'array' },
        myBoolean: { type: 'boolean' },
        myNumber: { type: 'number' },
        myString: { enum: ['hello world', 'bye world'], type: 'string' }
    }
};

undefined

local.validateBySwaggerSchema({
    data: {
        myArrayOfStrings: ['foo', 'bar'],
        myBoolean: false,
        myString: 'hello world'
    },
    prefix: ['myData'],
    schema: mySchema
});

{required: Array(1), properties: {…}}

local.validateBySwaggerSchema({
    data: {
        myArrayOfStrings: [1, 2],
        myBoolean: false
    },
    prefix: ['myData'],
    schema: mySchema
});

assets.utility2.rollup.js:26060 Uncaught Error: error.itemType - value myData["myArrayOfStrings"][0] = 1 is not a valid string
    at Object.local.throwSwaggerError (assets.utility2.rollup.js:26048)
    at Object.local.validateBySwaggerSchema (assets.utility2.rollup.js:27017)
    at assets.utility2.rollup.js:27097
    at Array.forEach (<anonymous>)
    at Object.local.validateBySwaggerSchema (assets.utility2.rollup.js:27095)
    at assets.utility2.rollup.js:27172
    at Array.forEach (<anonymous>)
    at Object.local.validateBySwaggerSchema (assets.utility2.rollup.js:27167)
    at <anonymous>:2:7
local.throwSwaggerError @ assets.utility2.rollup.js:26048
local.validateBySwaggerSchema @ assets.utility2.rollup.js:27017
(anonymous) @ assets.utility2.rollup.js:27097
local.validateBySwaggerSchema @ assets.utility2.rollup.js:27095
(anonymous) @ assets.utility2.rollup.js:27172
local.validateBySwaggerSchema @ assets.utility2.rollup.js:27167
(anonymous) @ VM341:2

local.validateBySwaggerSchema({
    data: {
        myArrayOfStrings: ['foo', 'bar'],
        myBoolean: null
    },
    prefix: ['myData'],
    schema: mySchema
});

assets.utility2.rollup.js:26060 Uncaught Error: error.objectRequired - object myData = {"myArrayOfStrings":["foo","bar"],"myBoolean":null} must have property "myBoolean"
    at Object.local.throwSwaggerError (assets.utility2.rollup.js:26048)
    at assets.utility2.rollup.js:27158
    at Array.forEach (<anonymous>)
    at Object.local.validateBySwaggerSchema (assets.utility2.rollup.js:27156)
    at <anonymous>:2:7
local.throwSwaggerError @ assets.utility2.rollup.js:26048
(anonymous) @ assets.utility2.rollup.js:27158
local.validateBySwaggerSchema @ assets.utility2.rollup.js:27156
(anonymous) @ VM343:2

local.validateBySwaggerSchema({
    data: {
        myBoolean: false,
        myString: 'hello undefined'
    },
    prefix: ['myData'],
    schema: mySchema
});

assets.utility2.rollup.js:26060 Uncaught Error: error.itemEnum - string myData["myString"] = "hello undefined" can only have items from the list ["hello world","bye world"]
    at Object.local.throwSwaggerError (assets.utility2.rollup.js:26048)
    at Object.local.validateBySwaggerSchema (assets.utility2.rollup.js:27274)
    at assets.utility2.rollup.js:27172
    at Array.forEach (<anonymous>)
    at Object.local.validateBySwaggerSchema (assets.utility2.rollup.js:27167)
    at <anonymous>:2:7
local.throwSwaggerError @ assets.utility2.rollup.js:26048
local.validateBySwaggerSchema @ assets.utility2.rollup.js:27274
(anonymous) @ assets.utility2.rollup.js:27172
local.validateBySwaggerSchema @ assets.utility2.rollup.js:27167
(anonymous) @ VM345:2
```

On Feb 18, 2018, at 9:42 AM, Jordan Harband <[hidden email]> wrote:

Your proposal is conceptually the same as a labelled break statement (ie, GOTO); if you want to follow the advice to avoid labels, I suspect it would apply to your proposal as well.

On Sat, Feb 17, 2018 at 4:44 PM, 李白|字一日 <[hidden email]> wrote:
you can simply put these value handler pairs into an array.


const a = [[0, function(){}], [1, function(){}]];
let i = 0;

while (a[i++][0]) {
a[i - 1][1]()
break;
}


2018-02-18 5:58 GMT+08:00 sagiv ben giat <[hidden email]>:
What kind of argument is that? ESlint isn't a JavaScript runtime, it is fully configurable, and I don't see how it's at all relevant. 

I know ESLint can be configured, it was just an example for how `label`  statements are considered as poor design of code.



Sagiv B.G

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: withBreak blocks

Jerry Schulteis
In reply to this post by sagiv ben giat
No if / else if / else or nested if blocks:

```js
const log = x => console.log(x);

// Simulated fallible fetchData
const fetchData = () => {
  const x = Math.random();
  if (x < 0.25) return {error: true, message: "fetchData error"};
  if (x < 0.50) return {};
  if (x < 0.75) return {data: {}};
  return {data: {todos: ["refactor your code"]}};
};

// Simulated action
const action = o => log(o.data);
   
const checkForError = response => {
  const isError = response.error;
  if (isError) {
    log(response.message);
  }
  return isError;
};

const checkForNoData = response => {
  const isNoData = !response.data;
  if (isNoData) {
    log("No data");
  }
  return isNoData;
};

const checkForNoTodos = response => {
  const isNoTodos = !response.data.todos;
  if (isNoTodos) {
    log("No Todos");
  }
  return isNoTodos;
};

const checkList = [
  checkForError,
  checkForNoData,
  checkForNoTodos
];

const doWork = () => {
  const response = fetchData();
  const checkFailed = checkList.find(check => check(response));
  if (!checkFailed) {
    return action({data: response.data});
  }
};
```


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: withBreak blocks

Naveen Chawla
In reply to this post by kai zhu
Kai, it's unlikely anyone will read all that code! Better to illustrate your point with minimal code snippets

On Sun, 18 Feb 2018, 8:25 am kai zhu, <[hidden email]> wrote:
On Feb 18, 2018, at 4:52 AM, sagiv ben giat <[hidden email]> wrote:

Can you provide a clear use case that can't (or shouldn't) be covered by what others have mentioned?

@sagiv, if you need guidance by use-case/example, here’s a real-world example [1] of a validator “god” function (with 100% code-coverage [2]) that encapsulates most of the logic for validating user-inputs against the full swagger/openapi 2.0 spec [3].  attached screenshot showing how its used from browser-console (works just as well in nodejs).

and yes, the code-sample makes use of break statements in:
1. a recursive while loop to dereference schema pointers [4]
2. in switch/case blocks which are conceptually similar to what you want to do


```javascript
/*
 * real-world example of swagger-validator from
 */

/*jslint
    bitwise: true,
    browser: true,
    maxerr: 8,
    maxlen: 100,
    node: true,
    nomen: true,
    regexp: true,
    stupid: true
*/

local.validateBySwaggerSchema = function (options) {
/*
 * this function will validate options.data against the swagger options.schema
 * according to the spec defined at:
 */
    var $ref,
        circularList,
        data,
        dataReadonlyRemove2,
        ii,
        oneOf,
        schema,
        test,
        tmp;
    if (!options.schema) {
        return;
    }
    data = options.data;
    options.dataReadonlyRemove = options.dataReadonlyRemove || [{}, '', null];
    dataReadonlyRemove2 = options.dataReadonlyRemove[2] || {};
    schema = options.schema;
    circularList = [];
    while (true) {
        // dereference schema.schema
        while (schema.schema) {
            schema = schema.schema;
        }
        // dereference schema.oneOf
        oneOf = (data && schema.oneOf) || [];
        for (ii = 0; ii < oneOf.length; ii += 1) {
            tmp = String(oneOf[ii] && oneOf[ii].$ref)
                .replace('<a href="http://json-schema.org/draft-04/schema#&#39;,%20&#39;%23" target="_blank">http://json-schema.org/draft-04/schema#', '#');
            switch (tmp + ' ' + (!local.isNullOrUndefined(data.$ref) || data.in)) {
            case '#/definitions/bodyParameter body':
            case '#/definitions/formDataParameterSubSchema formData':
            case '#/definitions/headerParameterSubSchema header':
            case '#/definitions/jsonReference true':
            case '#/definitions/pathParameterSubSchema path':
            case '#/definitions/queryParameterSubSchema query':
                schema = local.swaggerSchemaJson.definitions[tmp.split('/')[2]];
                break;
            default:
                switch (tmp) {
                case '#/definitions/bodyParameter':
                case '#/definitions/jsonReference':
                    schema = oneOf[ii ^ 1];
                    break;
                }
            }
            if (!schema.oneOf) {
                break;
            }
        }
        // dereference schema.$ref
        $ref = schema && schema.$ref;
        if (!$ref) {
            break;
        }
        test = circularList.indexOf($ref) < 0;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'schemaDeferenceCircular',
            prefix: options.prefix,
            schema: schema
        });
        circularList.push($ref);
        tmp = $ref.split('/').slice(-2);
        schema = $ref.indexOf('<a href="http://json-schema.org/draft-04/schema#/&#39;" target="_blank">http://json-schema.org/draft-04/schema#/') === 0
            ? local.swaggerSchemaJson[tmp[0]]
            : options.swaggerJson[tmp[0]];
        schema = schema && schema[tmp[1]];
        test = schema;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'schemaDeference',
            prefix: options.prefix,
            schema: options.schema
        });
    }
    if (options.modeDereference) {
        if (options.modeDereferenceDepth > 1) {
            schema = local.jsonCopy(schema);
            Object.keys(schema.properties || {}).forEach(function (key) {
                schema.properties[key] = local.validateBySwaggerSchema({
                    // dereference property
                    modeDereference: true,
                    modeDereferenceDepth: options.modeDereferenceDepth - 1,
                    prefix: options.prefix.concat(['properties', key]),
                    schema: schema.properties[key],
                    swaggerJson: options.swaggerJson
                });
            });
        }
        return schema;
    }
    // validate schema.default
    if (options.modeDefault) {
        data = schema.default;
    }
    // validate semanticRequired
    test = options.modeDefault ||
        !local.isNullOrUndefined(data) ||
        schema.required !== true ||
        schema['x-swgg-notRequired'];
    local.throwSwaggerError(!test && {
        data: data,
        errorType: 'semanticRequired',
        prefix: options.prefix,
        schema: schema
    });
    if (local.isNullOrUndefined(data)) {
        return;
    }
    // validate semanticRequiredArrayItems
    test = !options.modeSchema || local.schemaPType(data) !== 'array' ||
        (typeof local.schemaPItems(data) === 'object' && local.schemaPItems(data));
    local.throwSwaggerError(!test && {
        errorType: 'semanticRequiredArrayItems',
        prefix: options.prefix,
        schema: data
    });
    // remove readOnly property
    if (schema.readOnly) {
        delete options.dataReadonlyRemove[0][options.dataReadonlyRemove[1]];
    }
    // optimization - validate schema.type first
    // 5.5.2. type
    switch (local.schemaPType(schema)) {
    case 'array':
        test = Array.isArray(data);
        break;
    case 'boolean':
        test = typeof data === 'boolean';
        break;
    case 'file':
        test = !options.modeSchema;
        break;
    case 'integer':
        test = Number.isFinite(data) && Math.floor(data) === data;
        switch (schema.format) {
        case 'int32':
            break;
        case 'int64':
            break;
        }
        break;
    case 'number':
        test = Number.isFinite(data);
        switch (schema.format) {
        case 'double':
            break;
        case 'float':
            break;
        }
        break;
    case 'string':
        test = typeof data === 'string' ||
            (!options.modeSchema && schema.format === 'binary');
        switch (test && !options.modeSchema && schema.format) {
        // Clarify 'byte' format #50
        case 'byte':
            test = !(/[^\n\r\+\/0-9\=A-Za-z]/).test(data);
            break;
        case 'date':
        case 'date-time':
            test = JSON.stringify(new Date(data)) !== 'null';
            break;
        case 'email':
            test = local.regexpEmailValidate.test(data);
            break;
        case 'json':
            test = local.tryCatchOnError(function () {
                JSON.parse(data);
                return true;
            }, local.nop);
            break;
        case 'phone':
            test = local.regexpPhoneValidate.test(data);
            break;
        }
        break;
    default:
        test = options.modeSchema || typeof data === 'object';
        break;
    }
    local.throwSwaggerError(!test && {
        data: data,
        errorType: 'itemType',
        prefix: options.prefix,
        schema: schema,
        typeof: typeof data
    });
    tmp = typeof data;
    if (tmp === 'object' && Array.isArray(data)) {
        tmp = 'array';
    }
    switch (tmp) {
    // 5.1. Validation keywords for numeric instances (number and integer)
    case 'number':
        // 5.1.1. multipleOf
        test = typeof schema.multipleOf !== 'number' || data % schema.multipleOf === 0;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'numberMultipleOf',
            prefix: options.prefix,
            schema: schema
        });
        // 5.1.2. maximum and exclusiveMaximum
        test = typeof schema.maximum !== 'number' || (schema.exclusiveMaximum
            ? data < schema.maximum
            : data <= schema.maximum);
        local.throwSwaggerError(!test && {
            data: data,
            errorType: schema.exclusiveMaximum
                ? 'numberExclusiveMaximum'
                : 'numberMaximum',
            prefix: options.prefix,
            schema: schema
        });
        // 5.1.3. minimum and exclusiveMinimum
        test = typeof schema.minimum !== 'number' || (schema.exclusiveMinimum
            ? data > schema.minimum
            : data >= schema.minimum);
        local.throwSwaggerError(!test && {
            data: data,
            errorType: schema.exclusiveMinimum
                ? 'numberExclusiveMinimum'
                : 'numberMinimum',
            prefix: options.prefix,
            schema: schema
        });
        break;
    // 5.2. Validation keywords for strings
    case 'string':
        // 5.2.1. maxLength
        test = typeof schema.maxLength !== 'number' || data.length <= schema.maxLength;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'stringMaxLength',
            prefix: options.prefix,
            schema: schema
        });
        // 5.2.2. minLength
        test = typeof schema.minLength !== 'number' || data.length >= schema.minLength;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'stringMinLength',
            prefix: options.prefix,
            schema: schema
        });
        // 5.2.3. pattern
        test = !schema.pattern || new RegExp(schema.pattern).test(data);
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'stringPattern',
            prefix: options.prefix,
            schema: schema
        });
        break;
    // 5.3. Validation keywords for arrays
    case 'array':
        // 5.3.1. additionalItems and items
        // swagger disallows array items
        data.forEach(function (element, ii) {
            // recurse - schema.additionalItems and schema.items
            local.validateBySwaggerSchema({
                data: element,
                dataReadonlyRemove: [dataReadonlyRemove2, ii, dataReadonlyRemove2[ii]],
                modeSchema: options.modeSchema,
                prefix: options.prefix.concat([ii]),
                schema: local.schemaPItems(schema) || schema.additionalItems,
                swaggerJson: options.swaggerJson
            });
        });
        // 5.3.2. maxItems
        test = typeof schema.maxItems !== 'number' || data.length <= schema.maxItems;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'arrayMaxItems',
            prefix: options.prefix,
            schema: schema
        });
        // 5.3.3. minItems
        test = typeof schema.minItems !== 'number' || data.length >= schema.minItems;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'arrayMinItems',
            prefix: options.prefix,
            schema: schema
        });
        // 5.3.4. uniqueItems
        test = !schema.uniqueItems || data.every(function (element) {
            tmp = element;
            return data.indexOf(element) === data.lastIndexOf(element);
        });
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'arrayUniqueItems',
            prefix: options.prefix,
            schema: schema,
            tmp: tmp
        });
        break;
    // 5.4. Validation keywords for objects
    case 'object':
        // 5.4.1. maxProperties
        test = typeof schema.maxProperties !== 'number' ||
            Object.keys(data).length <= schema.maxProperties;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'objectMaxProperties',
            prefix: options.prefix,
            schema: schema
        });
        // 5.4.2. minProperties
        test = typeof schema.minProperties !== 'number' ||
            Object.keys(data).length >= schema.minProperties;
        local.throwSwaggerError(!test && {
            data: data,
            errorType: 'objectMinProperties',
            prefix: options.prefix,
            schema: schema
        });
        // 5.4.3. required
        local.normalizeValue('list', schema.required).forEach(function (key) {
            test = !local.isNullOrUndefined(data[key]);
            local.throwSwaggerError(!test && {
                data: data,
                errorType: 'objectRequired',
                key: key,
                prefix: options.prefix,
                schema: schema
            });
        });
        // 5.4.4. additionalProperties, properties and patternProperties
        Object.keys(data).forEach(function (key) {
            tmp = null;
            if (schema.properties && schema.properties[key]) {
                tmp = true;
                // recurse - schema.properties
                local.validateBySwaggerSchema({
                    data: data[key],
                    dataReadonlyRemove: [
                        dataReadonlyRemove2,
                        key,
                        dataReadonlyRemove2[key]
                    ],
                    modeSchema: options.modeSchema,
                    prefix: options.prefix.concat([key]),
                    schema: schema.properties[key],
                    swaggerJson: options.swaggerJson
                });
            }
            Object.keys(schema.patternProperties || {}).forEach(function (rgx) {
                if (new RegExp(rgx).test(key)) {
                    tmp = true;
                    // recurse - schema.patternProperties
                    local.validateBySwaggerSchema({
                        data: data[key],
                        modeSchema: options.modeSchema,
                        prefix: options.prefix.concat([key]),
                        schema: schema.patternProperties[rgx],
                        swaggerJson: options.swaggerJson
                    });
                }
            });
/*
* validate
* 5.4.4.4. If "additionalProperties" has boolean value false
*
* In this case, validation of the instance depends on the property set of
* "properties" and "patternProperties". In this section, the property names of
* "patternProperties" will be called regexes for convenience.
*
* The first step is to collect the following sets:
*
* s
* The property set of the instance to validate.
* p
* The property set from "properties".
* pp
* The property set from "patternProperties".
* Having collected these three sets, the process is as follows:
*
* remove from "s" all elements of "p", if any;
* for each regex in "pp", remove all elements of "s" which this regex matches.
* Validation of the instance succeeds if, after these two steps, set "s" is empty.
*/
            test = tmp || schema.additionalProperties !== false;
            local.throwSwaggerError(!test && {
                data: data,
                errorType: 'objectAdditionalProperties',
                key: key,
                prefix: options.prefix,
                schema: schema
            });
            // recurse - schema.additionalProperties
            local.validateBySwaggerSchema({
                data: data[key],
                modeSchema: options.modeSchema,
                prefix: options.prefix.concat([key]),
                schema: schema.additionalProperties,
                swaggerJson: options.swaggerJson
            });
        });
        // 5.4.5. dependencies
        Object.keys(schema.dependencies || {}).forEach(function (key) {
            if (local.isNullOrUndefined(data[key])) {
                return;
            }
            // 5.4.5.2.1. Schema dependencies
            // recurse - schema.dependencies
            local.validateBySwaggerSchema({
                data: data[key],
                modeSchema: options.modeSchema,
                prefix: options.prefix.concat([key]),
                schema: schema.dependencies[key],
                swaggerJson: options.swaggerJson
            });
            // 5.4.5.2.2. Property dependencies
            local.normalizeValue('list', schema.dependencies[key]).every(function (key2) {
                test = !local.isNullOrUndefined(data[key2]);
                local.throwSwaggerError(!test && {
                    data: data,
                    errorType: 'objectDependencies',
                    key: key,
                    key2: key2,
                    prefix: options.prefix,
                    schema: schema
                });
            });
        });
        break;
    }
    // 5.5. Validation keywords for any instance type
    // 5.5.1. enum
    tmp = schema.enum || (!options.modeSchema && (local.schemaPItems(schema) || {}).enum);
    test = !tmp || (Array.isArray(data)
        ? data
        : [data]).every(function (element) {
        return tmp.indexOf(element) >= 0;
    });
    local.throwSwaggerError(!test && {
        data: data,
        errorType: 'itemEnum',
        prefix: options.prefix,
        schema: schema,
        tmp: tmp
    });
    // 5.5.2. type
    local.nop();
    // 5.5.3. allOf
    (schema.allOf || []).forEach(function (element) {
        // recurse - schema.allOf
        local.validateBySwaggerSchema({
            data: data,
            prefix: options.prefix,
            modeSchema: options.modeSchema,
            schema: element,
            swaggerJson: options.swaggerJson
        });
    });
    // 5.5.4. anyOf
    tmp = null;
    test = !schema.anyOf || schema.anyOf.some(function (element) {
        local.tryCatchOnError(function () {
            // recurse - schema.anyOf
            local.validateBySwaggerSchema({
                data: data,
                modeSchema: options.modeSchema,
                prefix: options.prefix,
                schema: element,
                swaggerJson: options.swaggerJson
            });
            return true;
        }, local.nop);
        tmp = tmp || local.utility2._debugTryCatchError;
        return !tmp;
    });
    local.throwSwaggerError(!test && {
        data: data,
        errorType: 'itemOneOf',
        prefix: options.prefix,
        schema: schema,
        tmp: tmp
    });
    // 5.5.5. oneOf
    tmp = !schema.oneOf
        ? 1
        : 0;
    (schema.oneOf || []).some(function (element) {
        local.tryCatchOnError(function () {
            // recurse - schema.oneOf
            local.validateBySwaggerSchema({
                data: data,
                modeSchema: options.modeSchema,
                prefix: options.prefix,
                schema: element,
                swaggerJson: options.swaggerJson
            });
            tmp += 1;
        }, local.nop);
        return tmp > 1;
    });
    test = tmp === 1;
    local.throwSwaggerError(!test && {
        data: data,
        errorType: 'itemOneOf',
        prefix: options.prefix,
        schema: schema,
        tmp: tmp
    });
    // 5.5.6. not
    test = !schema.not || !local.tryCatchOnError(function () {
        // recurse - schema.not
        local.validateBySwaggerSchema({
            data: data,
            modeSchema: options.modeSchema,
            prefix: options.prefix,
            schema: schema.not,
            swaggerJson: options.swaggerJson
        });
        return true;
    }, local.nop);
    local.throwSwaggerError(!test && {
        data: data,
        errorType: 'itemNot',
        prefix: options.prefix,
        schema: schema
    });
    // 5.5.7. definitions
    local.nop();
    // validate data.$ref
    if (schema === local.swaggerSchemaJson.definitions.jsonReference) {
        local.validateBySwaggerSchema({
            modeDereference: true,
            modeSchema: options.modeSchema,
            prefix: options.prefix,
            schema: data,
            swaggerJson: options.swaggerJson
        });
    }
    return schema;
};

```

```javascript
/*
 * output from running code inside browser-console
 */
var mySchema = {
    required: ['myBoolean'],
    properties: {
        myArrayOfStrings: { items: { type: 'string' }, type: 'array' },
        myBoolean: { type: 'boolean' },
        myNumber: { type: 'number' },
        myString: { enum: ['hello world', 'bye world'], type: 'string' }
    }
};

undefined

local.validateBySwaggerSchema({
    data: {
        myArrayOfStrings: ['foo', 'bar'],
        myBoolean: false,
        myString: 'hello world'
    },
    prefix: ['myData'],
    schema: mySchema
});

{required: Array(1), properties: {…}}

local.validateBySwaggerSchema({
    data: {
        myArrayOfStrings: [1, 2],
        myBoolean: false
    },
    prefix: ['myData'],
    schema: mySchema
});

assets.utility2.rollup.js:26060 Uncaught Error: error.itemType - value myData["myArrayOfStrings"][0] = 1 is not a valid string
    at Object.local.throwSwaggerError (assets.utility2.rollup.js:26048)
    at Object.local.validateBySwaggerSchema (assets.utility2.rollup.js:27017)
    at assets.utility2.rollup.js:27097
    at Array.forEach (<anonymous>)
    at Object.local.validateBySwaggerSchema (assets.utility2.rollup.js:27095)
    at assets.utility2.rollup.js:27172
    at Array.forEach (<anonymous>)
    at Object.local.validateBySwaggerSchema (assets.utility2.rollup.js:27167)
    at <anonymous>:2:7
local.throwSwaggerError @ assets.utility2.rollup.js:26048
local.validateBySwaggerSchema @ assets.utility2.rollup.js:27017
(anonymous) @ assets.utility2.rollup.js:27097
local.validateBySwaggerSchema @ assets.utility2.rollup.js:27095
(anonymous) @ assets.utility2.rollup.js:27172
local.validateBySwaggerSchema @ assets.utility2.rollup.js:27167
(anonymous) @ VM341:2

local.validateBySwaggerSchema({
    data: {
        myArrayOfStrings: ['foo', 'bar'],
        myBoolean: null
    },
    prefix: ['myData'],
    schema: mySchema
});

assets.utility2.rollup.js:26060 Uncaught Error: error.objectRequired - object myData = {"myArrayOfStrings":["foo","bar"],"myBoolean":null} must have property "myBoolean"
    at Object.local.throwSwaggerError (assets.utility2.rollup.js:26048)
    at assets.utility2.rollup.js:27158
    at Array.forEach (<anonymous>)
    at Object.local.validateBySwaggerSchema (assets.utility2.rollup.js:27156)
    at <anonymous>:2:7
local.throwSwaggerError @ assets.utility2.rollup.js:26048
(anonymous) @ assets.utility2.rollup.js:27158
local.validateBySwaggerSchema @ assets.utility2.rollup.js:27156
(anonymous) @ VM343:2

local.validateBySwaggerSchema({
    data: {
        myBoolean: false,
        myString: 'hello undefined'
    },
    prefix: ['myData'],
    schema: mySchema
});

assets.utility2.rollup.js:26060 Uncaught Error: error.itemEnum - string myData["myString"] = "hello undefined" can only have items from the list ["hello world","bye world"]
    at Object.local.throwSwaggerError (assets.utility2.rollup.js:26048)
    at Object.local.validateBySwaggerSchema (assets.utility2.rollup.js:27274)
    at assets.utility2.rollup.js:27172
    at Array.forEach (<anonymous>)
    at Object.local.validateBySwaggerSchema (assets.utility2.rollup.js:27167)
    at <anonymous>:2:7
local.throwSwaggerError @ assets.utility2.rollup.js:26048
local.validateBySwaggerSchema @ assets.utility2.rollup.js:27274
(anonymous) @ assets.utility2.rollup.js:27172
local.validateBySwaggerSchema @ assets.utility2.rollup.js:27167
(anonymous) @ VM345:2
```

On Feb 18, 2018, at 9:42 AM, Jordan Harband <[hidden email]> wrote:

Your proposal is conceptually the same as a labelled break statement (ie, GOTO); if you want to follow the advice to avoid labels, I suspect it would apply to your proposal as well.

On Sat, Feb 17, 2018 at 4:44 PM, 李白|字一日 <[hidden email]> wrote:
you can simply put these value handler pairs into an array.


const a = [[0, function(){}], [1, function(){}]];
let i = 0;

while (a[i++][0]) {
a[i - 1][1]()
break;
}


2018-02-18 5:58 GMT+08:00 sagiv ben giat <[hidden email]>:
What kind of argument is that? ESlint isn't a JavaScript runtime, it is fully configurable, and I don't see how it's at all relevant. 

I know ESLint can be configured, it was just an example for how `label`  statements are considered as poor design of code.



Sagiv B.G

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

Screen-Shot-2018-02-18-at-9.32.49-AM-compressor.png (447K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: withBreak blocks

Isiah Meadows-2
In reply to this post by sagiv ben giat
As previously mentioned, this is effectively already covered by
labeled blocks. They aren't slated for removal (some things are just
nearly impossible to express without them), just they have a tendency
to get abused like `goto` in C - people have this tendency in C/C++ to
get a little over-eager to reach for that shotgun when a
`while`/`for`/`if`/etc. would do. So a strong discouragement is
generally warranted, but mainly to get less-skilled coders to not code
themselves into an unmaintainable hole before they can properly wield
the tool and understand why it exists. (It makes for a nice way to
break from non-trivial logic when a separate function would only serve
to complicate the code.)
-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Sat, Feb 17, 2018 at 4:02 PM, sagiv ben giat <[hidden email]> wrote:

> I hope I'm on the right medium for this, I would like to propose a language
> feature.
> withBreak blocks
>
> Well the name might not be the best, but it's just my way to be the most
> clear about this feature proposal.
>
> I often find my self doing this in my code:
>
> const doWork = () => {
>   // try catch omitted for brevity
>   const response = fetchData();
>   do {
>     if (response.error) {
>       log(response.message);
>       break;
>     }
>     if (!response.data) {
>       log("No data");
>       break;
>     }
>     if (!response.data.todos) {
>       log("No Todos");
>       break;
>     }
>     return action({ data: response.data });
>   } while (false);
> };
>
> I'm doing this instead of doing bunch of  if / else if / else blocks or ugly
> nested if blocks.
>  What i would like to have is a block that will let me break without being
> in a loop context.
> Something like this:
> withBreak {
>   if (response.error) {
>     log(response.message);
>     break;
>   }
>   if (!response.data) {
>     log("No data");
>     break;
>   }
>   if (!response.data.todos) {
>     log("No Todos");
>     break;
>   }
>   return action({ data: response.data });
> }
>
> This can be a synthetic sugar for do{}while(false)  behind the scenes.
>
> Best regards,
>
> Sagiv B.G
>
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss