From 11b6a199c95be29024d3e9c1ac2ce712ad608110 Mon Sep 17 00:00:00 2001
From: John Firebaugh <john.firebaugh@gmail.com>
Date: Thu, 13 Sep 2018 17:06:50 -0700
Subject: [PATCH] Split Collator/Formatted types into separate files

This avoids a troublesome circular import.
---
 src/data/bucket/symbol_bucket.js              |  2 +-
 .../expression/definitions/collator.js        | 63 +------------------
 .../definitions/{formatted.js => format.js}   | 39 +-----------
 .../expression/definitions/index.js           |  4 +-
 .../expression/definitions/literal.js         |  2 +-
 src/style-spec/expression/parsing_context.js  |  4 +-
 src/style-spec/expression/types/collator.js   | 61 ++++++++++++++++++
 src/style-spec/expression/types/formatted.js  | 37 +++++++++++
 src/style-spec/expression/values.js           | 12 ++--
 .../background_style_layer_properties.js      |  2 +-
 .../circle_style_layer_properties.js          |  2 +-
 .../fill_extrusion_style_layer_properties.js  |  2 +-
 .../fill_style_layer_properties.js            |  2 +-
 .../heatmap_style_layer_properties.js         |  2 +-
 .../hillshade_style_layer_properties.js       |  2 +-
 src/style/style_layer/layer_properties.js.ejs |  2 +-
 .../line_style_layer_properties.js            |  2 +-
 .../raster_style_layer_properties.js          |  2 +-
 .../symbol_style_layer_properties.js          |  4 +-
 src/symbol/mergelines.js                      |  2 +-
 src/symbol/shaping.js                         |  2 +-
 src/symbol/symbol_layout.js                   |  2 +-
 src/symbol/transform_text.js                  |  2 +-
 23 files changed, 131 insertions(+), 123 deletions(-)
 rename src/style-spec/expression/definitions/{formatted.js => format.js} (77%)
 create mode 100644 src/style-spec/expression/types/collator.js
 create mode 100644 src/style-spec/expression/types/formatted.js

diff --git a/src/data/bucket/symbol_bucket.js b/src/data/bucket/symbol_bucket.js
index 17aa10c4d13..3945e7f6f26 100644
--- a/src/data/bucket/symbol_bucket.js
+++ b/src/data/bucket/symbol_bucket.js
@@ -18,7 +18,7 @@ import Anchor from '../../symbol/anchor';
 import { getSizeData } from '../../symbol/symbol_size';
 import { register } from '../../util/web_worker_transfer';
 import EvaluationParameters from '../../style/evaluation_parameters';
