From 820925bff84f984112897102c5d5482cb6387b39 Mon Sep 17 00:00:00 2001 From: Jonah Scheinerman Date: Wed, 30 May 2018 17:19:25 -0400 Subject: [PATCH] Remove circular imports (#28) * Add tslint rules * Move unit typedef * Explicit imports * More stuff * Fix coverage * Unit tests --- package.json | 1 + src/exponent/index.ts | 7 ---- src/measure/__test__/arithmeticSpec.ts | 2 +- src/measure/__test__/mathTests.ts | 2 +- src/measure/__test__/unitTests.ts | 3 +- src/measure/format.ts | 4 +- src/measure/index.ts | 2 +- src/measure/math.ts | 6 +-- src/measure/measure.ts | 11 +++--- src/measure/types.ts | 17 ++++---- src/measure/units.ts | 6 +-- src/quantity/__test__/quantityTests.ts | 8 ++-- src/quantity/quantities.ts | 2 +- src/unit/__test__/unitTests.ts | 54 ++++++++++++++++++++++++++ src/unit/angle.ts | 2 +- src/unit/base.ts | 2 +- src/unit/common.ts | 4 +- src/unit/imperial.ts | 4 +- src/unit/metric.ts | 9 +++-- src/unit/other.ts | 4 +- src/unit/uscu.ts | 4 +- tslint.json | 3 +- yarn.lock | 4 ++ 23 files changed, 105 insertions(+), 56 deletions(-) delete mode 100644 src/exponent/index.ts create mode 100644 src/unit/__test__/unitTests.ts diff --git a/package.json b/package.json index 595889a..ef70f87 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "tslint": "^5.10.0", "tslint-config-prettier": "^1.12.0", "tslint-config-standard": "^7.0.0", + "tslint-no-circular-imports": "^0.4.0", "tslint-plugin-prettier": "^1.3.0", "typescript": "~2.8.3" } diff --git a/src/exponent/index.ts b/src/exponent/index.ts deleted file mode 100644 index 5afb350..0000000 --- a/src/exponent/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { AddExponents } from "./addition"; -import { DivideExponents } from "./division"; -import { MultiplyExponents } from "./multiplication"; - -export { AddExponents, DivideExponents, MultiplyExponents }; -export * from "./common"; -export * from "./utils"; diff --git a/src/measure/__test__/arithmeticSpec.ts b/src/measure/__test__/arithmeticSpec.ts index 7b9e0f0..92ed367 100644 --- a/src/measure/__test__/arithmeticSpec.ts +++ b/src/measure/__test__/arithmeticSpec.ts @@ -1,4 +1,4 @@ -import { IsArithmeticError } from "../../exponent"; +import { IsArithmeticError } from "../../exponent/utils"; import { DivideUnits, ExponentiateUnit, diff --git a/src/measure/__test__/mathTests.ts b/src/measure/__test__/mathTests.ts index 777022d..d0ae4e3 100644 --- a/src/measure/__test__/mathTests.ts +++ b/src/measure/__test__/mathTests.ts @@ -1,4 +1,4 @@ -import { meters, seconds } from "../../unit"; +import { meters, seconds } from "../../unit/base"; import * as SafeMath from "../math"; import { Measure } from "../measure"; diff --git a/src/measure/__test__/unitTests.ts b/src/measure/__test__/unitTests.ts index 311953d..f548280 100644 --- a/src/measure/__test__/unitTests.ts +++ b/src/measure/__test__/unitTests.ts @@ -1,4 +1,5 @@ -import { dimension, divideUnits, exponentiateUnit, multiplyUnits, nthRootUnit, Unit } from "../units"; +import { Unit } from "../types"; +import { dimension, divideUnits, exponentiateUnit, multiplyUnits, nthRootUnit } from "../units"; describe("Units", () => { const x = dimension("x"); diff --git a/src/measure/format.ts b/src/measure/format.ts index 342acac..009f5b1 100644 --- a/src/measure/format.ts +++ b/src/measure/format.ts @@ -1,5 +1,5 @@ -import { Exponent } from "../exponent"; -import { Unit } from "./units"; +import { Exponent } from "../exponent/common"; +import { Unit } from "./types"; // TODO Remove cache and do this statelessly const DimensionSymbolCache: { [dimension: string]: string } = {}; diff --git a/src/measure/index.ts b/src/measure/index.ts index f13e617..9ccccfc 100644 --- a/src/measure/index.ts +++ b/src/measure/index.ts @@ -1,5 +1,5 @@ import * as SafeMath from "./math"; -import { Unit } from "./units"; +import { Unit } from "./types"; export { SafeMath, Unit }; export * from "./measure"; diff --git a/src/measure/math.ts b/src/measure/math.ts index 5fdf94d..d6c34dd 100644 --- a/src/measure/math.ts +++ b/src/measure/math.ts @@ -1,7 +1,7 @@ -import { Exponent } from "../exponent"; +import { Exponent } from "../exponent/common"; import { Measure } from "./measure"; -import { DivideUnits, ExponentiateUnit, MultiplyUnits, NthRootableUnit, NthRootUnit } from "./types"; -import { nthRootUnit, Unit } from "./units"; +import { DivideUnits, ExponentiateUnit, MultiplyUnits, NthRootableUnit, NthRootUnit, Unit } from "./types"; +import { nthRootUnit } from "./units"; export const abs = wrapUnary(Math.abs); export const ceil = wrapUnary(Math.ceil); diff --git a/src/measure/measure.ts b/src/measure/measure.ts index 30ed493..3ded3ff 100644 --- a/src/measure/measure.ts +++ b/src/measure/measure.ts @@ -1,8 +1,7 @@ -import { Exponent } from "../exponent"; -import { Dimensionless } from "../quantity"; +import { Exponent } from "../exponent/common"; import { formatUnit, setDimensionSymbol } from "./format"; -import { DivideUnits, ExponentiateUnit, MultiplyUnits } from "./types"; -import { dimension, divideUnits, exponentiateUnit, multiplyUnits, Unit } from "./units"; +import { DivideUnits, ExponentiateUnit, MultiplyUnits, Unit } from "./types"; +import { dimension, divideUnits, exponentiateUnit, multiplyUnits } from "./units"; export class Measure { // Construction functions @@ -11,7 +10,7 @@ export class Measure { if (symbol) { setDimensionSymbol(dim, symbol); } - return new Measure(1, dimension(dim)); + return new Measure(1, dimension(dim), symbol); } public static dimensionless(value: number): Measure<{}> { @@ -64,7 +63,7 @@ export class Measure { return new Measure(-this.value, this.unit); } - public scale(value: number | Dimensionless): Measure { + public scale(value: number | Measure<{}>): Measure { const numericValue = typeof value === "number" ? value : value.value; return new Measure(numericValue * this.value, this.unit); } diff --git a/src/measure/types.ts b/src/measure/types.ts index 668ec0b..f782c85 100644 --- a/src/measure/types.ts +++ b/src/measure/types.ts @@ -1,13 +1,10 @@ -import { - AddExponents, - ArithmeticError, - DivideExponents, - Exponent, - IsArithmeticError, - MultiplesOf, - MultiplyExponents, -} from "../exponent"; -import { Unit } from "./units"; +import { AddExponents } from "../exponent/addition"; +import { ArithmeticError, Exponent } from "../exponent/common"; +import { DivideExponents } from "../exponent/division"; +import { MultiplyExponents } from "../exponent/multiplication"; +import { IsArithmeticError, MultiplesOf } from "../exponent/utils"; + +export type Unit = Partial<{ [dimension: string]: Exponent }>; // Arithmetic diff --git a/src/measure/units.ts b/src/measure/units.ts index bf78cb7..d20c01e 100644 --- a/src/measure/units.ts +++ b/src/measure/units.ts @@ -1,7 +1,5 @@ -import { ArithmeticError, Exponent, MaxExponent, MinExponent } from "../exponent"; -import { DivideUnits, ExponentiateUnit, MultiplyUnits, NthRootableUnit, NthRootUnit } from "./types"; - -export type Unit = Partial<{ [dimension: string]: Exponent }>; +import { ArithmeticError, Exponent, MaxExponent, MinExponent } from "../exponent/common"; +import { DivideUnits, ExponentiateUnit, MultiplyUnits, NthRootableUnit, NthRootUnit, Unit } from "./types"; export function dimension(dim: D): { [K in D]: 1 } { // TODO Remove cast to any somehow diff --git a/src/quantity/__test__/quantityTests.ts b/src/quantity/__test__/quantityTests.ts index a072a06..5f0e485 100644 --- a/src/quantity/__test__/quantityTests.ts +++ b/src/quantity/__test__/quantityTests.ts @@ -1,7 +1,7 @@ -import { Measure } from "../../measure"; +import { Measure } from "../../measure/measure"; import * as Quantity from "../quantities"; -describe("Quantity", () => { +describe("Quantities", () => { const QuantityNames = Object.keys(Quantity); function forEachQuantity(fn: (quantity: Measure, name: string) => void) { @@ -10,7 +10,7 @@ describe("Quantity", () => { }); } - it("No two quantities should be the same", () => { + it("no two quantities should have the same dimensions", () => { forEachQuantity((a, aName) => { forEachQuantity((b, bName) => { if (aName === bName) { @@ -26,7 +26,7 @@ describe("Quantity", () => { }); }); - it("All quantities should be normalized", () => { + it("all quantities should be normalized", () => { forEachQuantity(quantity => { expect(quantity.value).toBe(1); }); diff --git a/src/quantity/quantities.ts b/src/quantity/quantities.ts index 01bbb49..9022c92 100644 --- a/src/quantity/quantities.ts +++ b/src/quantity/quantities.ts @@ -1,4 +1,4 @@ -import { Measure } from "../measure"; +import { Measure } from "../measure/measure"; import * as Base from "../unit/base"; // Dimensionless diff --git a/src/unit/__test__/unitTests.ts b/src/unit/__test__/unitTests.ts new file mode 100644 index 0000000..a94d093 --- /dev/null +++ b/src/unit/__test__/unitTests.ts @@ -0,0 +1,54 @@ +import { Measure } from "../../measure/measure"; +import * as Units from "../../unit"; +import { meters } from "../base"; +import { kilo, micro } from "../metric"; + +describe("Units", () => { + const UnitNames = Object.keys(Units); + + function forEachUnit(fn: (unit: Measure, name: string) => void) { + UnitNames.forEach(name => { + const value = (Units as any)[name]; + if (value instanceof Measure) { + fn(value, name); + } else { + for (const subName in value) { + if (value.hasOwnProperty(subName)) { + const unit = value[subName]; + fn(unit, subName); + } + } + } + }); + } + + it("all units should have a symbol", () => { + forEachUnit((unit, name) => { + try { + expect(unit.getSymbol()).not.toBeUndefined(); + } catch (e) { + console.log(`Unit ${name} has no symbol defined.`); + throw e; + } + }); + }); + + describe("prefixes", () => { + it("should scale the base unit", () => { + const km = kilo(meters); + expect(km.getUnit()).toEqual(meters.getUnit()); + expect(km.value).toBe(1000); + }); + + it("should apply a prefix when a symbol is present on the base unit", () => { + expect(kilo(meters).getSymbol()).toBe("km"); + }); + + it("should not apply a prefix when a symbo is not present on the base unit", () => { + const blargs = Measure.of(1_000_000, meters); + const microblargs = micro(blargs); + expect(microblargs.getSymbol()).toBeUndefined(); + expect(microblargs.value).toBe(1); + }); + }); +}); diff --git a/src/unit/angle.ts b/src/unit/angle.ts index 1efb0f6..7bb2354 100644 --- a/src/unit/angle.ts +++ b/src/unit/angle.ts @@ -1,4 +1,4 @@ -import { Measure } from "../measure"; +import { Measure } from "../measure/measure"; import { radians } from "./base"; export const pi = Measure.of(Math.PI, radians, "pi"); diff --git a/src/unit/base.ts b/src/unit/base.ts index 3729875..b6b0d48 100644 --- a/src/unit/base.ts +++ b/src/unit/base.ts @@ -1,4 +1,4 @@ -import { Measure } from "../measure"; +import { Measure } from "../measure/measure"; export const meters = Measure.dimension("length", "m"); export const kilograms = Measure.dimension("mass", "kg"); diff --git a/src/unit/common.ts b/src/unit/common.ts index 030d8b8..90b6bd6 100644 --- a/src/unit/common.ts +++ b/src/unit/common.ts @@ -1,5 +1,5 @@ -import { Measure } from "../measure"; -import { Quantity } from "../quantity"; +import { Measure } from "../measure/measure"; +import * as Quantity from "../quantity/quantities"; import { grams, meters, seconds } from "./base"; // Time diff --git a/src/unit/imperial.ts b/src/unit/imperial.ts index 773cb42..e2f8050 100644 --- a/src/unit/imperial.ts +++ b/src/unit/imperial.ts @@ -1,5 +1,5 @@ -import { cubic, Measure } from "../measure"; -import { Quantity } from "../quantity"; +import { cubic, Measure } from "../measure/measure"; +import * as Quantity from "../quantity/quantities"; import { grains, inches, pounds } from "./common"; // Liquid Volume diff --git a/src/unit/metric.ts b/src/unit/metric.ts index 422c762..e6709cb 100644 --- a/src/unit/metric.ts +++ b/src/unit/metric.ts @@ -1,5 +1,6 @@ -import { Measure, Unit } from "../measure"; -import { Quantity } from "../quantity"; +import { Measure } from "../measure/measure"; +import { Unit } from "../measure/types"; +import * as Quantity from "../quantity/quantities"; import { amperes, candela, kilograms, meters, moles, seconds, steradians } from "./base"; export const hertz: Quantity.Frequency = seconds.inverse().withSymbol("Hz"); @@ -17,8 +18,8 @@ export const webers: Quantity.MagneticFlux = joules.per(amperes).withSymbol("Wb" export const teslas: Quantity.MagneticFluxDensity = volts.times(seconds.per(meters.squared())).withSymbol("T"); export const sieverts: Quantity.RadiationDose = joules.per(kilograms).withSymbol("Sv"); export const katals: Quantity.CatalyticActivity = moles.per(seconds).withSymbol("kat"); -export const lumens: Quantity.LuminousFlux = candela.times(steradians); -export const luxes: Quantity.Illuminance = lumens.per(meters.squared()); +export const lumens: Quantity.LuminousFlux = candela.times(steradians).withSymbol("lm"); +export const luxes: Quantity.Illuminance = lumens.per(meters.squared()).withSymbol("lx"); // Prefixes diff --git a/src/unit/other.ts b/src/unit/other.ts index e800fe9..0877ec3 100644 --- a/src/unit/other.ts +++ b/src/unit/other.ts @@ -1,5 +1,5 @@ -import { cubic, Measure, square } from "../measure"; -import { Quantity } from "../quantity"; +import { cubic, Measure, square } from "../measure/measure"; +import * as Quantity from "../quantity/quantities"; import { grams, meters, seconds } from "./base"; import { milli, nano, pascals } from "./metric"; diff --git a/src/unit/uscu.ts b/src/unit/uscu.ts index ba3505d..06142bd 100644 --- a/src/unit/uscu.ts +++ b/src/unit/uscu.ts @@ -1,5 +1,5 @@ -import { cubic, Measure } from "../measure"; -import { Quantity } from "../quantity"; +import { cubic, Measure } from "../measure/measure"; +import * as Quantity from "../quantity/quantities"; import { grams, meters } from "./base"; import { grains, inches, pounds } from "./common"; import { micro } from "./metric"; diff --git a/tslint.json b/tslint.json index 19fa1bc..5ab7597 100644 --- a/tslint.json +++ b/tslint.json @@ -2,7 +2,8 @@ "extends": [ "tslint-config-standard", "tslint-config-prettier", - "tslint-plugin-prettier" + "tslint-plugin-prettier", + "tslint-no-circular-imports" ], "rules": { "prettier": [ diff --git a/yarn.lock b/yarn.lock index c6bad83..9aae287 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3315,6 +3315,10 @@ tslint-eslint-rules@^4.1.1: tslib "^1.0.0" tsutils "^1.4.0" +tslint-no-circular-imports@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/tslint-no-circular-imports/-/tslint-no-circular-imports-0.4.0.tgz#da22d442376f0eb5b03738b0b91a3d8949f6b8f3" + tslint-plugin-prettier@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/tslint-plugin-prettier/-/tslint-plugin-prettier-1.3.0.tgz#7eb65d19ea786a859501a42491b78c5de2031a3f"