|
1 | | -/** |
| 1 | +/* |
2 | 2 | * Copyright (C) NIWA & British Crown (Met Office) & Contributors. |
3 | 3 | * |
4 | 4 | * This program is free software: you can redistribute it and/or modify |
@@ -123,6 +123,8 @@ const RELATIVE_ID = new RegExp(` |
123 | 123 |
|
124 | 124 | /* eslint-enable */ |
125 | 125 |
|
| 126 | +const JOB_ID = /^(\d+|NN)$/ |
| 127 | + |
126 | 128 | function detokenise (tokens, workflow = true, relative = true) { |
127 | 129 | let parts = [] |
128 | 130 | let ret = '' |
@@ -159,7 +161,7 @@ function detokenise (tokens, workflow = true, relative = true) { |
159 | 161 | return ret |
160 | 162 | } |
161 | 163 |
|
162 | | -class Tokens { |
| 164 | +export class Tokens { |
163 | 165 | /* Represents a Cylc UID. |
164 | 166 | * |
165 | 167 | * Provides the interfaces for parsing to and from string IDs. |
@@ -262,19 +264,29 @@ class Tokens { |
262 | 264 | this.job = undefined |
263 | 265 | } |
264 | 266 |
|
| 267 | + if (this.job && !JOB_ID.test(this.job)) { |
| 268 | + throw new Error(`Invalid job ID: ${this.job}`) |
| 269 | + } |
| 270 | + |
265 | 271 | this.workflowID = detokenise(this, true, false) |
266 | 272 | this.relativeID = detokenise(this, false, true) |
267 | 273 | } |
268 | 274 |
|
269 | 275 | set (fields) { |
270 | | - for (const [key, value] of Object.entries(fields)) { |
271 | | - if (Tokens.KEYS.indexOf(key) === -1) { |
272 | | - throw new Error(`Invalid key: ${key}`) |
| 276 | + if (fields instanceof Tokens) { |
| 277 | + for (const key of Tokens.KEYS) { |
| 278 | + if (fields[key]) this[key] = fields[key] |
273 | 279 | } |
274 | | - if (typeof value !== 'string' && typeof value !== 'undefined') { |
275 | | - throw new Error(`Invalid type for value: ${value}`) |
| 280 | + } else { |
| 281 | + for (const [key, value] of Object.entries(fields)) { |
| 282 | + if (!Tokens.KEYS.includes(key)) { |
| 283 | + throw new Error(`Invalid key: ${key}`) |
| 284 | + } |
| 285 | + if (typeof value !== 'string' && value != null) { |
| 286 | + throw new Error(`Invalid type for value: ${value}`) |
| 287 | + } |
| 288 | + this[key] = value ?? undefined |
276 | 289 | } |
277 | | - this[key] = value |
278 | 290 | } |
279 | 291 | this.compute() |
280 | 292 | } |
@@ -360,6 +372,19 @@ class Tokens { |
360 | 372 | } |
361 | 373 | return ret |
362 | 374 | } |
363 | | -} |
364 | 375 |
|
365 | | -export { Tokens } |
| 376 | + /** |
| 377 | + * Validate an ID string without throwing an error. |
| 378 | + * |
| 379 | + * @param {string} id |
| 380 | + * @returns {string=} Error message if invalid, otherwise nothing. |
| 381 | + */ |
| 382 | + static validate (id, relative = false) { |
| 383 | + try { |
| 384 | + // eslint-disable-next-line no-new |
| 385 | + new Tokens(id, relative) |
| 386 | + } catch (e) { |
| 387 | + return e.message |
| 388 | + } |
| 389 | + } |
| 390 | +} |
0 commit comments