diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..02f7fdb --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,13 @@ +name: Test + +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + + - run: npm install + - run: npm build + - run: npm test diff --git a/.gitignore b/.gitignore index a3e8c4c..ccb38d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ # TypeScript (only needed for debugging) +/lib +/node_modules *.js.map launchSettings.json diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..4ddba9a --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "printWidth": 120, + "trailingComma": "all", + "singleQuote": true +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..7a8ccfc --- /dev/null +++ b/package-lock.json @@ -0,0 +1,339 @@ +{ + "name": "qowaiv.js", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz", + "integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "diff": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "jasmine": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.5.0.tgz", + "integrity": "sha512-DYypSryORqzsGoMazemIHUfMkXM7I7easFaxAvNM3Mr6Xz3Fy36TupTrAOxZWN8MVKEU5xECv22J4tUQf3uBzQ==", + "dev": true, + "requires": { + "glob": "^7.1.4", + "jasmine-core": "~3.5.0" + } + }, + "jasmine-core": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.5.0.tgz", + "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "prettier": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", + "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", + "dev": true + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "tslint": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.0.tgz", + "integrity": "sha512-2vqIvkMHbnx8acMogAERQ/IuINOq6DFqgF8/VDvhEkBqQh/x6SP0Y+OHnKth9/ZcHQSroOZwUQSN18v8KKF0/g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + } + }, + "tslint-config-prettier": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz", + "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==", + "dev": true + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "typescript": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", + "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/package.json b/package.json index 231b935..a0fc0c3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,22 @@ { - "name": "Qowaiv.js", + "name": "qowaiv.js", "version": "0.0.1", "description": "Qowaiv implements common, universal domain objects. These types form the base of your domain model.", "author": "Qowaiv Community", - "license": "MIT" - } \ No newline at end of file + "license": "MIT", + "devDependencies": { + "jasmine": "^3.5.0", + "prettier": "^1.18.2", + "tslint": "^5.20.0", + "tslint-config-prettier": "^1.18.0", + "typescript": "^3.6.3" + }, + "scripts": { + "build": "tsc", + "format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"", + "lint": "tslint -p tsconfig.json" + }, + "files": [ + "lib/**/*" + ] +} diff --git a/src/Qowaiv/Guid.ts b/src/Qowaiv/Guid.ts index b88d051..53f865e 100644 --- a/src/Qowaiv/Guid.ts +++ b/src/Qowaiv/Guid.ts @@ -1,177 +1,174 @@ -module Qowaiv { +namespace Qowaiv { + /** + * Represents a Globally unique identifier (GUID). + */ + export class Guid implements IEquatable, IFormattable, IJsonStringifyable { + /** + * Returns a new empty GUID. + */ + public static empty(): Guid { + return new Guid(); + } /** - * Represents a Globally unique identifier (GUID). + * Returns true if the val represents valid GUID, otherwise false. + * @param {string} s A string containing GUID. + * @remarks This method calls create(). It's of no use, to call isValid(), + * to avoid a create() call. */ - export class Guid implements IEquatable, IFormattable, IJsonStringifyable { - - /** - * @constructor - * @remarks It is the default constructor, for creating an actual GUID - * you will normally use Guid.newGuid() or Guid.parse(string). - */ - private constructor() { } - - /** - * The underlying value. - */ - private v = '00000000-0000-0000-0000-000000000000'; - - /** - * Returns a string that represents the current GUID. - */ - public toString(): string { - return this.v; - } - /** - * Returns a string that represents the current GUID. - */ - public format(f?: string): string { - switch (f) { - case 'B': return '{' + this.v + '}'; - case 'b': return '{' + this.v.toLowerCase() + '}'; - case 'S': return this.v.replace(/-/g, ''); - case 's': return this.v.replace(/-/g, '').toLowerCase(); - case 'l': return this.v.toLowerCase(); - case 'U': case 'u': default: return this.v; - } - } - /** - * Returns a JSON representation of the GUID. - */ - public toJSON(): string { - return this.v; - } + public static isValid(s: string): boolean { + return /^[0-9ABCDEF]{32}$/i.test(Guid.strip(s)); + } - /** - * Returns the version of the GUID. - */ - public version(): number { - return parseInt(this.v.substr(14, 1)); - } + /** + * Creates a GUID from a JSON string. + * @param {string} s A JSON string representing the GUID. + * @returns {Guid} A GUID if valid, otherwise null. + */ + public static fromJSON(s: string): Guid { + return Guid.parse(s); + } - /** - * Returns true if other is not null or undefined and a GUID - * representing the same value, otherwise false. - */ - public equals(other: any): boolean { - return other !== null && - other !== undefined && - other instanceof (Guid) && - other.v === this.v; - } + /** + * Creates a GUID. + * @param {string} s A string containing GUID to convert or a number. + * @returns {Guid} A GUID if valid, otherwise null. + */ + public static parse(s: string): Guid { + // an empty string should equal Guid.Empty. + if (s === '') { + return new Guid(); + } + + s = Guid.strip(s).toUpperCase(); + + // if the value parameter is valid + if (Guid.isValid(s)) { + const guid = new Guid(); + guid.v = Guid.unstrip(s); + return guid; + } + // return undefined if creation failed. + return undefined; + } - /** - * Creates a GUID from a JSON string. - * @param {string} s A JSON string representing the GUID. - * @returns {Guid} A GUID if valid, otherwise null. - */ - public static fromJSON(s: string): Guid { - return Guid.parse(s); + /** + * Creates a GUID. + * @param {Guid} An optional seed. + * @returns {Guid} A random GUID. + */ + public static newGuid(seed?: Guid): Guid { + const guid = new Guid(); + guid.v = Guid.unstrip(Guid.rnd()); + + if (seed !== null && seed instanceof Guid) { + const lookup = '0123456789ABCDEF'; + let merged = ''; + for (let i = 0; i < 36; i++) { + const l = lookup.indexOf(seed.v.charAt(i)); + const r = lookup.indexOf(guid.v.charAt(i)); + merged += l === -1 || r === -1 ? guid.v.charAt(i) : lookup.charAt(l ^ r); } + guid.v = merged; + } + // set version to 4 (Random). + guid.v = guid.v.substr(0, 14) + '4' + guid.v.substr(15); - /** - * Returns true if the val represents valid GUID, otherwise false. - * @param {string} s A string containing GUID. - * @remarks This method calls create(). It's of no use, to call isValid(), - * to avoid a create() call. - */ - public static isValid(s: string): boolean { - return /^[0-9ABCDEF]{32}$/i.test(Guid.strip(s)); - } + return guid; + } - /** - * Creates a GUID. - * @param {string} s A string containing GUID to convert or a number. - * @returns {Guid} A GUID if valid, otherwise null. - */ - public static parse(s: string): Guid { - - // an empty string should equal Guid.Empty. - if (s === '') { return new Guid(); } - - s = Guid.strip(s).toUpperCase(); - - // if the value parameter is valid - if (Guid.isValid(s)) { - let guid = new Guid(); - guid.v = Guid.unstrip(s); - return guid; - } - // return undefined if creation failed. - return undefined; - } + private static strip(s: string): string { + let replace = s.replace(/-/g, ''); + if (replace.indexOf('{') === 0 && replace.lastIndexOf('}') === replace.length - 1) { + replace = replace.substr(1, replace.length - 2); + } + return replace; + } + private static unstrip(s: string): string { + return s.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '$1-$2-$3-$4-$5').toUpperCase(); + } - private static strip(s: string): string { - let replace = s.replace(/-/g, ''); - if (replace.indexOf('{') == 0 && replace.lastIndexOf('}') == replace.length - 1) { - return replace.substr(1, replace.length - 2); - } - return replace; - } - private static unstrip(s: string): string { - return s.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '$1-$2-$3-$4-$5').toUpperCase(); - } + /** + * Creates a rnd GUID base string. + * @remarks Uses window.crypto.getRandomValues() when availabe, + * otherwise Math.Random(). + */ + private static rnd(): string { + if (typeof window.crypto.getRandomValues === 'function') { + const bytes = new Uint32Array(4); + window.crypto.getRandomValues(bytes); + return bytes[0].toString(16) + bytes[1].toString(16) + bytes[2].toString(16) + bytes[3].toString(16); + } + return Guid.rndGuid() + Guid.rndGuid() + Guid.rndGuid() + Guid.rndGuid(); + } - /** - * Returns a new empty GUID. - */ - public static empty(): Guid { - return new Guid(); - } + /** + * Creates random GUID blocks. + * @remarks called 4 times by Guid.newGuid(). + */ + private static rndGuid(): string { + return (Math.random().toString(16) + '000000000').substr(2, 8); + } - /** - * Creates a GUID. - * @param {Guid} An optional seed. - * @returns {Guid} A random GUID. - */ - public static newGuid(seed?: Guid): Guid { - - let guid = new Guid(); - guid.v = Guid.unstrip(Guid.rnd()); - - if (seed !== null && seed instanceof (Guid)) { - let lookup = '0123456789ABCDEF'; - var merged = ''; - for (var i = 0; i < 36; i++) { - let l = lookup.indexOf(seed.v.charAt(i)); - let r = lookup.indexOf(guid.v.charAt(i)); - merged += l === -1 || r === -1 ? guid.v.charAt(i) : lookup.charAt(l ^ r); - } - guid.v = merged; - } - // set version to 4 (Random). - guid.v = guid.v.substr(0, 14) + '4' + guid.v.substr(15); - - return guid; - } + /** + * The underlying value. + */ + private v = '00000000-0000-0000-0000-000000000000'; - /** - * Creates a rnd GUID base string. - * @remarks Uses window.crypto.getRandomValues() when availabe, - * otherwise Math.Random(). - */ - private static rnd(): string { - if (typeof window.crypto.getRandomValues === "function") { - let bytes = new Uint32Array(4); - window.crypto.getRandomValues(bytes); - return bytes[0].toString(16) + - bytes[1].toString(16) + - bytes[2].toString(16) + - bytes[3].toString(16); - } - return Guid.rndGuid() + - Guid.rndGuid() + - Guid.rndGuid() + - Guid.rndGuid(); - } + /** + * @constructor + * @remarks It is the default constructor, for creating an actual GUID + * you will normally use Guid.newGuid() or Guid.parse(string). + */ + private constructor() {} - /** - * Creates random GUID blocks. - * @remarks called 4 times by Guid.newGuid(). - */ - private static rndGuid(): string { - return (Math.random().toString(16) + '000000000').substr(2, 8); - } + /** + * Returns a string that represents the current GUID. + */ + public toString(): string { + return this.v; + } + /** + * Returns a string that represents the current GUID. + */ + public format(f?: string): string { + switch (f) { + case 'B': + return '{' + this.v + '}'; + case 'b': + return '{' + this.v.toLowerCase() + '}'; + case 'S': + return this.v.replace(/-/g, ''); + case 's': + return this.v.replace(/-/g, '').toLowerCase(); + case 'l': + return this.v.toLowerCase(); + case 'U': + case 'u': + default: + return this.v; + } + } + /** + * Returns a JSON representation of the GUID. + */ + public toJSON(): string { + return this.v; + } + + /** + * Returns the version of the GUID. + */ + public version(): number { + return parseInt(this.v.substr(14, 1), 10); + } + + /** + * Returns true if other is not null or undefined and a GUID + * representing the same value, otherwise false. + */ + public equals(other: any): boolean { + return other !== null && other !== undefined && other instanceof Guid && other.v === this.v; } -} + } +} diff --git a/src/Qowaiv/Interfaces/IEquatable.ts b/src/Qowaiv/Interfaces/IEquatable.ts index 97b690b..680b337 100644 --- a/src/Qowaiv/Interfaces/IEquatable.ts +++ b/src/Qowaiv/Interfaces/IEquatable.ts @@ -1,11 +1,10 @@ /** * Defines a generalized method that for determining equality of instances. */ -interface IEquatable -{ - /** - * Returns true if other is not null or undefined and a object - * representing the same value, otherwise false. - */ - equals(other: any): boolean; -} \ No newline at end of file +interface IEquatable { + /** + * Returns true if other is not null or undefined and a object + * representing the same value, otherwise false. + */ + equals(other: any): boolean; +} diff --git a/src/Qowaiv/Interfaces/IFormattable.ts b/src/Qowaiv/Interfaces/IFormattable.ts index 671df02..f80130e 100644 --- a/src/Qowaiv/Interfaces/IFormattable.ts +++ b/src/Qowaiv/Interfaces/IFormattable.ts @@ -1,18 +1,17 @@ /** * Provides functionality to format the value of an object into a string representation. */ -interface IFormattable -{ - /** - * Returns a string that represents the object. - * @returns string. - */ - toString(): string; +interface IFormattable { + /** + * Returns a string that represents the object. + * @returns string. + */ + toString(): string; - /** - * Returns a formatted string that represents the object. - * @param {string} f The format that this describes the formatting. - * @returns formatted string. - */ - format(f: string): string; -} \ No newline at end of file + /** + * Returns a formatted string that represents the object. + * @param {string} f The format that this describes the formatting. + * @returns formatted string. + */ + format(f: string): string; +} diff --git a/src/Qowaiv/Interfaces/IJsonStringifyable.ts b/src/Qowaiv/Interfaces/IJsonStringifyable.ts index cdbd525..372322c 100644 --- a/src/Qowaiv/Interfaces/IJsonStringifyable.ts +++ b/src/Qowaiv/Interfaces/IJsonStringifyable.ts @@ -2,8 +2,8 @@ * To support JSON.stringify() */ interface IJsonStringifyable { - /** - * Returns a JSON representation of the object. - */ - toJSON(): any; -} \ No newline at end of file + /** + * Returns a JSON representation of the object. + */ + toJSON(): any; +} diff --git a/src/Qowaiv/_eq.js b/src/Qowaiv/_eq.js index 3522a94..330159d 100644 --- a/src/Qowaiv/_eq.js +++ b/src/Qowaiv/_eq.js @@ -5,12 +5,14 @@ * @returns True if the left operand equals the right operand, otherwise false. */ function eq(l, r) { - if (arguments.length !== 2) { throw new Error('Invalid number of arguments.'); } - if (l !== null && l !== undefined && typeof (l.equals) === 'function') { - return l.equals(r); - } - if (r !== null && r !== undefined && typeof (r.equals) === 'function') { - return r.equals(l); - } - return l === r; -} \ No newline at end of file + if (arguments.length !== 2) { + throw new Error('Invalid number of arguments.'); + } + if (l !== null && l !== undefined && typeof l.equals === 'function') { + return l.equals(r); + } + if (r !== null && r !== undefined && typeof r.equals === 'function') { + return r.equals(l); + } + return l === r; +} diff --git a/tsconfig.json b/tsconfig.json index 78e9a6b..fe93d69 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,13 +3,14 @@ // enabling the VSCode build tasks "tsc: build" and "tsc: watch". "compilerOptions": { "target": "es5", // Compatible with older browsers - "module": "umd", // Compatible with both Node.js and browser + "module": "amd", // Compatible with both Node.js and browser + "declaration": true, // We build a package after all. "moduleResolution": "node", // Tell tsc to look in node_modules for modules - "outDir": "dist", + "outFile": "./lib/qowaiv.js", "sourceMap": true, // Creates *.js.map files "strict": false, // Strict types, eg. prohibits `var x=0; x=null` "alwaysStrict": true // Enable JavaScript's "use strict" mode }, - "include": ["**/*.ts"], + "include": ["src/**/*.ts"], "exclude": ["node_modules"] } \ No newline at end of file diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..71287e5 --- /dev/null +++ b/tslint.json @@ -0,0 +1,6 @@ +{ + "extends": [ + "tslint:recommended", + "tslint-config-prettier" + ] +} \ No newline at end of file