@mapwhit/tilerenderer 0.47.2 → 0.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/build/min/package.json +1 -1
  2. package/package.json +3 -2
  3. package/src/data/array_types.js +169 -0
  4. package/src/data/bucket/symbol_attributes.js +18 -0
  5. package/src/data/bucket/symbol_bucket.js +116 -73
  6. package/src/data/program_configuration.js +18 -10
  7. package/src/geo/transform.js +17 -7
  8. package/src/index.js +1 -1
  9. package/src/render/glyph_atlas.js +3 -6
  10. package/src/render/image_atlas.js +3 -6
  11. package/src/render/image_manager.js +41 -41
  12. package/src/source/rtl_text_plugin.js +1 -0
  13. package/src/source/source_cache.js +1 -1
  14. package/src/source/tile.js +6 -5
  15. package/src/source/worker.js +1 -10
  16. package/src/style/style.js +4 -19
  17. package/src/style/style_layer/symbol_style_layer_properties.js +7 -1
  18. package/src/style-spec/expression/compound_expression.js +30 -16
  19. package/src/style-spec/expression/definitions/assertion.js +52 -5
  20. package/src/style-spec/expression/definitions/coercion.js +13 -0
  21. package/src/style-spec/expression/definitions/comparison.js +193 -0
  22. package/src/style-spec/expression/definitions/formatted.js +123 -0
  23. package/src/style-spec/expression/definitions/index.js +11 -62
  24. package/src/style-spec/expression/definitions/interpolate.js +17 -7
  25. package/src/style-spec/expression/definitions/literal.js +5 -0
  26. package/src/style-spec/expression/parsing_context.js +6 -7
  27. package/src/style-spec/expression/types.js +12 -1
  28. package/src/style-spec/feature_filter/convert.js +197 -0
  29. package/src/style-spec/feature_filter/index.js +5 -2
  30. package/src/style-spec/function/convert.js +78 -100
  31. package/src/style-spec/reference/v8.json +160 -52
  32. package/src/symbol/collision_index.js +0 -1
  33. package/src/symbol/cross_tile_symbol_index.js +12 -7
  34. package/src/symbol/get_anchors.js +11 -22
  35. package/src/symbol/mergelines.js +4 -1
  36. package/src/symbol/placement.js +58 -54
  37. package/src/symbol/quads.js +7 -6
  38. package/src/symbol/shaping.js +185 -40
  39. package/src/symbol/symbol_layout.js +40 -37
  40. package/src/symbol/transform_text.js +12 -1
  41. package/src/ui/map.js +8 -25
  42. package/src/style-spec/expression/definitions/array.js +0 -82
  43. package/src/style-spec/expression/definitions/equals.js +0 -93