-import {Formatted} from '../../style-spec/expression/definitions/formatted';
+import Formatted from '../../style-spec/expression/types/formatted';
 
 
 import type {
diff --git a/src/style-spec/expression/definitions/collator.js b/src/style-spec/expression/definitions/collator.js
index c99f9e3a8df..bc7ae8ad8b8 100644
--- a/src/style-spec/expression/definitions/collator.js
+++ b/src/style-spec/expression/definitions/collator.js
@@ -1,73 +1,14 @@
 // @flow
 
 import { StringType, BooleanType, CollatorType } from '../types';
+import Collator from '../types/collator';
 
 import type { Expression } from '../expression';
 import type EvaluationContext from '../evaluation_context';
 import type ParsingContext from '../parsing_context';
 import type { Type } from '../types';
 
-// Flow type declarations for Intl cribbed from
-// https://github.com/facebook/flow/issues/1270
-
-declare var Intl: {
-  Collator: Class<Intl$Collator>
-}
-
-declare class Intl$Collator {
-  constructor (
-    locales?: string | string[],
-    options?: CollatorOptions
-  ): Intl$Collator;
-
-  static (
-    locales?: string | string[],
-    options?: CollatorOptions
-  ): Intl$Collator;
-
-  compare (a: string, b: string): number;
-
-  resolvedOptions(): any;
-}
-
-type CollatorOptions = {
-  localeMatcher?: 'lookup' | 'best fit',
-  usage?: 'sort' | 'search',
-  sensitivity?: 'base' | 'accent' | 'case' | 'variant',
-  ignorePunctuation?: boolean,
-  numeric?: boolean,
-  caseFirst?: 'upper' | 'lower' | 'false'
-}
-
-export class Collator {
-    locale: string | null;
-    sensitivity: 'base' | 'accent' | 'case' | 'variant';
-    collator: Intl$Collator;
-
-    constructor(caseSensitive: boolean, diacriticSensitive: boolean, locale: string | null) {
-        if (caseSensitive)
-            this.sensitivity = diacriticSensitive ? 'variant' : 'case';
-        else
-            this.sensitivity = diacriticSensitive ? 'accent' : 'base';
-
-        this.locale = locale;
-        this.collator = new Intl.Collator(this.locale ? this.locale : [],
-            { sensitivity: this.sensitivity, usage: 'search' });
-    }
-
-    compare(lhs: string, rhs: string): number {
-        return this.collator.compare(lhs, rhs);
-    }
-
-    resolvedLocale(): string {
-        // We create a Collator without "usage: search" because we don't want
-        // the search options encoded in our result (e.g. "en-u-co-search")
-        return new Intl.Collator(this.locale ? this.locale : [])
-            .resolvedOptions().locale;
-    }
-}
-
-export class CollatorExpression implements Expression {
+export default class CollatorExpression implements Expression {
     type: Type;
     caseSensitive: Expression;
     diacriticSensitive: Expression;
diff --git a/src/style-spec/expression/definitions/formatted.js b/src/style-spec/expression/definitions/format.js
similarity index 77%
rename from src/style-spec/expression/definitions/formatted.js
rename to src/style-spec/expression/definitions/format.js
index ef4a74b86c3..071c2110b4c 100644
--- a/src/style-spec/expression/definitions/formatted.js
+++ b/src/style-spec/expression/definitions/format.js
@@ -1,6 +1,7 @@
 // @flow
 
 import { NumberType, ValueType, FormattedType, array, StringType } from '../types';
+import Formatted, { FormattedSection } from '../types/formatted';
 import { toString } from '../values';
 
 import type { Expression } from '../expression';
@@ -8,49 +9,13 @@ import type EvaluationContext from '../evaluation_context';
 import type ParsingContext from '../parsing_context';
 import type { Type } from '../types';
 
-export class FormattedSection {
-    text: string
-    scale: number | null
-    fontStack: string | null
-
-    constructor(text: string, scale: number | null, fontStack: string | null) {
-        this.text = text;
-        this.scale = scale;
-        this.fontStack = fontStack;
-    }
-}
-
-export class Formatted {
-    sections: Array<FormattedSection>
-
-    constructor(sections: Array<FormattedSection>) {
-        this.sections = sections;
-    }
-
-    toString(): string {
-        return this.sections.map(section => section.text).join('');
-    }
-
-    serialize() {
-        const serialized = ["format"];
-        for (const section of this.sections) {
-            serialized.push(section.text);
-            const fontStack = section.fontStack ?
-                ["literal", section.fontStack.split(',')] :
-                null;
-            serialized.push({ "text-font": fontStack, "font-scale": section.scale });
-        }
-        return serialized;
-    }
-}
-
 type FormattedSectionExpression = {
     text: Expression,
     scale: Expression | null;
     font: Expression | null;
 }
 
-export class FormatExpression implements Expression {
+export default class FormatExpression implements Expression {
     type: Type;
     sections: Array<FormattedSectionExpression>;
 
diff --git a/src/style-spec/expression/definitions/index.js b/src/style-spec/expression/definitions/index.js
index 107249f40ce..da07b7bc9bd 100644
--- a/src/style-spec/expression/definitions/index.js
+++ b/src/style-spec/expression/definitions/index.js
@@ -36,8 +36,8 @@ import {
     LessThanOrEqual,
     GreaterThanOrEqual
 } from './comparison';
-import { CollatorExpression } from './collator';
-import { FormatExpression } from './formatted';
+import CollatorExpression from './collator';
+import FormatExpression from './format';
 import Length from './length';
 
 import type { Varargs } from '../compound_expression';
diff --git a/src/style-spec/expression/definitions/literal.js b/src/style-spec/expression/definitions/literal.js
index 2c8668d0e52..015a4cac93d 100644
--- a/src/style-spec/expression/definitions/literal.js
+++ b/src/style-spec/expression/definitions/literal.js
@@ -2,7 +2,7 @@
 
 import assert from 'assert';
 import { isValue, typeOf, Color } from '../values';
-import { Formatted } from './formatted';
+import Formatted from '../types/formatted';
 
 import type { Type } from '../types';
 import type { Value }  from '../values';
diff --git a/src/style-spec/expression/parsing_context.js b/src/style-spec/expression/parsing_context.js
index 646c2a39da2..b12de8a1002 100644
--- a/src/style-spec/expression/parsing_context.js
+++ b/src/style-spec/expression/parsing_context.js
@@ -9,14 +9,14 @@ import Assertion from './definitions/assertion';
 import Coercion from './definitions/coercion';
 import EvaluationContext from './evaluation_context';
 import CompoundExpression from './compound_expression';
-import { CollatorExpression } from './definitions/collator';
+import CollatorExpression from './definitions/collator';
+import FormatExpression from './definitions/format';
 import {isGlobalPropertyConstant, isFeatureConstant} from './is_constant';
 import Var from './definitions/var';
 
 
 import type {Expression, ExpressionRegistry} from './expression';
 import type {Type} from './types';
-import {FormatExpression} from './definitions/formatted';
 
 /**
  * State associated parsing at a given point in an expression tree.
diff --git a/src/style-spec/expression/types/collator.js b/src/style-spec/expression/types/collator.js
new file mode 100644
index 00000000000..40e80ec3214
--- /dev/null
+++ b/src/style-spec/expression/types/collator.js
@@ -0,0 +1,61 @@
+// @flow
+
+// Flow type declarations for Intl cribbed from
+// https://github.com/facebook/flow/issues/1270
+
+declare var Intl: {
+    Collator: Class<Intl$Collator>
+};
+
+declare class Intl$Collator {
+    constructor (
+        locales?: string | string[],
+        options?: CollatorOptions
+    ): Intl$Collator;
+
+    static (
+        locales?: string | string[],
+        options?: CollatorOptions
+    ): Intl$Collator;
+
+    compare (a: string, b: string): number;
+
+    resolvedOptions(): any;
+}
+
+type CollatorOptions = {
+    localeMatcher?: 'lookup' | 'best fit',
+    usage?: 'sort' | 'search',
+    sensitivity?: 'base' | 'accent' | 'case' | 'variant',
+    ignorePunctuation?: boolean,
+    numeric?: boolean,
+    caseFirst?: 'upper' | 'lower' | 'false'
+}
+
+export default class Collator {
+    locale: string | null;
+    sensitivity: 'base' | 'accent' | 'case' | 'variant';
+    collator: Intl$Collator;
+
+    constructor(caseSensitive: boolean, diacriticSensitive: boolean, locale: string | null) {
+        if (caseSensitive)
+            this.sensitivity = diacriticSensitive ? 'variant' : 'case';
+        else
+            this.sensitivity = diacriticSensitive ? 'accent' : 'base';
+
+        this.locale = locale;
+        this.collator = new Intl.Collator(this.locale ? this.locale : [],
+            { sensitivity: this.sensitivity, usage: 'search' });
+    }
+
+    compare(lhs: string, rhs: string): number {
+        return this.collator.compare(lhs, rhs);
+    }
+
+    resolvedLocale(): string {
+        // We create a Collator without "usage: search" because we don't want
+        // the search options encoded in our result (e.g. "en-u-co-search")
+        return new Intl.Collator(this.locale ? this.locale : [])
+            .resolvedOptions().locale;
+    }
+}
diff --git a/src/style-spec/expression/types/formatted.js b/src/style-spec/expression/types/formatted.js
new file mode 100644
index 00000000000..7637e2717cf
--- /dev/null
+++ b/src/style-spec/expression/types/formatted.js
@@ -0,0 +1,37 @@
+// @flow
+
+export class FormattedSection {
+    text: string;
+    scale: number | null;
+    fontStack: string | null;
+
+    constructor(text: string, scale: number | null, fontStack: string | null) {
+        this.text = text;
+        this.scale = scale;
+        this.fontStack = fontStack;
+    }
+}
+
+export default class Formatted {
+    sections: Array<FormattedSection>;
+
+    constructor(sections: Array<FormattedSection>) {
+        this.sections = sections;
+    }
+
+    toString(): string {
+        return this.sections.map(section => section.text).join('');
+    }
+
+    serialize() {
+        const serialized = ["format"];
+        for (const section of this.sections) {
+            serialized.push(section.text);
+            const fontStack = section.fontStack ?
+                ["literal", section.fontStack.split(',')] :
+                null;
+            serialized.push({ "text-font": fontStack, "font-scale": section.scale });
+        }
+        return serialized;
+    }
+}
diff --git a/src/style-spec/expression/values.js b/src/style-spec/expression/values.js
index 80e1d99dffa..3f8b5c874c2 100644
--- a/src/style-spec/expression/values.js
+++ b/src/style-spec/expression/values.js
@@ -3,9 +3,9 @@
 import assert from 'assert';
 
 import Color from '../util/color';
-import { Collator } from './definitions/collator';
-import { Formatted } from './definitions/formatted';
-import { NullType, NumberType, StringType, BooleanType, ColorType, ObjectType, ValueType, CollatorType, array } from './types';
+import Collator from './types/collator';
+import Formatted from './types/formatted';
+import { NullType, NumberType, StringType, BooleanType, ColorType, ObjectType, ValueType, CollatorType, FormattedType, array } from './types';
 
 import type { Type } from './types';
 
@@ -28,7 +28,7 @@ export function validateRGBA(r: mixed, g: mixed, b: mixed, a?: mixed): ?string {
     return null;
 }
 
-export type Value = null | string | boolean | number | Color | Collator | $ReadOnlyArray<Value> | { +[string]: Value }
+export type Value = null | string | boolean | number | Color | Collator | Formatted | $ReadOnlyArray<Value> | { +[string]: Value }
 
 export function isValue(mixed: mixed): boolean {
     if (mixed === null) {
@@ -43,6 +43,8 @@ export function isValue(mixed: mixed): boolean {
         return true;
     } else if (mixed instanceof Collator) {
         return true;
+    } else if (mixed instanceof Formatted) {
+        return true;
     } else if (Array.isArray(mixed)) {
         for (const item of mixed) {
             if (!isValue(item)) {
@@ -75,6 +77,8 @@ export function typeOf(value: Value): Type {
         return ColorType;
     } else if (value instanceof Collator) {
         return CollatorType;
+    } else if (value instanceof Formatted) {
+        return FormattedType;
     } else if (Array.isArray(value)) {
         const length = value.length;
         let itemType: ?Type;
diff --git a/src/style/style_layer/background_style_layer_properties.js b/src/style/style_layer/background_style_layer_properties.js
index 64644162963..c4c9b36ab37 100644
--- a/src/style/style_layer/background_style_layer_properties.js
+++ b/src/style/style_layer/background_style_layer_properties.js
@@ -15,7 +15,7 @@ import {
 
 import type Color from '../../style-spec/util/color';
 
-import type {Formatted} from '../../style-spec/expression/definitions/formatted';
+import type Formatted from '../../style-spec/expression/types/formatted';
 
 
 export type PaintProps = {|
diff --git a/src/style/style_layer/circle_style_layer_properties.js b/src/style/style_layer/circle_style_layer_properties.js
index cfa515be11a..65ea36aeb18 100644
--- a/src/style/style_layer/circle_style_layer_properties.js
+++ b/src/style/style_layer/circle_style_layer_properties.js
@@ -15,7 +15,7 @@ import {
 
 import type Color from '../../style-spec/util/color';
 
-import type {Formatted} from '../../style-spec/expression/definitions/formatted';
+import type Formatted from '../../style-spec/expression/types/formatted';
 
 
 export type PaintProps = {|
diff --git a/src/style/style_layer/fill_extrusion_style_layer_properties.js b/src/style/style_layer/fill_extrusion_style_layer_properties.js
index fbfd2a08f5c..c8e27695110 100644
--- a/src/style/style_layer/fill_extrusion_style_layer_properties.js
+++ b/src/style/style_layer/fill_extrusion_style_layer_properties.js
@@ -15,7 +15,7 @@ import {
 
 import type Color from '../../style-spec/util/color';
 
-import type {Formatted} from '../../style-spec/expression/definitions/formatted';
+import type Formatted from '../../style-spec/expression/types/formatted';
 
 
 export type PaintProps = {|
diff --git a/src/style/style_layer/fill_style_layer_properties.js b/src/style/style_layer/fill_style_layer_properties.js
index c321dede0d8..d0173c989b3 100644
--- a/src/style/style_layer/fill_style_layer_properties.js
+++ b/src/style/style_layer/fill_style_layer_properties.js
@@ -15,7 +15,7 @@ import {
 
 import type Color from '../../style-spec/util/color';
 
-import type {Formatted} from '../../style-spec/expression/definitions/formatted';
+import type Formatted from '../../style-spec/expression/types/formatted';
 
 
 export type PaintProps = {|
diff --git a/src/style/style_layer/heatmap_style_layer_properties.js b/src/style/style_layer/heatmap_style_layer_properties.js
index a2cc3bacdca..76b6079e550 100644
--- a/src/style/style_layer/heatmap_style_layer_properties.js
+++ b/src/style/style_layer/heatmap_style_layer_properties.js
@@ -15,7 +15,7 @@ import {
 
 import type Color from '../../style-spec/util/color';
 
-import type {Formatted} from '../../style-spec/expression/definitions/formatted';
+import type Formatted from '../../style-spec/expression/types/formatted';
 
 
 export type PaintProps = {|
diff --git a/src/style/style_layer/hillshade_style_layer_properties.js b/src/style/style_layer/hillshade_style_layer_properties.js
index 0c7b96f850d..39d94286ad8 100644
--- a/src/style/style_layer/hillshade_style_layer_properties.js
+++ b/src/style/style_layer/hillshade_style_layer_properties.js
@@ -15,7 +15,7 @@ import {
 
 import type Color from '../../style-spec/util/color';
 
-import type {Formatted} from '../../style-spec/expression/definitions/formatted';
+import type Formatted from '../../style-spec/expression/types/formatted';
 
 
 export type PaintProps = {|
diff --git a/src/style/style_layer/layer_properties.js.ejs b/src/style/style_layer/layer_properties.js.ejs
index a916e899726..573538879dc 100644
--- a/src/style/style_layer/layer_properties.js.ejs
+++ b/src/style/style_layer/layer_properties.js.ejs
@@ -20,7 +20,7 @@ import {
 
 import type Color from '../../style-spec/util/color';
 
-import type {Formatted} from '../../style-spec/expression/definitions/formatted';
+import type Formatted from '../../style-spec/expression/types/formatted';
 
 <% if (layoutProperties.length) { -%>
 export type LayoutProps = {|
diff --git a/src/style/style_layer/line_style_layer_properties.js b/src/style/style_layer/line_style_layer_properties.js
index 468b937ecc0..a9fb955ef94 100644
--- a/src/style/style_layer/line_style_layer_properties.js
+++ b/src/style/style_layer/line_style_layer_properties.js
@@ -15,7 +15,7 @@ import {
 
 import type Color from '../../style-spec/util/color';
 
-import type {Formatted} from '../../style-spec/expression/definitions/formatted';
+import type Formatted from '../../style-spec/expression/types/formatted';
 
 export type LayoutProps = {|
     "line-cap": DataConstantProperty<"butt" | "round" | "square">,
diff --git a/src/style/style_layer/raster_style_layer_properties.js b/src/style/style_layer/raster_style_layer_properties.js
index 97d46906570..b813a73459c 100644
--- a/src/style/style_layer/raster_style_layer_properties.js
+++ b/src/style/style_layer/raster_style_layer_properties.js
@@ -15,7 +15,7 @@ import {
 
 import type Color from '../../style-spec/util/color';
 
-import type {Formatted} from '../../style-spec/expression/definitions/formatted';
+import type Formatted from '../../style-spec/expression/types/formatted';
 
 
 export type PaintProps = {|
diff --git a/src/style/style_layer/symbol_style_layer_properties.js b/src/style/style_layer/symbol_style_layer_properties.js
index adf350a093e..9a1c4a64109 100644
--- a/src/style/style_layer/symbol_style_layer_properties.js
+++ b/src/style/style_layer/symbol_style_layer_properties.js
@@ -15,13 +15,13 @@ import {
 
 import type Color from '../../style-spec/util/color';
 
-import type {Formatted} from '../../style-spec/expression/definitions/formatted';
+import type Formatted from '../../style-spec/expression/types/formatted';
 
 export type LayoutProps = {|
     "symbol-placement": DataConstantProperty<"point" | "line" | "line-center">,
     "symbol-spacing": DataConstantProperty<number>,
     "symbol-avoid-edges": DataConstantProperty<boolean>,
-    "symbol-z-order": DataConstantProperty<boolean>,
+    "symbol-z-order": DataConstantProperty<"viewport-y" | "source">,
     "icon-allow-overlap": DataConstantProperty<boolean>,
     "icon-ignore-placement": DataConstantProperty<boolean>,
     "icon-optional": DataConstantProperty<boolean>,
diff --git a/src/symbol/mergelines.js b/src/symbol/mergelines.js
index 3468cf74f30..a3bde56367f 100644
--- a/src/symbol/mergelines.js
+++ b/src/symbol/mergelines.js
@@ -1,7 +1,7 @@
 // @flow
 
 import type {SymbolFeature} from '../data/bucket/symbol_bucket';
-import {Formatted} from '../style-spec/expression/definitions/formatted';
+import Formatted from '../style-spec/expression/types/formatted';
 
 export default function (features: Array<SymbolFeature>): Array<SymbolFeature> {
     const leftIndex: {[string]: number} = {};
diff --git a/src/symbol/shaping.js b/src/symbol/shaping.js
index fc6036fed9d..b1e7e1f26aa 100644
--- a/src/symbol/shaping.js
+++ b/src/symbol/shaping.js
@@ -9,7 +9,7 @@ import { plugin as rtlTextPlugin } from '../source/rtl_text_plugin';
 
 import type {StyleGlyph} from '../style/style_glyph';
 import type {ImagePosition} from '../render/image_atlas';
-import {Formatted} from '../style-spec/expression/definitions/formatted';
+import Formatted from '../style-spec/expression/types/formatted';
 
 const WritingMode = {
     horizontal: 1,
diff --git a/src/symbol/symbol_layout.js b/src/symbol/symbol_layout.js
index 8aef10f1228..91f10722cab 100644
--- a/src/symbol/symbol_layout.js
+++ b/src/symbol/symbol_layout.js
@@ -17,7 +17,7 @@ import classifyRings from '../util/classify_rings';
 import EXTENT from '../data/extent';
 import SymbolBucket from '../data/bucket/symbol_bucket';
 import EvaluationParameters from '../style/evaluation_parameters';
-import {Formatted} from '../style-spec/expression/definitions/formatted';
+import Formatted from '../style-spec/expression/types/formatted';
 import {SIZE_PACK_FACTOR} from './symbol_size';
 
 import type {Shaping, PositionedIcon} from './shaping';
diff --git a/src/symbol/transform_text.js b/src/symbol/transform_text.js
index e7058086c90..b2904d9fcc9 100644
--- a/src/symbol/transform_text.js
+++ b/src/symbol/transform_text.js
@@ -4,7 +4,7 @@ import { plugin as rtlTextPlugin } from '../source/rtl_text_plugin';
 
 import type SymbolStyleLayer from '../style/style_layer/symbol_style_layer';
 import type {Feature} from '../style-spec/expression';
-import {Formatted} from '../style-spec/expression/definitions/formatted';
+import Formatted from '../style-spec/expression/types/formatted';
 
 function transformText(text: string, layer: SymbolStyleLayer, feature: Feature) {
     const transform = layer.layout.get('text-transform').evaluate(feature, {});