* TODO [2015-04-04 Sab] dsah: dev manual: add section on human language generation
* TODO [2015-04-04 Sab] [#B] dsah: use temporary variable for str's each_value? :optim:

  - now gen_each() accept fifth argument $code_at_sub_begin that we can use
  - checking against substr($data, $_, 1) everytime might be slow.

* TODO [2015-04-03 Fri] dsah: better error message for hash's each_value


      @key: Not an integer
  
  this can be confused when we use each_key too:
  

      @key: Not an integer
  
  i'd like each_value's error message to be:
  

      @key: Value not an integer
  
  that is, we add a noun. currently i'm reluctant to add this because i've
  forgotten the details of human compiler and haven't refreshed my memory on it
  yet.
  
  UPDATE: req_keys's error message looks rather nice: hash has missing required
  field(s) (b, c)

* TODO [2015-04-03 Fri] [#B] dsah: in or logic, shortcut after $_sah_ok = 1

  [str => "match|" => ["a","b","c"]]
  
  so:
  
              (# op=or
              ((do {
                  my $_sahv_ok = 0;
                  my $_sahv_nok = 0;
  
                  # clause: match
                  (($data =~ qr((?:(?-)a))) ? ++$_sahv_ok : ++$_sahv_nok)
  
                  &&
  
                  (($data =~ qr((?:(?-)b))) ? ++$_sahv_ok : ++$_sahv_nok)
  
                  &&
  
                  (($data =~ qr((?:(?-)c))) ? ++$_sahv_ok : ++$_sahv_nok) && $_sahv_ok >= 1 && ($err_data = undef, 1)}) ? 1 : (($err_data //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Must match regex pattern one of [\"a\",\"b\",\"c\"]"),0)))));
  
  becomes:
  
              (# op=or
              ((do {
                  # clause: match
                  (($data =~ qr((?:(?-)a))) ? 1:0)
  
                  ||
  
                  (($data =~ qr((?:(?-)b))) ? 1:0)
  
                  &&
  
                  (($data =~ qr((?:(?-)c))) ? 1:(($err_data = ...), 0))
              }))

* WISHLIST [2015-04-08 Wed] dsah: improve error message for any

  [any, of => [int, [str => match => "ab"]]]
  
  if data fails to validate, the error message is the first schema's "Not an
  integer", perhaps we'd like it to be "Not any of (integer, text matching "ab")"?

* BUG [2015-03-26 Thu] dsah: any

  for example: in sah-eg, hash-headers.yaml, we have each_index to validate key
  name and each_value to validate values. the key name validation is currently
  ignored.
  

      [hash, {
        each_key: ['str*', match: '\A\w+(-\w+)*\z'],
        each_value: ['any*', of, ['str*', ['array*', of, 'str*']]]
      }]
  
  UPDATE [2015-04-03 Fri]: the problem is with "any" and the second type.
  

      {"Foo"=>"str", "Bar-Baz"=>["str"], "Qux"=>["str",[]]}
  
  the above hash is okay, when it shouldn't be. the Qux value is not a str nor an
  array of str.
  
  in fact, this schema:
  

      ['any*', of, ['str*', ['array*', of, 'str*']]]
  
  still allows:
  

      [[]]
  
  UPDATE [2015-04-08 Wed]: as i said before this only happens when
  return_type=str, things are okay for return_type=bool or full. but some schema
  is okay, e.g. ['any*', of, ['int', ['str', 'match', 'ab']]].
  
  ok, ketauan penyebabnya adalah list flattening, e.g.:
  

      [push(@_sahv_dpath,undef), (... && ... && ...), pop(@_sahv_dpath)]->[1]
      [push(@_sahv_dpath,undef), (($err_data //= "Not of type text"), 0), pop(@_sahv_dpath)]->[1]
      "Not of type text"
  
  seharusnya:
  

      [push(@_sahv_dpath,undef), ~~(... && ... && ...), pop(@_sahv_dpath)]->[1]
      [push(@_sahv_dpath,undef), ~~(($err_data //= "Not of type text"), 0), pop(@_sahv_dpath)]->[1]
      [push(@_sahv_dpath,undef), 0, pop(@_sahv_dpath)]->[1]
      0
  
  di js ini tidak terjadi.

* TODO [2013-10-15 Sel] dsah: bool: handle JSON::{PP,XS}::Boolean objects [#C]

  - either create a special plugin to convert the object to 1/0 prior to
    validating, or don't assume bool is always !ref($data)?
  - sekarang sih gak usah dulu, gw cuma butuh di periga-argv dan periahs aja yang
    menerima json dari external lalu pass them to functions.

* TODO [2013-10-02 Wed] dsah: opsi utk generate translatable message strings instead of static strings, where we need to regenerate wrapper code just to change language

  contoh, instead of:

      ...
        24|        # check arguments
        25|        for (keys %args) {
        26|            if (!/\A(-?)\w+(\.\w+)*\z/o) {
        27|                $res = [400, "Invalid argument name '$_'"];
        28|                goto RETURN_RES;
        29|            }
        30|            if (!($1 || $_ ~~ ['array','round'])) {
        31|                $res = [400, "Unknown argument '$_'"];
        32|                goto RETURN_RES;
        33|            }
        34|        }
        35|        if (exists($args{'array'})) {
        36|            my $err_array;
        37|                # req #0
        38|                ((defined($args{'array'})) ? 1 : (($err_array //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . "Required input not specified"),0))
          |
      ...
  we generate this instead:

      ...
        24|        # check arguments
        25|        for (keys %args) {
        26|            if (!/\A(-?)\w+(\.\w+)*\z/o) {
        27|                $res = [400, _loc("Invalid argument name '%s'", $_)];
        28|                goto RETURN_RES;
        29|            }
        30|            if (!($1 || $_ ~~ ['array','round'])) {
        31|                $res = [400, _loc("Unknown argument '%s'", $_)];
        32|                goto RETURN_RES;
        33|            }
        34|        }
        35|        if (exists($args{'array'})) {
        36|            my $err_array;
        37|                # req #0
        38|                ((defined($args{'array'})) ? 1 : (($err_array //= (@$_sahv_dpath ? '@'.join("/",@$_sahv_dpath).": " : "") . _loc("Required input not specified")),0))
          |
      ...

* TODO [2013-01-30 Wed] dsah: js: tambah implementasi Object.keys untuk yg belum support ECMAScript 5 (mis: IE8 ke bawah, opera < 12)

  - boy, javascript sucks.

* TODO [2013-01-30 Wed] dsah: js: tambah implementasi Array.prototype.{indexOf,every} di kode jika utk client/IE (gak punya array.prototype.indexOf)

  - boy, javascript sucks.

* IDEA [2013-01-17 Thu] dsah: from schema, generate code other than validator

  e.g. data compliance measurer, data transformer, or whatever.

* TODO dsah: format_ccls: array of ccl: sort list di belakang
* TODO dsah: human: markdown
* TODO dsah: implement def/subschema
* TODO dsah: human: saat find base type, gak usah merge semua clauses

  mis:

      [pos_int, div_by=>2]
  gak perlu ditranslate jadi:

      [int, min=>0, div_by=>2] # => "integer, at least 0, divisible by 2"
  melainkan cukup:

      # => "positive integer, divisible by 2"
  kecuali jika pos_int gak punya name. pos_int yang punya name itu sbb:

      [int, min=>0, name=>["positive integer", "positive integers"], "name(id_ID)"=>"biangan bluat positif"]

* TODO dsah: human: use base schema's name (or name.alt.lang.XX) e.g.


      pos_int: [int, {name=>["positive integer", "positive integers"], min=>0}]
      schema: [pos_int, div_by=>2] -> "positive integer, must be divisible by 2" (gak diterjemahin lagi jadi "integer, must be at least 0, must be divisible by 2")

* TODO dsah: expression: variabel $_ (= data term) dulu aja
* TODO dsah: create Compiler Perlish and move common stuffs there
* TODO dsah: write js compiler

    - note: js juga ada lexical dengan let, tinggal { let a=1; ... { let a=2; ...
      } }
    - padanan do { ... } di js? (i'm thinking (function() { let x=... })(), but
      maybe there's another alternative? di js juga bisa { ... { ... } ... }
      ternyata.
    - demo: form + jquery + jquery validation (+ bootstrap for prettiness)

* TODO dsah: prefilters (mis: utk convert timestamp unix ke datetime sblm diproses)
* TODO dsah: strategi sort clause berdasarkan dependency [2012-09-26 Wed]

    + TH: normalize_arg agar kita bisa normalize schemas yang ada di clause arg
    + normalize_schema memanggil normalize_arg
    + TH: get_schemas_in_arg utk return semua schemas yang ada di arg
    + _form_deps memanggil get_schemas_in_arg secara rekursif untuk get semua
      subschemas. baru setelah itu dilist semua expression dan sort berdasarkan
      variable dependency.

* TODO dsah: strategi merge:

    + merge dan buang merge prefixes
    + rekursif?
    + normalize hasil merge

* TODO [2012-11-20 Tue] dsah: type scalar (utk check specific perl stuffs: weak ref, blessed, tainted, read_only, ref) [#C]

  - turunan dari BaseType (jangan dari str)
  - clauses: is_ref, is_weak_ref, blessed, tainted, is_ro

* IDEA [2012-11-20 Tue] dsah: generate XS code [#C]
* IDEA [2012-11-20 Tue] dsah: support re2 (mencegah dos attack) [#C]
* IDEA [2012-11-13 Tue] perl module: dsah: modul utk menghasilkan schema by examples

  mis: dikasih valid => [1, 3, 2, 6, 5, 10], invalid => ["foo", -1, 11], hasilnya
  [int, min=>1, max=>10].
  
  konsepnya sama seperti "create mail filters on messages like these".

* TODO [2012-10-31 Wed] dsah: bagaimana menghandle clause yang return something other than bool?

  - contoh: cset

* TODO [2014-01-04 Sab] dsah: Prog: for return_type=full, add msgpath/dpath/spath (proper array form) on each error message
* TODO [2014-01-04 Sab] dsah: js/perl: test validating under compile option debug=1 (debug_log=1)

  - karna saat ini di js masih error hasil kompilasi jika debug_log hidup.

* WISHLIST [2013-11-23 Sab] dsah: configurable term utk hash/field/etc

  nanti translation di Data::Lang::id_ID isinya:
  
  q[hash]
  q[hash]
  
  q[$TERM_HASH contains non-allowable TERM_KEY %s]
  q[$TERM_HASH mengandung $TERM_KEY %s]
  
  default $TERM_KEY = field, default $TERM_HASH = hash.
  
  bisa diconfigure di Data::Sah::Compiler::human compile option, mis: terms =>
  {TERM_HASH => "hash", TERM_KEY=>"field"}. nanti "hash" dan "field" ini
  ditranslate dulu.

* TODO [2013-11-20 Rab] dsah: make it easier to customize or translate error messages

  - selain memasangnya di schema (lewat atribut .err_msg)
  - contohnya, "Data is not of type %s", gw pengen ganti ini jadi "You didn't
    input a number" tanpa gw harus monkey patching atau tau terlalu banyak detil
    Data::Sah internal, kalo bisa.
  - sebenernya ini masuk ke translation. kita ingin subclass en, lalu menambahkan
    frase2x kita sendiri.

* TODO [2014-03-28 Fri] dsah: fix broken tests after adding normalize_clset
* TODO [2014-03-28 Fri] dsah: add tests for normalize_clset, test that 'clset' clause normalizes its value
* BUG [2014-01-04 Sat] dsah: js compiler: jika debug=1 (debug_log=1) maka kode yg digenerate error (dan agak aneh memang hasilnya, misalnya ada '&&' di awal)
* TODO [2014-12-19 Jum] dsah: testlib.pl: refactor the other spectest routines to use test_sah cases() too

  - UPDATE: not so straightforward because there are lots of per-compiler specific
    code.
  

* TODO [2015-01-03 Sat] dsah: perl compiler: Replace smartmatch because of its inconsistent behavior

  C<<$data ~~ ["x", 1]>> will do string comparison, while C<<$data ~~ [1, "x"]>>
  or even C<<$data ~~ ["1", "x"]>> will do a numeric comparison.

* IDEA [2014-04-29 Sel] dsah: date: support format ISO8601 ("2014-04-29T01:02:03")

  - ingat, format ISO8601 ini ada banyak lho variannya... kita pilih mensupport
    satu atau beberapa varian aja.
  - ntar kalo butuh deh, ke depannya kemungkinan sih akan butuh

* IDEA [2014-04-29 Sel] dsah: plc: return normalized datetime utk tipe date?

  - mempermudah fungsi agar langsung dapet
  - optimize juga, gak usah calculate coerce_date() 2x.
  - fungsi dapat melakukan gini: $date = $wrap_result{date} //
    coerce_date($args{date}); jadi bisa avoid calculate 2x tapi juga jika fungsi
    tidak diwrap masih bisa jalan.

* BUG [2014-06-20 Fri] dsah: gagal/salah dalam mengeset locale

  ada pesan error ini di log periahs:
  

      [pid 28341] [2014/06/20 09:21:51] Data/Sah/Lang/C cannot be found, falling back to en_US
  
  kayaknya cara ngeset locale salah, jadi nama package terbawa gitu.

* BUG [2014-04-29 Sel] dsah: jsc: hasil compile error jika debug=1 [#C]

  ada 'function() { ... }' lagi ngewrap 'function (data) { ... }' dan jadi syntax
  error.

* TODO [2014-04-27 Sun] dsah: use Sah-Schema-Sah untuk determine which prop contains another schema, so it can offer recursive normalization

  - agak ribet, karena clause2x yang mana aja tergantung dari tipenya.