@@ -0,0 +1,193 @@
1
+ const { toString, ValueType, BooleanType, CollatorType } = require('../types');
2
+ const Assertion = require('./assertion');
3
+ const { typeOf } = require('../values');
4
+ const RuntimeError = require('../runtime_error');
5
+
6
+ function isComparableType(op, type) {
7
+ if (op === '==' || op === '!=') {
8
+ // equality operator
9
+ return (
10
+ type.kind === 'boolean' ||
11
+ type.kind === 'string' ||
12
+ type.kind === 'number' ||
13
+ type.kind === 'null' ||
14
+ type.kind === 'value'
15
+ );
16
+ }
17
+ // ordering operator
18
+ return type.kind === 'string' || type.kind === 'number' || type.kind === 'value';
19
+ }
20
+
21
+ function eq(ctx, a, b) {
22
+ return a === b;
23
+ }
24
+ function neq(ctx, a, b) {
25
+ return a !== b;
26
+ }
27
+ function lt(ctx, a, b) {
28
+ return a < b;
29
+ }
30
+ function gt(ctx, a, b) {
31
+ return a > b;
32
+ }
33
+ function lteq(ctx, a, b) {
34
+ return a <= b;
35
+ }
36
+ function gteq(ctx, a, b) {
37
+ return a >= b;
38
+ }
39
+
40
+ function eqCollate(ctx, a, b, c) {
41
+ return c.compare(a, b) === 0;
42
+ }
43
+ function neqCollate(ctx, a, b, c) {
44
+ return !eqCollate(ctx, a, b, c);
45
+ }
46
+ function ltCollate(ctx, a, b, c) {
47
+ return c.compare(a, b) < 0;
48
+ }
49
+ function gtCollate(ctx, a, b, c) {
50
+ return c.compare(a, b) > 0;
51
+ }
52
+ function lteqCollate(ctx, a, b, c) {
53
+ return c.compare(a, b) <= 0;
54
+ }
55
+ function gteqCollate(ctx, a, b, c) {
56
+ return c.compare(a, b) >= 0;
57
+ }
58
+
59
+ /**
60
+ * Special form for comparison operators, implementing the signatures:
61
+ * - (T, T, ?Collator) => boolean
62
+ * - (T, value, ?Collator) => boolean
63
+ * - (value, T, ?Collator) => boolean
64
+ *
65
+ * For inequalities, T must be either value, string, or number. For ==/!=, it
66
+ * can also be boolean or null.
67
+ *
68
+ * Equality semantics are equivalent to Javascript's strict equality (===/!==)
69
+ * -- i.e., when the arguments' types don't match, == evaluates to false, != to
70
+ * true.
71
+ *
72
+ * When types don't match in an ordering comparison, a runtime error is thrown.
73
+ *
74
+ * @private
75
+ */
76
+ function makeComparison(op, compareBasic, compareWithCollator) {
77
+ const isOrderComparison = op !== '==' && op !== '!=';
78
+
79
+ return class Comparison {
80
+ constructor(lhs, rhs, collator) {
81
+ this.type = BooleanType;
82
+ this.lhs = lhs;
83
+ this.rhs = rhs;
84
+ this.collator = collator;
85
+ this.hasUntypedArgument = lhs.type.kind === 'value' || rhs.type.kind === 'value';
86
+ }
87
+
88
+ static parse(args, context) {
89
+ if (args.length !== 3 && args.length !== 4) return context.error('Expected two or three arguments.');
90
+
91
+ const op = args[0];
92
+
93
+ let lhs = context.parse(args[1], 1, ValueType);
94
+ if (!lhs) return null;
95
+ if (!isComparableType(op, lhs.type)) {
96
+ return context.concat(1).error(`"${op}" comparisons are not supported for type '${toString(lhs.type)}'.`);
97
+ }
98
+ let rhs = context.parse(args[2], 2, ValueType);
99
+ if (!rhs) return null;
100
+ if (!isComparableType(op, rhs.type)) {
101
+ return context.concat(2).error(`"${op}" comparisons are not supported for type '${toString(rhs.type)}'.`);
102
+ }
103
+
104
+ if (lhs.type.kind !== rhs.type.kind && lhs.type.kind !== 'value' && rhs.type.kind !== 'value') {
105
+ return context.error(`Cannot compare types '${toString(lhs.type)}' and '${toString(rhs.type)}'.`);
106
+ }
107
+
108
+ if (isOrderComparison) {
109
+ // typing rules specific to less/greater than operators
110
+ if (lhs.type.kind === 'value' && rhs.type.kind !== 'value') {
111
+ // (value, T)
112
+ lhs = new Assertion(rhs.type, [lhs]);
113
+ } else if (lhs.type.kind !== 'value' && rhs.type.kind === 'value') {
114
+ // (T, value)
115
+ rhs = new Assertion(lhs.type, [rhs]);
116
+ }
117
+ }
118
+
119
+ let collator = null;
120
+ if (args.length === 4) {
121
+ if (
122
+ lhs.type.kind !== 'string' &&
123
+ rhs.type.kind !== 'string' &&
124
+ lhs.type.kind !== 'value' &&
125
+ rhs.type.kind !== 'value'
126
+ ) {
127
+ return context.error('Cannot use collator to compare non-string types.');
128
+ }
129
+ collator = context.parse(args[3], 3, CollatorType);
130
+ if (!collator) return null;
131
+ }
132
+
133
+ return new Comparison(lhs, rhs, collator);
134
+ }
135
+
136
+ evaluate(ctx) {
137
+ const lhs = this.lhs.evaluate(ctx);
138
+ const rhs = this.rhs.evaluate(ctx);
139
+
140
+ if (isOrderComparison && this.hasUntypedArgument) {
141
+ const lt = typeOf(lhs);
142
+ const rt = typeOf(rhs);
143
+ // check that type is string or number, and equal
144
+ if (lt.kind !== rt.kind || !(lt.kind === 'string' || lt.kind === 'number')) {
145
+ throw new RuntimeError(
146
+ `Expected arguments for "${op}" to be (string, string) or (number, number), but found (${lt.kind}, ${rt.kind}) instead.`
147
+ );
148
+ }
149
+ }
150
+
151
+ if (this.collator && !isOrderComparison && this.hasUntypedArgument) {
152
+ const lt = typeOf(lhs);
153
+ const rt = typeOf(rhs);
154
+ if (lt.kind !== 'string' || rt.kind !== 'string') {
155
+ return compareBasic(ctx, lhs, rhs);
156
+ }
157
+ }
158
+
159
+ return this.collator
160
+ ? compareWithCollator(ctx, lhs, rhs, this.collator.evaluate(ctx))
161
+ : compareBasic(ctx, lhs, rhs);
162
+ }
163
+
164
+ eachChild(fn) {
165
+ fn(this.lhs);
166
+ fn(this.rhs);
167
+ if (this.collator) {
168
+ fn(this.collator);
169
+ }
170
+ }
171
+
172
+ possibleOutputs() {
173
+ return [true, false];
174
+ }
175
+
176
+ serialize() {
177
+ const serialized = [op];
178
+ this.eachChild(child => {
179
+ serialized.push(child.serialize());
180
+ });
181
+ return serialized;
182
+ }
183
+ };
184
+ }
185
+
186
+ module.exports = {
187
+ Equals: makeComparison('==', eq, eqCollate),
188
+ NotEquals: makeComparison('!=', neq, neqCollate),
189
+ LessThan: makeComparison('<', lt, ltCollate),
190
+ GreaterThan: makeComparison('>', gt, gtCollate),
191
+ LessThanOrEqual: makeComparison('<=', lteq, lteqCollate),
192
+ GreaterThanOrEqual: makeComparison('>=', gteq, gteqCollate)
193
+ };
@@ -0,0 +1,123 @@
1
+ const { NumberType, ValueType, FormattedType, array, StringType } = require('../types');
2
+
3
+ class FormattedSection {
4
+ constructor(text, scale, fontStack) {
5
+ this.text = text;
6
+ this.scale = scale;
7
+ this.fontStack = fontStack;
8
+ }
9
+ }
10
+
11
+ class Formatted {
12
+ constructor(sections) {
13
+ this.sections = sections;
14
+ }
15
+
16
+ toString() {
17
+ return this.sections.map(section => section.text).join('');
18
+ }
19
+
20
+ serialize() {
21
+ const serialized = ['format'];
22
+ for (const section of this.sections) {
23
+ serialized.push(section.text);
24
+ const fontStack = section.fontStack ? ['literal', section.fontStack.split(',')] : null;
25
+ serialized.push({ 'text-font': fontStack, 'font-scale': section.scale });
26
+ }
27
+ return serialized;
28
+ }
29
+ }
30
+
31
+ class FormatExpression {
32
+ constructor(sections) {
33
+ this.type = FormattedType;
34
+ this.sections = sections;
35
+ }
36
+
37
+ static parse(args, context) {
38
+ if (args.length < 3) {
39
+ return context.error('Expected at least two arguments.');
40
+ }
41
+
42
+ if ((args.length - 1) % 2 !== 0) {
43
+ return context.error('Expected an even number of arguments.');
44
+ }
45
+
46
+ const sections = [];
47
+ for (let i = 1; i < args.length - 1; i += 2) {
48
+ const text = context.parse(args[i], 1, ValueType);
49
+ if (!text) return null;
50
+ const kind = text.type.kind;
51
+ if (kind !== 'string' && kind !== 'value' && kind !== 'null')
52
+ return context.error("Formatted text type must be 'string', 'value', or 'null'.");
53
+
54
+ const options = args[i + 1];
55
+ if (typeof options !== 'object' || Array.isArray(options))
56
+ return context.error('Format options argument must be an object.');
57
+
58
+ let scale = null;
59
+ if (options['font-scale']) {
60
+ scale = context.parse(options['font-scale'], 1, NumberType);
61
+ if (!scale) return null;
62
+ }
63
+
64
+ let font = null;
65
+ if (options['text-font']) {
66
+ font = context.parse(options['text-font'], 1, array(StringType));
67
+ if (!font) return null;
68
+ }
69
+ sections.push({ text, scale, font });
70
+ }
71
+
72
+ return new FormatExpression(sections);
73
+ }
74
+
75
+ evaluate(ctx) {
76
+ return new Formatted(
77
+ this.sections.map(
78
+ section =>
79
+ new FormattedSection(
80
+ section.text.evaluate(ctx) || '',
81
+ section.scale ? section.scale.evaluate(ctx) : null,
82
+ section.font ? section.font.evaluate(ctx).join(',') : null
83
+ )
84
+ )
85
+ );
86
+ }
87
+
88
+ eachChild(fn) {
89
+ for (const section of this.sections) {
90
+ fn(section.text);
91
+ if (section.scale) {
92
+ fn(section.scale);
93
+ }
94
+ if (section.font) {
95
+ fn(section.font);
96
+ }
97
+ }
98
+ }
99
+
100
+ possibleOutputs() {
101
+ // Technically the combinatoric set of all children
102
+ // Usually, this.text will be undefined anyway
103
+ return [undefined];
104
+ }
105
+
106
+ serialize() {
107
+ const serialized = ['format'];
108
+ for (const section of this.sections) {
109
+ serialized.push(section.text.serialize());
110
+ const options = {};
111
+ if (section.scale) {
112
+ options['font-scale'] = section.scale.serialize();
113
+ }
114
+ if (section.font) {
115
+ options['text-font'] = section.font.serialize();
116
+ }
117
+ serialized.push(options);
118
+ }
119
+ return serialized;
120
+ }
121
+ }
122
+
123
+ module.exports = { Formatted, FormatExpression };
@@ -18,7 +18,6 @@ const Let = require('./let');
18
18
  const Var = require('./var');
