Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Converting isIP to Typescript? #1263

Closed
fireflysemantics opened this issue Mar 2, 2020 · 3 comments
Closed

Converting isIP to Typescript? #1263

fireflysemantics opened this issue Mar 2, 2020 · 3 comments
Labels
to-be-closed PR or issue that's coming to "end-of-life"

Comments

@fireflysemantics
Copy link

fireflysemantics commented Mar 2, 2020

Just wanted to double check this implementation with ya'll. I put single quotes around 4 and 6, since they should be strings IIUC.

import assertString from './util/assertString';
/**
11.3.  Examples

   The following addresses

             fe80::1234 (on the 1st link of the node)
             ff02::5678 (on the 5th link of the node)
             ff08::9abc (on the 10th organization of the node)

   would be represented as follows:

             fe80::1234%1
             ff02::5678%5
             ff08::9abc%10

   (Here we assume a natural translation from a zone index to the
   <zone_id> part, where the Nth zone of any scope is translated into
   "N".)

   If we use interface names as <zone_id>, those addresses could also be
   represented as follows:

            fe80::1234%ne0
            ff02::5678%pvc1.3
            ff08::9abc%interface10

   where the interface "ne0" belongs to the 1st link, "pvc1.3" belongs
   to the 5th link, and "interface10" belongs to the 10th organization.
 * * */
const ipv4Maybe = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/;
const ipv6Block = /^[0-9A-F]{1,4}$/i;

export function isIP(str:string, version:string = '') {
  assertString(str);
  version = String(version);
  if (!version) {
    return isIP(str, '4') || isIP(str, '6');
  } else if (version === '4') {
    if (!ipv4Maybe.test(str)) {
      return false;
    }
    const parts = str.split('.').sort((a:any, b:any) => a - b);
    return parseInt(parts[3]) <= 255;
  } else if (version === '6') {
    let addressAndZone = [str];
    // ipv6 addresses could have scoped architecture
    // according to https://tools.ietf.org/html/rfc4007#section-11
    if (str.includes('%')) {
      addressAndZone = str.split('%');
      if (addressAndZone.length !== 2) {
        // it must be just two parts
        return false;
      }
      if (!addressAndZone[0].includes(':')) {
        // the first part must be the address
        return false;
      }

      if (addressAndZone[1] === '') {
        // the second part must not be empty
        return false;
      }
    }

    const blocks = addressAndZone[0].split(':');
    let foundOmissionBlock = false; // marker to indicate ::

    // At least some OS accept the last 32 bits of an IPv6 address
    // (i.e. 2 of the blocks) in IPv4 notation, and RFC 3493 says
    // that '::ffff:a.b.c.d' is valid for IPv4-mapped IPv6 addresses,
    // and '::a.b.c.d' is deprecated, but also valid.
    const foundIPv4TransitionBlock = isIP(blocks[blocks.length - 1], '4');
    const expectedNumberOfBlocks = foundIPv4TransitionBlock ? 7 : 8;

    if (blocks.length > expectedNumberOfBlocks) {
      return false;
    }
    // initial or final ::
    if (str === '::') {
      return true;
    } else if (str.substr(0, 2) === '::') {
      blocks.shift();
      blocks.shift();
      foundOmissionBlock = true;
    } else if (str.substr(str.length - 2) === '::') {
      blocks.pop();
      blocks.pop();
      foundOmissionBlock = true;
    }

    for (let i = 0; i < blocks.length; ++i) {
      // test for a :: which can not be at the string start/end
      // since those cases have been handled above
      if (blocks[i] === '' && i > 0 && i < blocks.length - 1) {
        if (foundOmissionBlock) {
          return false; // multiple :: in address
        }
        foundOmissionBlock = true;
      } else if (foundIPv4TransitionBlock && i === blocks.length - 1) {
        // it has been checked before that the last
        // block is a valid IPv4 address
      } else if (!ipv6Block.test(blocks[i])) {
        return false;
      }
    }
    if (foundOmissionBlock) {
      return blocks.length >= 1;
    }
    return blocks.length === expectedNumberOfBlocks;
  }
  return false;
}
@fireflysemantics
Copy link
Author

Also if someone could look over isISBNthat would be awesome as well. I added parseIntto convert chartAt string to integers:

import assertString from './util/assertString';

const isbn10Maybe = /^(?:[0-9]{9}X|[0-9]{10})$/;
const isbn13Maybe = /^(?:[0-9]{13})$/;
const factor = [1, 3];

export function isISBN(str:string, version:string = '') {
  assertString(str);
  version = String(version);
  if (!version) {
    return isISBN(str, '10') || isISBN(str, '13');
  }
  const sanitized:string = str.replace(/[\s-]+/g, '');
  let checksum = 0;
  let i;
  if (version === '10') {
    if (!isbn10Maybe.test(sanitized)) {
      return false;
    }
    for (i = 0; i < 9; i++) {
      checksum += (i + 1) * parseInt(sanitized.charAt(i));
    }
    if (sanitized.charAt(9) === 'X') {
      checksum += 10 * 10;
    } else {
      checksum += 10 * parseInt(sanitized.charAt(9));
    }
    if ((checksum % 11) === 0) {
      return !!sanitized;
    }
  } else if (version === '13') {
    if (!isbn13Maybe.test(sanitized)) {
      return false;
    }
    for (i = 0; i < 12; i++) {
      checksum += factor[i % 2] * parseInt(sanitized.charAt(i));
    }
    if (parseInt(sanitized.charAt(12)) - ((10 - (checksum % 10)) % 10) === 0) {
      return !!sanitized;
    }
  }
  return false;
}


@johannesschobel
Copy link
Contributor

Dear @fireflysemantics ,

that is not really an issue, right? You are proposing a re-write of specific parts of the library to TS. I am not sure if this should be discussed in an issue. What, if everyone starts to propose the rewrite of specific methods in issues? the maintainer would drown in issues that are actually not real issues with the library.

also - before starting to propose TS implementations for methods, a decision whether the library should be rewritten as TS or not should be forced.

Keep in mind, that a rewrite could cause major issues, as this library is a widely used library in the JS world. Such a decision must be well-discussed and backed by the majority of the dev-team!

All the best,
Johannes

@eightshone
Copy link
Contributor

Hi @fireflysemantics ,
First, this is not an issue. Also, why do you want to change the code from JS to TS?

@profnandaa profnandaa added marked-for-close to-be-closed PR or issue that's coming to "end-of-life" and removed marked-for-close labels Mar 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
to-be-closed PR or issue that's coming to "end-of-life"
Projects
None yet
Development

No branches or pull requests

4 participants