@mapbox/mapbox-gl-style-spec 14.2.0 → 14.3.0-beta.1

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.
package/dist/index.es.js CHANGED
@@ -865,6 +865,17 @@ var source_raster_array = {
865
865
  type: "*",
866
866
  doc: "Contains the description of the raster data layers and the bands contained within the tiles."
867
867
  },
868
+ volatile: {
869
+ type: "boolean",
870
+ "default": false,
871
+ doc: "A setting to determine whether a source's tiles are cached locally.",
872
+ "sdk-support": {
873
+ "basic functionality": {
874
+ android: "9.3.0",
875
+ ios: "5.10.0"
876
+ }
877
+ }
878
+ },
868
879
  "*": {
869
880
  type: "*",
870
881
  doc: "Other keys to configure the data source."
@@ -1116,6 +1127,17 @@ var layer = {
1116
1127
  }
1117
1128
  }
1118
1129
  },
1130
+ "raster-particle": {
1131
+ doc: "Particle animation driven by textures such as wind maps.",
1132
+ "sdk-support": {
1133
+ "basic functionality": {
1134
+ js: "0.10.0",
1135
+ android: "2.0.1",
1136
+ ios: "2.0.0",
1137
+ macos: "0.1.0"
1138
+ }
1139
+ }
1140
+ },
1119
1141
  hillshade: {
1120
1142
  doc: "Client-side hillshading visualization based on DEM data. Currently, the implementation only supports Mapbox Terrain RGB and Mapzen Terrarium tiles.",
1121
1143
  "sdk-support": {
@@ -1226,6 +1248,7 @@ var layout = [
1226
1248
  "layout_fill-extrusion",
1227
1249
  "layout_symbol",
1228
1250
  "layout_raster",
1251
+ "layout_raster-particle",
1229
1252
  "layout_hillshade",
1230
1253
  "layout_background",
1231
1254
  "layout_sky",
@@ -3582,7 +3605,7 @@ var expression_name = {
3582
3605
  }
3583
3606
  },
3584
3607
  image: {
3585
- doc: "Returns a [`ResolvedImage`](/mapbox-gl-js/style-spec/types/#resolvedimage) for use in [`icon-image`](/mapbox-gl-js/style-spec/layers/#layout-symbol-icon-image), `*-pattern` entries, and as a section in the [`'format'`](#types-format) expression. A [`'coalesce'`](#coalesce) expression containing `image` expressions will evaluate to the first listed image that is currently in the style. This validation process is synchronous and requires the image to have been added to the style before requesting it in the `'image'` argument.",
3608
+ doc: "Returns a [`ResolvedImage`](/mapbox-gl-js/style-spec/types/#resolvedimage) for use in [`icon-image`](/mapbox-gl-js/style-spec/layers/#layout-symbol-icon-image), `*-pattern` entries, and as a section in the [`'format'`](#types-format) expression. A [`'coalesce'`](#coalesce) expression containing `image` expressions will evaluate to the first listed image that is currently in the style. This validation process is synchronous and requires the image to have been added to the style before requesting it in the `'image'` argument. To implement crossfading between two images within a symbol layer using the [`icon-image-cross-fade`](/mapbox-gl-js/style-spec/layers/#paint-symbol-icon-image-cross-fade) attribute, include a second image as the second argument in the `'image'` expression.",
3586
3609
  group: "Types",
3587
3610
  "sdk-support": {
3588
3611
  "basic functionality": {
@@ -4326,6 +4349,17 @@ var expression_name = {
4326
4349
  }
4327
4350
  }
4328
4351
  },
4352
+ "raster-particle-speed": {
4353
+ doc: "Returns the length of the particle velocity vector. Can only be used in the `raster-particle-color` property.",
4354
+ group: "Raster Particle Animation",
4355
+ "sdk-support": {
4356
+ "basic functionality": {
4357
+ js: "3.3.0",
4358
+ android: "",
4359
+ ios: ""
4360
+ }
4361
+ }
4362
+ },
4329
4363
  random: {
4330
4364
  doc: "Returns a random value in the specified range (first two input numbers) based on a supplied seed (third input). The seed can be an expression or a constant number or string value.",
4331
4365
  group: "Math",
@@ -6325,6 +6359,9 @@ var paint_symbol = {
6325
6359
  "measure-light"
6326
6360
  ]
6327
6361
  },
6362
+ requires: [
6363
+ "icon-image"
6364
+ ],
6328
6365
  "sdk-support": {
6329
6366
  "basic functionality": {
6330
6367
  js: "3.0.0",
@@ -6902,7 +6939,7 @@ var paint_raster = {
6902
6939
  },
6903
6940
  "raster-elevation": {
6904
6941
  type: "number",
6905
- doc: "Specifies an uniform elevation from the ground, in meters. Only supported with image sources.",
6942
+ doc: "Specifies an uniform elevation from the ground, in meters.",
6906
6943
  "default": 0,
6907
6944
  minimum: 0,
6908
6945
  transition: true,
@@ -7976,6 +8013,37 @@ var v8 = {
7976
8013
  layout_line: layout_line,
7977
8014
  layout_symbol: layout_symbol,
7978
8015
  layout_raster: layout_raster,
8016
+ "layout_raster-particle": {
8017
+ visibility: {
8018
+ type: "enum",
8019
+ values: {
8020
+ visible: {
8021
+ doc: "The layer is shown."
8022
+ },
8023
+ none: {
8024
+ doc: "The layer is not shown."
8025
+ }
8026
+ },
8027
+ "default": "visible",
8028
+ doc: "Whether this layer is displayed.",
8029
+ "sdk-support": {
8030
+ "basic functionality": {
8031
+ js: "0.10.0",
8032
+ android: "2.0.1",
8033
+ ios: "2.0.0"
8034
+ },
8035
+ "expressions support": {
8036
+ js: "3.0.0",
8037
+ android: "11.0.0",
8038
+ ios: "11.0.0"
8039
+ }
8040
+ },
8041
+ expression: {
8042
+ interpolated: false
8043
+ },
8044
+ "property-type": "constant"
8045
+ }
8046
+ },
7979
8047
  layout_hillshade: layout_hillshade,
7980
8048
  filter: filter,
7981
8049
  filter_symbol: filter_symbol,
@@ -8642,6 +8710,134 @@ var v8 = {
8642
8710
  paint_heatmap: paint_heatmap,
8643
8711
  paint_symbol: paint_symbol,
8644
8712
  paint_raster: paint_raster,
8713
+ "paint_raster-particle": {
8714
+ "raster-particle-array-band": {
8715
+ type: "string",
8716
+ required: false,
8717
+ "property-type": "data-constant",
8718
+ transition: false,
8719
+ doc: "Displayed band of raster array source layer",
8720
+ example: "band-name",
8721
+ "sdk-support": {
8722
+ "basic functionality": {
8723
+ js: "",
8724
+ android: "",
8725
+ ios: ""
8726
+ }
8727
+ }
8728
+ },
8729
+ "raster-particle-count": {
8730
+ type: "number",
8731
+ doc: "Defines the amount of particles per tile.",
8732
+ "default": 512,
8733
+ minimum: 1,
8734
+ transition: false,
8735
+ "sdk-support": {
8736
+ "basic functionality": {
8737
+ js: "",
8738
+ android: "",
8739
+ ios: ""
8740
+ }
8741
+ },
8742
+ "property-type": "data-constant"
8743
+ },
8744
+ "raster-particle-color": {
8745
+ type: "color",
8746
+ doc: "Defines a color map by which to colorize a raster particle layer, parameterized by the `[\"raster-particle-speed\"]` expression and evaluated at 256 uniformly spaced steps over the range specified by `raster-particle-max-speed`.",
8747
+ transition: false,
8748
+ "sdk-support": {
8749
+ "basic functionality": {
8750
+ js: "",
8751
+ android: "",
8752
+ ios: ""
8753
+ },
8754
+ "data-driven styling": {
8755
+ }
8756
+ },
8757
+ expression: {
8758
+ interpolated: true,
8759
+ parameters: [
8760
+ "raster-particle-speed"
8761
+ ]
8762
+ },
8763
+ "property-type": "color-ramp"
8764
+ },
8765
+ "raster-particle-max-speed": {
8766
+ type: "number",
8767
+ doc: "Defines the maximum speed for particles. Velocities with magnitudes equal to or exceeding this value are clamped to the max value.",
8768
+ "default": 1,
8769
+ minimum: 1,
8770
+ transition: false,
8771
+ "sdk-support": {
8772
+ "basic functionality": {
8773
+ js: "",
8774
+ android: "",
8775
+ ios: ""
8776
+ }
8777
+ },
8778
+ "property-type": "data-constant"
8779
+ },
8780
+ "raster-particle-speed-factor": {
8781
+ type: "number",
8782
+ doc: "Defines a coefficient for the speed of particles’ motion.",
8783
+ "default": 0.2,
8784
+ minimum: 0,
8785
+ maximum: 1,
8786
+ transition: true,
8787
+ "sdk-support": {
8788
+ "basic functionality": {
8789
+ js: "",
8790
+ android: "",
8791
+ ios: ""
8792
+ }
8793
+ },
8794
+ expression: {
8795
+ interpolated: true,
8796
+ parameters: [
8797
+ "zoom"
8798
+ ]
8799
+ },
8800
+ "property-type": "data-constant"
8801
+ },
8802
+ "raster-particle-fade-opacity-factor": {
8803
+ type: "number",
8804
+ doc: "Defines defines the opacity coefficient applied to the faded particles in each frame. In practice, this property controls the length of the particle tail.",
8805
+ "default": 0.98,
8806
+ minimum: 0,
8807
+ maximum: 1,
8808
+ transition: true,
8809
+ "sdk-support": {
8810
+ "basic functionality": {
8811
+ js: "",
8812
+ android: "",
8813
+ ios: ""
8814
+ }
8815
+ },
8816
+ expression: {
8817
+ interpolated: true,
8818
+ parameters: [
8819
+ "zoom"
8820
+ ]
8821
+ },
8822
+ "property-type": "data-constant"
8823
+ },
8824
+ "raster-particle-reset-rate-factor": {
8825
+ type: "number",
8826
+ doc: "Defines a coefficient for a time period at which particles will restart at a random position, to avoid degeneration (empty areas without particles).",
8827
+ "default": 0.8,
8828
+ minimum: 0,
8829
+ maximum: 1,
8830
+ transition: false,
8831
+ "sdk-support": {
8832
+ "basic functionality": {
8833
+ js: "",
8834
+ android: "",
8835
+ ios: ""
8836
+ }
8837
+ },
8838
+ "property-type": "data-constant"
8839
+ }
8840
+ },
8645
8841
  paint_hillshade: paint_hillshade,
8646
8842
  paint_background: paint_background,
8647
8843
  paint_sky: paint_sky,
@@ -13239,6 +13435,125 @@ class Distance {
13239
13435
  }
13240
13436
  var Distance$1 = Distance;
13241
13437
 
13438
+ //
13439
+ function coerceValue(type, value) {
13440
+ switch (type) {
13441
+ case 'string':
13442
+ return toString(value);
13443
+ case 'number':
13444
+ return +value;
13445
+ case 'boolean':
13446
+ return !!value;
13447
+ case 'color':
13448
+ return Color$1.parse(value);
13449
+ case 'formatted': {
13450
+ return Formatted.fromString(toString(value));
13451
+ }
13452
+ case 'resolvedImage': {
13453
+ return ResolvedImage.fromString(toString(value));
13454
+ }
13455
+ }
13456
+ return value;
13457
+ }
13458
+ function clampToAllowedNumber(value, min, max, step) {
13459
+ if (step !== undefined) {
13460
+ value = step * Math.round(value / step);
13461
+ }
13462
+ if (min !== undefined && value < min) {
13463
+ value = min;
13464
+ }
13465
+ if (max !== undefined && value > max) {
13466
+ value = max;
13467
+ }
13468
+ return value;
13469
+ }
13470
+ class Config {
13471
+ constructor(type, key, scope) {
13472
+ this.type = type;
13473
+ this.key = key;
13474
+ this.scope = scope;
13475
+ }
13476
+ static parse(args, context) {
13477
+ let type = context.expectedType;
13478
+ if (type === null || type === undefined) {
13479
+ type = ValueType;
13480
+ }
13481
+ if (args.length < 2 || args.length > 3) {
13482
+ return context.error(`Invalid number of arguments for 'config' expression.`);
13483
+ }
13484
+ const configKey = context.parse(args[1], 1);
13485
+ if (!(configKey instanceof Literal$1)) {
13486
+ return context.error(`Key name of 'config' expression must be a string literal.`);
13487
+ }
13488
+ if (args.length >= 3) {
13489
+ const configScope = context.parse(args[2], 2);
13490
+ if (!(configScope instanceof Literal$1)) {
13491
+ return context.error(`Scope of 'config' expression must be a string literal.`);
13492
+ }
13493
+ return new Config(type, toString(configKey.value), toString(configScope.value));
13494
+ }
13495
+ return new Config(type, toString(configKey.value));
13496
+ }
13497
+ evaluate(ctx) {
13498
+ const FQIDSeparator = '\x1F';
13499
+ const configKey = [
13500
+ this.key,
13501
+ this.scope,
13502
+ ctx.scope
13503
+ ].filter(Boolean).join(FQIDSeparator);
13504
+ const config = ctx.getConfig(configKey);
13505
+ if (!config)
13506
+ return null;
13507
+ const {type, value, values, minValue, maxValue, stepValue} = config;
13508
+ const defaultValue = config.default.evaluate(ctx);
13509
+ let result = defaultValue;
13510
+ if (value) {
13511
+ // temporarily override scope to parent to evaluate config expressions passed from the parent
13512
+ const originalScope = ctx.scope;
13513
+ ctx.scope = (originalScope || '').split(FQIDSeparator).slice(1).join(FQIDSeparator);
13514
+ result = value.evaluate(ctx);
13515
+ ctx.scope = originalScope;
13516
+ }
13517
+ if (type) {
13518
+ result = coerceValue(type, result);
13519
+ }
13520
+ if (result !== undefined && (minValue !== undefined || maxValue !== undefined || stepValue !== undefined)) {
13521
+ if (typeof result === 'number') {
13522
+ result = clampToAllowedNumber(result, minValue, maxValue, stepValue);
13523
+ } else if (Array.isArray(result)) {
13524
+ result = result.map(item => typeof item === 'number' ? clampToAllowedNumber(item, minValue, maxValue, stepValue) : item);
13525
+ }
13526
+ }
13527
+ if (value !== undefined && result !== undefined && values && !values.includes(result)) {
13528
+ // The result is not among the allowed values. Instead, use the default value from the option.
13529
+ result = defaultValue;
13530
+ if (type) {
13531
+ result = coerceValue(type, result);
13532
+ }
13533
+ }
13534
+ if (type && type !== this.type || result !== undefined && typeOf(result) !== this.type) {
13535
+ result = coerceValue(this.type.kind, result);
13536
+ }
13537
+ return result;
13538
+ }
13539
+ eachChild() {
13540
+ }
13541
+ outputDefined() {
13542
+ return false;
13543
+ }
13544
+ serialize() {
13545
+ const res = [
13546
+ 'config',
13547
+ this.key
13548
+ ];
13549
+ if (this.scope) {
13550
+ res.concat(this.key);
13551
+ }
13552
+ return res;
13553
+ }
13554
+ }
13555
+ var Config$1 = Config;
13556
+
13242
13557
  //
13243
13558
  function isFeatureConstant(e) {
13244
13559
  if (e instanceof CompoundExpression$1) {
@@ -13283,10 +13598,8 @@ function isStateConstant(e) {
13283
13598
  return result;
13284
13599
  }
13285
13600
  function isConfigConstant(e) {
13286
- if (e instanceof CompoundExpression$1) {
13287
- if (e.name === 'config') {
13288
- return false;
13289
- }
13601
+ if (e instanceof Config$1) {
13602
+ return false;
13290
13603
  }
13291
13604
  let result = true;
13292
13605
  e.eachChild(arg => {
@@ -13488,8 +13801,6 @@ function isConstant(expression) {
13488
13801
  return isConstant(expression.boundExpression);
13489
13802
  } else if (expression instanceof CompoundExpression$1 && expression.name === 'error') {
13490
13803
  return false;
13491
- } else if (expression instanceof CompoundExpression$1 && expression.name === 'config') {
13492
- return false;
13493
13804
  } else if (expression instanceof CollatorExpression) {
13494
13805
  // Although the results of a Collator expression with fixed arguments
13495
13806
  // generally shouldn't change between executions, we can't serialize them
@@ -13499,6 +13810,8 @@ function isConstant(expression) {
13499
13810
  return false;
13500
13811
  } else if (expression instanceof Distance$1) {
13501
13812
  return false;
13813
+ } else if (expression instanceof Config$1) {
13814
+ return false;
13502
13815
  }
13503
13816
  const isTypeAnnotation = expression instanceof Coercion$1 || expression instanceof Assertion$1;
13504
13817
  let childrenConstant = true;
@@ -13528,7 +13841,8 @@ function isConstant(expression) {
13528
13841
  'is-supported-script',
13529
13842
  'pitch',
13530
13843
  'distance-from-center',
13531
- 'measure-light'
13844
+ 'measure-light',
13845
+ 'raster-particle-speed'
13532
13846
  ]);
13533
13847
  }
13534
13848
 
@@ -15012,7 +15326,9 @@ const expressions = {
15012
15326
  // $FlowFixMe[method-unbinding]
15013
15327
  'within': Within$1,
15014
15328
  // $FlowFixMe[method-unbinding]
15015
- 'distance': Distance$1
15329
+ 'distance': Distance$1,
15330
+ // $FlowFixMe[method-unbinding]
15331
+ 'config': Config$1
15016
15332
  };
15017
15333
  function rgba(ctx, [r, g, b, a]) {
15018
15334
  r = r.evaluate(ctx);
@@ -15045,69 +15361,6 @@ function get(key, obj) {
15045
15361
  const v = obj[key];
15046
15362
  return typeof v === 'undefined' ? null : v;
15047
15363
  }
15048
- function coerceValue(type, value) {
15049
- switch (type) {
15050
- case 'string':
15051
- return String(value);
15052
- case 'number':
15053
- return +value;
15054
- case 'boolean':
15055
- return !!value;
15056
- case 'color':
15057
- return Color$1.parse(value);
15058
- }
15059
- return value;
15060
- }
15061
- function clampToAllowedNumber(value, min, max, step) {
15062
- if (step !== undefined) {
15063
- value = step * Math.round(value / step);
15064
- }
15065
- if (min !== undefined && value < min) {
15066
- value = min;
15067
- }
15068
- if (max !== undefined && value > max) {
15069
- value = max;
15070
- }
15071
- return value;
15072
- }
15073
- const FQIDSeparator = '\x1F';
15074
- function getConfig(ctx, key, scope) {
15075
- // Create a fully qualified key from the requested scope
15076
- // and the scope from the current evaluation context
15077
- key = [
15078
- key,
15079
- scope,
15080
- ctx.scope
15081
- ].filter(Boolean).join(FQIDSeparator);
15082
- const config = ctx.getConfig(key);
15083
- if (!config)
15084
- return null;
15085
- const {type, value, values, minValue, maxValue, stepValue} = config;
15086
- const defaultValue = config.default.evaluate(ctx);
15087
- let result = defaultValue;
15088
- if (value) {
15089
- // temporarily override scope to parent to evaluate config expressions passed from the parent
15090
- const originalScope = ctx.scope;
15091
- ctx.scope = (originalScope || '').split(FQIDSeparator).slice(1).join(FQIDSeparator);
15092
- result = value.evaluate(ctx);
15093
- ctx.scope = originalScope;
15094
- }
15095
- if (type)
15096
- result = coerceValue(type, result);
15097
- if (value !== undefined && result !== undefined && values && !values.includes(result)) {
15098
- result = defaultValue;
15099
- if (type)
15100
- result = coerceValue(type, result);
15101
- }
15102
- if (result !== undefined && (minValue !== undefined || maxValue !== undefined || stepValue !== undefined)) {
15103
- if (typeof result === 'number') {
15104
- result = clampToAllowedNumber(result, minValue, maxValue, stepValue);
15105
- } else if (Array.isArray(result)) {
15106
- result = result.map(item => typeof item === 'number' ? clampToAllowedNumber(item, minValue, maxValue, stepValue) : item);
15107
- }
15108
- }
15109
- return result;
15110
- }
15111
15364
  function binarySearch(v, a, i, j) {
15112
15365
  while (i <= j) {
15113
15366
  const m = i + j >> 1;
@@ -15225,22 +15478,6 @@ CompoundExpression$1.register(expressions, {
15225
15478
  ]
15226
15479
  ]
15227
15480
  },
15228
- 'config': {
15229
- type: ValueType,
15230
- overloads: [
15231
- [
15232
- [StringType],
15233
- (ctx, [key]) => getConfig(ctx, key.evaluate(ctx))
15234
- ],
15235
- [
15236
- [
15237
- StringType,
15238
- StringType
15239
- ],
15240
- (ctx, [key, scope]) => getConfig(ctx, key.evaluate(ctx), scope.evaluate(ctx))
15241
- ]
15242
- ]
15243
- },
15244
15481
  'feature-state': [
15245
15482
  ValueType,
15246
15483
  [StringType],
@@ -15296,6 +15533,11 @@ CompoundExpression$1.register(expressions, {
15296
15533
  [],
15297
15534
  ctx => ctx.globals.rasterValue || 0
15298
15535
  ],
15536
+ 'raster-particle-speed': [
15537
+ NumberType,
15538
+ [],
15539
+ ctx => ctx.globals.rasterParticleSpeed || 0
15540
+ ],
15299
15541
  'sky-radial-progress': [
15300
15542
  NumberType,
15301
15543
  [],
@@ -17453,18 +17695,10 @@ const operations = {
17453
17695
  * { command: 'removeImport', args: [importId] }
17454
17696
  */
17455
17697
  removeImport: 'removeImport',
17456
- /*
17457
- * { command: 'setImportUrl', args: [importId, styleUrl] }
17458
- */
17459
- setImportUrl: 'setImportUrl',
17460
- /*
17461
- * { command: 'setImportData', args: [importId, stylesheet] }
17462
- */
17463
- setImportData: 'setImportData',
17464
- /*
17465
- * { command: 'setImportConfig', args: [importId, config] }
17698
+ /**
17699
+ * { command: 'updateImport', args: [importId, importSpecification | styleUrl] }
17466
17700
  */
17467
- setImportConfig: 'setImportConfig'
17701
+ updateImport: 'updateImport'
17468
17702
  };
17469
17703
  function addSource(sourceId, after, commands) {
17470
17704
  commands.push({
@@ -17795,35 +18029,13 @@ function diffImports(before = [], after = [], commands) {
17795
18029
  const beforeImport = beforeIndex[afterImport.id];
17796
18030
  if (!beforeImport || deepEqual(beforeImport, afterImport))
17797
18031
  continue;
17798
- if (!deepEqual(beforeImport.config, afterImport.config)) {
17799
- commands.push({
17800
- command: operations.setImportConfig,
17801
- args: [
17802
- afterImport.id,
17803
- afterImport.config
17804
- ]
17805
- });
17806
- }
17807
- if (!deepEqual(beforeImport.url, afterImport.url)) {
17808
- commands.push({
17809
- command: operations.setImportUrl,
17810
- args: [
17811
- afterImport.id,
17812
- afterImport.url
17813
- ]
17814
- });
17815
- }
17816
- const beforeData = beforeImport && beforeImport.data;
17817
- const afterData = afterImport.data;
17818
- if (!deepEqual(beforeData, afterData)) {
17819
- commands.push({
17820
- command: operations.setImportData,
17821
- args: [
17822
- afterImport.id,
17823
- afterData
17824
- ]
17825
- });
17826
- }
18032
+ commands.push({
18033
+ command: operations.updateImport,
18034
+ args: [
18035
+ afterImport.id,
18036
+ afterImport
18037
+ ]
18038
+ });
17827
18039
  }
17828
18040
  }
17829
18041
  /**
@@ -18680,8 +18892,15 @@ function validateLayer(options) {
18680
18892
  errors.push(new ValidationError(key, layer, `layer "${ layer.id }" must specify a "source-layer"`));
18681
18893
  } else if (sourceType === 'raster-dem' && type !== 'hillshade') {
18682
18894
  errors.push(new ValidationError(key, layer.source, 'raster-dem source can only be used with layer type \'hillshade\'.'));
18895
+ } else if (sourceType === 'raster-array' && ![
18896
+ 'raster',
18897
+ 'raster-particle'
18898
+ ].includes(type)) {
18899
+ errors.push(new ValidationError(key, layer.source, `raster-array source can only be used with layer type \'raster\'.`));
18683
18900
  } else if (type === 'line' && layer.paint && (layer.paint['line-gradient'] || layer.paint['line-trim-offset']) && (sourceType !== 'geojson' || !source.lineMetrics)) {
18684
18901
  errors.push(new ValidationError(key, layer, `layer "${ layer.id }" specifies a line-gradient, which requires a GeoJSON source with \`lineMetrics\` enabled.`));
18902
+ } else if (type === 'raster-particle' && sourceType !== 'raster-array') {
18903
+ errors.push(new ValidationError(key, layer.source, `layer "${ layer.id }" requires a \'raster-array\' source.`));
18685
18904
  }
18686
18905
  }
18687
18906
  }
@@ -18775,7 +18994,8 @@ function validateSource(options) {
18775
18994
  if ([
18776
18995
  'vector',
18777
18996
  'raster',
18778
- 'raster-dem'
18997
+ 'raster-dem',
18998
+ 'raster-array'
18779
18999
  ].includes(type)) {
18780
19000
  if (!value.url && !value.tiles) {
18781
19001
  errors.push(new ValidationWarning(key, value, 'Either "url" or "tiles" is required.'));
@@ -18785,6 +19005,7 @@ function validateSource(options) {
18785
19005
  case 'vector':
18786
19006
  case 'raster':
18787
19007
  case 'raster-dem':
19008
+ case 'raster-array':
18788
19009
  errors = errors.concat(validateObject({
18789
19010
  key,
18790
19011
  value,
@@ -20413,6 +20634,7 @@ const acceptedSourceTypes = new Set([
20413
20634
  'vector',
20414
20635
  'raster',
20415
20636
  'raster-dem',
20637
+ 'raster-array',
20416
20638
  'model',
20417
20639
  'batched-model'
20418
20640
  ]);
@@ -20429,7 +20651,7 @@ function getSourceErrors(source, i) {
20429
20651
  ];
20430
20652
  errors.push(...getAllowedKeyErrors(source, sourceKeys, 'source'));
20431
20653
  /*
20432
- * "type" is required and must be one of "vector", "raster", "raster-dem"
20654
+ * "type" is required and must be one of "vector", "raster", "raster-dem", "raster-array"
20433
20655
  */
20434
20656
  if (!acceptedSourceTypes.has(String(source.type))) {
20435
20657
  errors.push(new ValidationError(`sources[${ i }].type`, source.type, `Expected one of [${ Array.from(acceptedSourceTypes).join(', ') }]`));