19
19
  const Literal = require('./literal');
20
20
  const Assertion = require('./assertion');
21
- const ArrayAssertion = require('./array');
22
21
  const Coercion = require('./coercion');
23
22
  const At = require('./at');
24
23
  const Match = require('./match');
@@ -26,21 +25,29 @@ const Case = require('./case');
26
25
  const Step = require('./step');
27
26
  const Interpolate = require('./interpolate');
28
27
  const Coalesce = require('./coalesce');
29
- const { Equals, NotEquals } = require('./equals');
28
+ const { Equals, NotEquals, LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual } = require('./comparison');
30
29
  const { CollatorExpression } = require('./collator');
30
+ const { Formatted, FormatExpression } = require('./formatted');
31
31
  const Length = require('./length');
32
32
 
33
33
  const expressions = {
34
34
  // special forms
35
35
  '==': Equals,
36
36
  '!=': NotEquals,
37
- array: ArrayAssertion,
37
+ '>': GreaterThan,
38
+ '<': LessThan,
39
+ '>=': GreaterThanOrEqual,
40
+ '<=': LessThanOrEqual,
41
+ array: Assertion,
38
42
  at: At,
39
43
  boolean: Assertion,
40
44
  case: Case,
41
45
  coalesce: Coalesce,
42
46
  collator: CollatorExpression,
47
+ format: FormatExpression,
43
48
  interpolate: Interpolate,
49
+ 'interpolate-hcl': Interpolate,
50
+ 'interpolate-lab': Interpolate,
44
51
  length: Length,
45
52
  let: Let,
46
53
  literal: Literal,
@@ -73,32 +80,6 @@ function get(key, obj) {
73
80
  return typeof v === 'undefined' ? null : v;
74
81
  }
75
82
 
76
- function lt(ctx, [a, b]) {
77
- return a.evaluate(ctx) < b.evaluate(ctx);
78
- }
79
- function gt(ctx, [a, b]) {
80
- return a.evaluate(ctx) > b.evaluate(ctx);
81
- }
82
- function lteq(ctx, [a, b]) {
83
- return a.evaluate(ctx) <= b.evaluate(ctx);
84
- }
85
- function gteq(ctx, [a, b]) {
86
- return a.evaluate(ctx) >= b.evaluate(ctx);
87
- }
88
-
89
- function ltCollate(ctx, [a, b, c]) {
90
- return c.evaluate(ctx).compare(a.evaluate(ctx), b.evaluate(ctx)) < 0;
91
- }
92
- function gtCollate(ctx, [a, b, c]) {
93
- return c.evaluate(ctx).compare(a.evaluate(ctx), b.evaluate(ctx)) > 0;
94
- }
95
- function lteqCollate(ctx, [a, b, c]) {
96
- return c.evaluate(ctx).compare(a.evaluate(ctx), b.evaluate(ctx)) <= 0;
97
- }
98
- function gteqCollate(ctx, [a, b, c]) {
99
- return c.evaluate(ctx).compare(a.evaluate(ctx), b.evaluate(ctx)) >= 0;
100
- }
101
-
102
83
  function binarySearch(v, a, i, j) {
103
84
  while (i <= j) {
104
85
  const m = (i + j) >> 1;
@@ -134,7 +115,7 @@ CompoundExpression.register(expressions, {
134
115
  if (type === 'string' || type === 'number' || type === 'boolean') {
135
116
  return String(v);
136
117
  }
137
- if (v instanceof Color) {
118
+ if (v instanceof Color || v instanceof Formatted) {
138
119
  return v.toString();
139
120
  }
140
121
  return JSON.stringify(v);
@@ -323,38 +304,6 @@ CompoundExpression.register(expressions, {
323
304
  // assumes v is a array literal with values sorted in ascending order and of a single type
324
305
  (ctx, [k, v]) => binarySearch(ctx.properties()[k.value], v.value, 0, v.value.length - 1)
325
306
  ],
326
- '>': {
327
- type: BooleanType,
328
- overloads: [
329
- [[NumberType, NumberType], gt],
330
- [[StringType, StringType], gt],
331
- [[StringType, StringType, CollatorType], gtCollate]
332
- ]
333
- },
334
- '<': {
335
- type: BooleanType,
336
- overloads: [
337
- [[NumberType, NumberType], lt],
338
- [[StringType, StringType], lt],
339
- [[StringType, StringType, CollatorType], ltCollate]
340
- ]
341
- },
342
- '>=': {
343
- type: BooleanType,
344
- overloads: [
345
- [[NumberType, NumberType], gteq],
346
- [[StringType, StringType], gteq],
347
- [[StringType, StringType, CollatorType], gteqCollate]
348
- ]
349
- },
350
- '<=': {
351
- type: BooleanType,
352
- overloads: [
353
- [[NumberType, NumberType], lteq],
354
- [[StringType, StringType], lteq],
355
- [[StringType, StringType, CollatorType], lteqCollate]
356
- ]
357
- },
358
307
  all: {
359
308
  type: BooleanType,
360
309
  overloads: [
@@ -1,12 +1,14 @@
1
1
  const UnitBezier = require('@mapbox/unitbezier');
2
2
 
3
3
  const interpolate = require('../../util/interpolate');
4
- const { toString, NumberType } = require('../types');
4
+ const { toString, ColorType, NumberType } = require('../types');
5
5
  const { findStopLessThanOrEqualTo } = require('../stops');
6
+ const { hcl, lab } = require('../../util/color_spaces');
6
7
 
7
8
  class Interpolate {
8
- constructor(type, interpolation, input, stops) {
9
+ constructor(type, operator, interpolation, input, stops) {
9
10
  this.type = type;
11
+ this.operator = operator;
10
12
  this.interpolation = interpolation;
11
13
  this.input = input;
12
14
 
@@ -33,7 +35,7 @@ class Interpolate {
33
35
  }
34
36
 
35
37
  static parse(args, context) {
36
- let [, interpolation, input, ...rest] = args;
38
+ let [operator, interpolation, input, ...rest] = args;
37
39
 
38
40
  if (!Array.isArray(interpolation) || interpolation.length === 0) {
39
41
  return context.error('Expected an interpolation type expression.', 1);
@@ -79,7 +81,9 @@ class Interpolate {
79
81
  const stops = [];
80
82
 
81
83
  let outputType = null;
82
- if (context.expectedType && context.expectedType.kind !== 'value') {
84
+ if (operator === 'interpolate-hcl' || operator === 'interpolate-lab') {
85
+ outputType = ColorType;
86
+ } else if (context.expectedType && context.expectedType.kind !== 'value') {
83
87
  outputType = context.expectedType;
84
88
  }
85
89
 
@@ -118,7 +122,7 @@ class Interpolate {
118
122
  return context.error(`Type ${toString(outputType)} is not interpolatable.`);
119
123
  }
120
124
 
121
- return new Interpolate(outputType, interpolation, input, stops);
125
+ return new Interpolate(outputType, operator, interpolation, input, stops);
122
126
  }
123
127
 
124
128
  evaluate(ctx) {
@@ -147,7 +151,13 @@ class Interpolate {
147
151
  const outputLower = outputs[index].evaluate(ctx);
148
152
  const outputUpper = outputs[index + 1].evaluate(ctx);
149
153
 
150
- return interpolate[this.type.kind.toLowerCase()](outputLower, outputUpper, t);
154
+ if (this.operator === 'interpolate') {
155
+ return interpolate[this.type.kind.toLowerCase()](outputLower, outputUpper, t);
156
+ }
157
+ if (this.operator === 'interpolate-hcl') {
158
+ return hcl.reverse(hcl.interpolate(hcl.forward(outputLower), hcl.forward(outputUpper), t));
159
+ }
160
+ return lab.reverse(lab.interpolate(lab.forward(outputLower), lab.forward(outputUpper), t));
151
161
  }
152
162
 
153
163
  eachChild(fn) {
@@ -175,7 +185,7 @@ class Interpolate {
175
185
  interpolation = ['cubic-bezier'].concat(this.interpolation.controlPoints);
176
186
  }
177
187
 
178
- const serialized = ['interpolate', interpolation, this.input.serialize()];
188
+ const serialized = [this.operator, interpolation, this.input.serialize()];
179
189
 
180
190
  for (let i = 0; i < this.labels.length; i++) {
181
191
  serialized.push(this.labels[i], this.outputs[i].serialize());
@@ -1,5 +1,6 @@
1
1
  const assert = require('assert');
2
2
  const { isValue, typeOf, Color } = require('../values');
3
+ const { Formatted } = require('./formatted');
3
4
 
4
5
  class Literal {
5
6
  constructor(type, value) {
@@ -51,6 +52,10 @@ class Literal {
51
52
  // so we have to implement an equivalent serialization here
52
53
  return ['rgba'].concat(this.value.toArray());
53
54
  }
55
+ if (this.value instanceof Formatted) {
56
+ // Same as Color
57
+ return this.value.serialize();
58
+ }
54
59
  assert(
55
60
  this.value === null ||
56
61
  typeof this.value === 'string' ||
@@ -4,7 +4,6 @@ const { checkSubtype } = require('./types');
4
4
  const ParsingError = require('./parsing_error');
5
5
  const Literal = require('./definitions/literal');
6
6
  const Assertion = require('./definitions/assertion');
7
- const ArrayAssertion = require('./definitions/array');
8
7
  const Coercion = require('./definitions/coercion');
9
8
  const EvaluationContext = require('./evaluation_context');
10
9
  const { CollatorExpression } = require('./definitions/collator');
@@ -83,17 +82,18 @@ class ParsingContext {
83
82
  (expected.kind === 'string' ||
84
83
  expected.kind === 'number' ||
85
84
  expected.kind === 'boolean' ||
86
- expected.kind === 'object') &&
85
+ expected.kind === 'object' ||
86
+ expected.kind === 'array') &&
87
87
  actual.kind === 'value'
88
88
  ) {
89
89
  if (!options.omitTypeAnnotations) {
90
90
  parsed = new Assertion(expected, [parsed]);
91
91
  }
92
- } else if (expected.kind === 'array' && actual.kind === 'value') {
92
+ } else if (expected.kind === 'color' && (actual.kind === 'value' || actual.kind === 'string')) {
93
93
  if (!options.omitTypeAnnotations) {
94
- parsed = new ArrayAssertion(expected, parsed);
94
+ parsed = new Coercion(expected, [parsed]);
95
95
  }
96
- } else if (expected.kind === 'color' && (actual.kind === 'value' || actual.kind === 'string')) {
96
+ } else if (expected.kind === 'formatted' && (actual.kind === 'value' || actual.kind === 'string')) {
97
97
  if (!options.omitTypeAnnotations) {
98
98
  parsed = new Coercion(expected, [parsed]);
99
99
  }
@@ -184,8 +184,7 @@ function isConstant(expression) {
184
184
  return false;
185
185
  }
186
186
 
187
- const isTypeAnnotation =
188
- expression instanceof Coercion || expression instanceof Assertion || expression instanceof ArrayAssertion;
187
+ const isTypeAnnotation = expression instanceof Coercion || expression instanceof Assertion;
189
188
 
190
189
  let childrenConstant = true;
191
190
  expression.eachChild(child => {
@@ -7,6 +7,7 @@ const ObjectType = { kind: 'object' };
7
7
  const ValueType = { kind: 'value' };
8
8
  const ErrorType = { kind: 'error' };
9
9
  const CollatorType = { kind: 'collator' };
10
+ const FormattedType = { kind: 'formatted' };
10
11
 
11
12
  function array(itemType, N) {
12
13
  return {
@@ -28,7 +29,16 @@ function toString(type) {
28
29
  return type.kind;
29
30
  }
30
31
 
31
- const valueMemberTypes = [NullType, NumberType, StringType, BooleanType, ColorType, ObjectType, array(ValueType)];
32
+ const valueMemberTypes = [
33
+ NullType,
34
+ NumberType,
35
+ StringType,
36
+ BooleanType,
37
+ ColorType,
38
+ FormattedType,
39
+ ObjectType,
40
+ array(ValueType)
41
+ ];
32
42
 
33
43
  /**
34
44
  * Returns null if `t` is a subtype of `expected`; otherwise returns an
@@ -67,6 +77,7 @@ module.exports = {
67
77
  StringType,
68
78
  BooleanType,
69
79
  ColorType,
80
+ FormattedType,
70
81
  ObjectType,
71
82
  ValueType,
72
83
  ErrorType,