/**
* Provides utitly methods for data sets
*
* @module josm/ds
*/
/* global Java */
import * as util from 'josm/util'
import { NodeBuilder, WayBuilder, RelationBuilder } from 'josm/builder'
export const DataSet = Java.type('org.openstreetmap.josm.data.osm.DataSet')
const SimplePrimitiveId = Java.type('org.openstreetmap.josm.data.osm.SimplePrimitiveId')
const PrimitiveId = Java.type('org.openstreetmap.josm.data.osm.PrimitiveId')
export const OsmPrimitiveType = Java.type('org.openstreetmap.josm.data.osm.OsmPrimitiveType')
const Collection = Java.type('java.util.Collection')
const HashSet = Java.type('java.util.HashSet')
const File = Java.type('java.io.File')
const FileWriter = Java.type('java.io.FileWriter')
const PrintWriter = Java.type('java.io.PrintWriter')
const FileInputStream = Java.type('java.io.FileInputStream')
const OsmImporter = Java.type('org.openstreetmap.josm.gui.io.importexport.OsmImporter')
const OsmChangeImporter = Java.type('org.openstreetmap.josm.gui.io.importexport.OsmChangeImporter')
const OsmReader = Java.type('org.openstreetmap.josm.io.OsmReader')
const OsmChangeReader = Java.type('org.openstreetmap.josm.io.OsmChangeReader')
const Utils = Java.type('org.openstreetmap.josm.tools.Utils')
const GZIPInputStream = Java.type('java.util.zip.GZIPInputStream')
const OsmWriterFactory = Java.type('org.openstreetmap.josm.io.OsmWriterFactory')
const Changeset = Java.type('org.openstreetmap.josm.data.osm.Changeset')
const System = Java.type('java.lang.System')
function log (msg) {
System.out.println(msg)
}
function normalizeType (type) {
if (util.isString(type)) {
type = type.trim().toLowerCase()
if ('node'.startsWith(type)) {
return OsmPrimitiveType.NODE
} else if ('way'.startsWith(type)) {
return OsmPrimitiveType.WAY
} else if ('relation'.startsWith(type)) {
return OsmPrimitiveType.RELATION
} else {
util.assert(false,
'expected type as string, i.e. "node", "way", or "relation", got "{0}"',
type)
}
} else if (type instanceof OsmPrimitiveType) {
return type
} else {
util.assert(false, 'expected String or OsmPrimitiveType, got "{0}", type')
}
}
function normalizeId (id) {
if (util.isNumber(id)) {
if (Number.isInteger(id)) {
return id
} else {
util.assert(false, 'expected integer , got "{0}"', id)
}
} else if (util.isString(id)) {
const idSaved = id
id = parseInt(id.trim())
if (isNaN(id)) {
util.assert(false, 'expected integer as string, got "{0}"', idSaved)
}
} else {
util.assert(false, 'expected an integer or a string, got "{0}"', id)
}
}
/**
* Creates an ID for an OSM primitive.
*
* <strong>Signatures</strong>
* <dl>
* <dt><code class="signature">buildId(id, type)</code></dt>
* <dd class="param-desc">Replies an object given by its unique numeric id and a type.
* The type is either a string <code>node</code>, <code>way</code>, or
* <code>relation</code>, or one of the symbols
* {@class org.openstreetmap.josm.data.osm.OsmPrimitiveType}.NODE,
* {@class org.openstreetmap.josm.data.osm.OsmPrimitiveType}.WAY, or
* {@class org.openstreetmap.josm.data.osm.OsmPrimitiveType}.RELATION.</dd>
*
* <dt><code class="signature">buildId(id)</code></dt>
* <dd class="param-desc">Replies an object given an ID. <code>id</code> is either an instance
* of
* {@class org.openstreetmap.josm.data.osm.PrimitiveId} or an object with
* the properties <code>id</code> and <code>type</code>, i.e.
* <code>{id: 1234, type: 'node'}</code>.</dd>
* </dl>
*
* @example
* import { buildId, OsmPrimitiveType} from 'josm/ds'
*
* // build a node id
* const id1 = buildId(1234, 'node')
*
* // build a way id
* const id2 = buildId(3333, OsmPrimitiveType.WAY)
*
* // build a relation id
* const id3 = buildId({id: 5423, type: 'relation'})
*
*
* @param args see description
*/
export function buildId (id, type) {
function buildId2 (id, type) {
id = normalizeId(id)
type = normalizeType(type)
if (id === 0) {
util.assert(false, 'expected id != 0, got 0')
}
return new SimplePrimitiveId(id, type)
}
function buildId1 (id) {
if (id instanceof PrimitiveId) {
return id
}
if (util.hasProp(id, 'id') && util.hasProp(id, 'type')) {
return buildId2(id.id, id.type)
}
util.assert(false, 'expected PrimitiveId or {id: ..., type: ...}, got "{0}"', id)
}
util.assert(arguments.length > 0, 'expected at least 1 argument, got 0')
switch (arguments.length) {
case 1:
return buildId1(...arguments)
case 2:
return buildId2(...arguments)
default:
util.assert(false, 'expected 1 or 2 arguments, got {0}', arguments.length)
}
}
function each (collection, delegate) {
if (util.isArray(collection) || util.isArguments(collection)) {
for (let i = 0; i < collection.length; i++) {
delegate(collection[i])
}
} else if (collection instanceof Collection) {
for (let it = collection.iterator(); it.hasNext();) {
delegate(it.next())
}
} else {
util.assert(false, 'Expected list or collection, got {0}', collection)
}
}
function collect (collection, predicate) {
const ret = []
each(collection, (obj) => {
if (predicate(obj)) ret.push(obj)
})
return ret
}
function isCollection (collection) {
return util.isArray(collection) ||
util.isArguments(collection) ||
collection instanceof Collection
}
function normalizeIds () {
function walk (set, ids) {
if (util.isNothing(ids)) return
if (ids instanceof PrimitiveId) {
set.add(ids)
} else if (isCollection(ids)) {
each(ids, (that) => walk(set, that))
} else {
util.assert(false,
'PrimitiveId or collection required, got {0}', ids)
}
}
const set = new HashSet()
for (let i = 0; i < arguments.length; i++) {
walk(set, arguments[i])
}
return set
}
/**
* <code>DataSetUtil</code> provides methods to build OSM primitive IDs and to
* manipulate data in a {@class org.openstreetmap.josm.data.osm.DataSet}.
*
*/
export class DataSetUtil {
/**
* Creates an instance of <code>DataSetUtil</code> for a given {@class org.openstreetmap.josm.data.osm.DataSet}
*
* @example
* import { DataSetUtil, DataSet } from 'josm/ds'
* const dsutil = new DataSetUtil(new DataSet())
*
* @summary Build an utility object wrapping the dataset <code>ds</code>
* @param {org.openstreetmap.josm.data.osm.DataSet} [ds] the dataset. Creates a new dataset if missing
*/
constructor (ds) {
ds = ds || new DataSet()
this.ds = ds
}
/**
* Replies an OSM object from the dataset, or undefined, if no such object
* exists.
*
* <strong>Signatures</strong>
* <dl>
* <dt><code class="signature">get(id, type)</code></dt>
* <dd class="param-desc">Replies an object given by its unique numeric id and a type.
* The type is either a string "node", "way", or "relation", or one of
* the symbols
* {@class org.openstreetmap.josm.data.osm.OsmPrimitiveType}.NODE,
* {@class org.openstreetmap.josm.data.osm.OsmPrimitiveType}.WAY, or
* {@class org.openstreetmap.josm.data.osm.OsmPrimitiveType}.RELATION.</dd>
*
* <dt><code class="signature">get(id)</code></dt>
* <dd class="param-desc">Replies an object given an ID. <code>id</code> is either an instance
* of
* {@class org.openstreetmap.josm.data.osm.PrimitiveId} or an object with
* the properties <code>id</code> and <code>type</code>, i.e.
* <code>{id: 1234, type: "node"}</code>.</dd>
* </dl>
*
* @example
* import { buildId , DataSetUtil, DataSet, OsmPrimitiveType} from 'josm/ds'
*
* const dsutil = new DataSetUtil(new DataSet())
* // get a node
* const n1 = dsutil.get(1234, 'node')
*
* // get a way
* const w1 = dsutil.get(3333, OsmPrimitiveType.WAY)
*
* // get a relation
* const r1 = dsutil.get({id: 5423, type: 'relation'})
*
* // pass in a SimplePrimitiveId
* const id = buildId(-5, OsmPrimitiveType.NODE)
* const n2 = dsutil.get(id)
*
* // pass in a primitive to get it
* const w2 = dsutil.wayBuilder().create(987)
* const w3 = dsutil.get(w2)
*
* @param args see description
*/
get () {
const id = buildId(...arguments)
return this.ds.getPrimitiveById(id)
}
/**
* Replies the node with id <code>id</code>, or null.
*
* @example
* import { DataSet, DataSetUtil } from 'josm/ds'
*
* const dsutil = new DataSetUtil(new DataSet())
* // get a node
* const n = dsutil.node(1234)
*
* @param {number} id the unique numeric id. Must not be 0.
* @returns {org.openstreetmap.josm.data.osm.Node} the node
*/
node (id) {
util.assert(util.isSomething(id), 'expected defined id, got "{0}"', id)
return this.get(id, 'node')
}
/**
* Replies the way with id <code>id</code>, or null
*
* @example
* import { DataSet, DataSetUtil } from 'josm/ds'
*
* const dsutil = new DataSetUtil(new DataSet())
* // get a way
* const w = dsutil.way(1234)
* @param {number} id the unique numeric id. Must not be 0.
* @returns {org.openstreetmap.josm.data.osm.Way} the way
*/
way (id) {
util.assert(util.isSomething(id), 'expected defined id, got "{0}"', id)
return this.get(id, 'way')
}
/**
* Replies the relation with id <code>id</code>.
*
* @example
* import { DataSet, DataSetUtil } from 'josm/ds'
*
* const dsutil = new DataSetUtil(new DataSet())
* // get a relation
* const r = dsutil.relation(1234)
*
* @param {number} id the unique numeric id. Must not be 0.
* @returns {org.openstreetmap.josm.data.osm.Relation} the relation
*/
relation (id) {
util.assert(util.isSomething(id), 'expected defined id, got "{0}"', id)
return this.get(id, 'relation')
}
/**
* Run a sequence of operations against the dataset in "batch mode".
*
* Listeners to data set events are only notified at the end of the batch.
*
* @example
* import { DataSet, DataSetUtil } from 'josm/ds'
* const dsutil = new DataSetUtil(new DataSet())
* // creates and adds two nodes and a way in batch operation
* // to the dataset
* dsutil.batch(() => {
* const n1 = dsutil.nodeBuilder().create()
* const n2 = dsutil.nodeBuilder().create()
* dsutil.wayBuilder().withNodes(n1,n2).create()
* })
*
* @param {function} delegate the function implementing the batch process.
* Ignored if null or undefined.
*/
batch (delegate) {
if (!(util.isSomething(delegate))) {
return
}
util.assert(util.isFunction(delegate), 'expected a function, got "{0}"',
delegate)
this.ds.beginUpdate()
try {
delegate()
} finally {
this.ds.endUpdate()
}
}
/**
* Removes objects from the dataset
*
* <strong>Signatures</strong>
* <dl>
* <dt><code class="signature">remove(id, type)</code></dt>
* <dd class="param-desc">Removes a single object given by its unique numeric ID (nid) and a
* type. The type is either a string "node", "way", or "relation", or one
* of the symbols
* {@class org.openstreetmap.josm.data.osm.OsmPrimitiveType}.NODE,
* {@class org.openstreetmap.josm.data.osm.OsmPrimitiveType}.WAY, or
* {@class org.openstreetmap.josm.data.osm.OsmPrimitiveType}.RELATION.</dd>
*
* <dt><code class="signature">remove(id, id, ...)</code></dt>
* <dd class="param-desc">Removes a collection of objects given by the ids. <code>id</code> is
* either an instance of
* {@class org.openstreetmap.josm.data.osm.PrimitiveId} or an object with
* the properties <code>id</code> and <code>type</code>, i.e.
* <code>{id: 1234, type: "node"}</code>.
* null and undefined are ignored.</dd>
*
* <dt><code class="signature">remove(array|collection)</code></dt>
* <dd class="param-desc">Removes a collection of objects given by the an array or a
* java.util.Collection of ids.
* The collection elemeents are either instances of
* {@class org.openstreetmap.josm.data.osm.PrimitiveId} or an object with
* the properties <code>id</code> and <code>type</code>, i.e.
* <code>{id: 1234, type: "node"}</code>.
* null or undefined elements are ignored.
* </dd>
* </dl>
*
* @example
* import { DataSet, DataSetUtil, OsmPrimitiveType, buildId} from 'josm/ds'
* const HashSet = Java.type('java.util.HashSet')
* const dsutil = new DataSetUtil(new DataSet())
*
* // remove a node with a global id
* dsutil.remove(1234, 'node')
*
* // remove a node and a way
* const id1 = buildId(1234, 'node')
* const id2 = buildId(3333, OsmPrimitiveType.WAY)
* dsutil.remove(id1, id2)
*
* // remove a relation and a node
* dsutil.remove({id: 1234, type: 'relation'}, id1)
*
* // remove an array of nodes
* dsutil.remove([id1,id2])
*
* // remove a set of primitives
* const ids = new HashSet()
* ids.add(id1)
* ids.add(id1)
* dsutil.remove(ids)
*
* @param args see description
*/
remove () {
// we have exactly two arguments, id and type. If we succeed
// to convert them to a primitive id, then we are done
if (arguments.length === 2) {
let id
try {
id = buildId(normalizeId(arguments[0]), normalizeType(arguments[1]))
} catch (e) {
id = null
}
if (id) {
this.ds.removePrimitive(id)
return
}
}
// we have a list of ids or collections of ids to remove.
// First build a flat list of the ids, then remove them
// in a batch operation from the dataset
const ids = normalizeIds(...arguments)
const ds = this.ds
this.batch(() => {
each(ids, (id) => {
ds.removePrimitive(id)
})
})
}
/**
* Replies a node builder to create {@class org.openstreetmap.josm.data.osm.Node}s in this dataset.
*
* @example
* import { DataSet, DataSetUtil } from 'josm/ds'
* const dsutil = new DataSetUtil(new DataSet())
* const n = dsutil.nodeBuilder
* .withId(1234,4567)
* .withTags({amenity: 'restaurant'})
* .create()
* dsutil.has(n)
*
* @property {module:josm/builder~NodeBuilder} nodeBuilder
* @readOnly
*/
get nodeBuilder () {
return NodeBuilder.forDataSet(this.ds)
}
/**
* Replies a way builder to create ways in this dataset.
*
* @example
* import { DataSet, DataSetUtil } from 'josm/ds'
*
* const dsutil = new DataSetUtil(new DataSet())
* const nb = dsutil.nodeBuilder()
* const w = dsutil.wayBuilder()
* .withNodes(nb.create(), nb.create())
* .create(1234, {tags: {highway: "residential"}})
* dsutil.has(w)
*
* @property {module:josm/builder~WayBuilder} wayBuilder
* @readOnly
*/
get wayBuilder () {
return WayBuilder.forDataSet(this.ds)
}
/**
* Replies a relation builder to create relations in this dataset.
*
* @example
* import { DataSet, DataSetUtil } from 'josm/ds'
*
* const dsutil = new DataSetUtil(new DataSet())
* const r = dsutil.relationBuilder()
* .withId(8765,1234)
* .create({tags: {type: 'network'}})
* ds.has(r) // --> true
*
* @property {module:josm/builder~RelationBuilder} relationBuilder
* @readOnly
*/
get relationBuilder () {
return RelationBuilder.forDataSet(this.ds)
}
/**
* Loads a dataset from a file.
* <p>
* Derives the format of the file from the file suffix, unless the named
* option <code>options.format</code> is set.
* <p>
* <code>options</code> can contain the following named options:
* <dl>
* <dt><code class="signature">format</code></dt>
* <dd class="param-desc">one of the strings <code>osm</code> (Open Street Map XML data),
* <code>osc</code> (Open Street Map change format), or
* <code>osm.gz</code> (Open Street Map XML data,
* compressed with gzip). The format is normalized: white space is removed and it is
* converted to lower case.</dd>
* </dl>
*
* @example
* import { DataSetUtil } from 'josm/ds'
*
* // loads an OSM file
* DataSetUtil.load('/path/to/my/file.osm')
*
* // loads an OSM file, explicity passing in the format
* DataSetUtil.load('/path/to/my/file.any-suffix', { format 'osm' })
*
* @param {string|java.io.File} source the data source
* @param {object} [options] optional named parameters
*
* @return {module:josm/ds~DataSetUtil} the data set util with the loaded data set
*/
static load (source, options) {
function normalizeFile (source) {
if (source instanceof File) {
return source
} else if (util.isString(source)) {
return new File(source)
} else {
util.assert(false,
'source: illegal value, expected string or File, got {0}',
source)
}
}
function normalizeFormat (source, options) {
const FORMATS = {
osm: true,
osc: true,
'osm.gz': true
}
if (util.isSomething(options.format)) {
// convert to string
const format = util.trim(options.format + '').toLowerCase()
if (FORMATS[format]) {
return format
}
util.assert(false,
`options.format: unknown format '${format}'`)
} else {
if (source.getPath().endsWith('.osm.gz')) {
return 'osm.gz'
}
if (new OsmImporter().acceptFile(source)) {
return 'osm'
}
if (new OsmChangeImporter().acceptFile(source)) {
return 'osc'
}
util.assert(false,
`Failed to derive format from file name. file is '${source}'`)
}
}
util.assert(util.isSomething(source),
'source: must not be null or undefined')
options = options || {}
source = normalizeFile(source)
const format = normalizeFormat(source, options)
log(`format: ${format}`)
let is
try {
switch (format) {
// load an OSM file
case 'osm': {
is = new FileInputStream(source)
const other = OsmReader.parseDataSet(is,
null /* null progress monitor */)
return new DataSetUtil(other)
}
// load an OSC file
case 'osc': {
is = new FileInputStream(source)
const other = OsmChangeReader.parseDataSet(is,
null /* null progress monitor */)
return new DataSetUtil(other)
}
// load a compressed OSM file
case 'osm.gz': {
is = new GZIPInputStream(new FileInputStream(source))
const other = OsmReader.parseDataSet(is,
null /* null progress monitor */)
return new DataSetUtil(other)
}
default:
util.assert(false,
`unknown format '${format}'. Failed to load from ${source}`)
}
} finally {
is && Utils.close(is)
}
}
/**
* Saves the dataset to a file (in OSM XML format).
* <p>
*
* <code>options</code> can contain the following named options:
* <dl>
* <dt><code class="signature">version</code>: string</dt>
* <dd class="param-desc">the value of the attribute <code>version</code> in the OSM file
* header. Default: "0.6"</dd>
*
* <dt><codeclass="signature">changeset</code>: Changeset</dt>
* <dd class="param-desc">the changeset whose id is included in the attribute
* <code>changeset</code> on every OSM object. If undefined, includes the
* individual <code>changeset</code> attribute of the OSM object.
* Default: undefined</dd>
* <dt><codeclass="signature">osmConform</code>: bool</dt>
* <dd class="param-desc">if true, prevents modification attributes to be written
* Default: true</dd>
* </dl>
*
* @example
* import { DataSetUtil } from 'josm/ds'
*
* const dsutil = new DataSetUtil()
* // create a node in the dataset
* dsutil.nodeBuilder()
* .withId(1, 1)
* .withPosition({ lat: 1.0, lon: 1.0 })
* .create()
*
* // save the dataset
* dsutil.save('/tmp/my-dataset.osm')
*
* @param {string|java.io.File} target the target file
* @param {object} [options] optional named parameters
* @instance
*/
save (target, options) {
function normalizeTarget (target) {
util.assert(util.isSomething(target),
'target: must not be null or undefined')
if (util.isString(target)) {
return new File(target)
} else if (target instanceof File) {
return target
} else {
util.assert(false,
'target: unexpected type of value, got {0}', target)
}
}
function normalizeOptions (options) {
options = options || {}
util.assert(
!util.isDef(options.version) || util.isString(options.version),
'options.version: expected a string, got {0}', options.version)
options.version = options.version
? util.trim(options.version)
: null /* default version */
/// true, if not explicity set to false
options.osmConform = options.osmConform !== false
const changeset = options.changeset
util.assert(
!util.isDef(changeset) || changeset instanceof Changeset,
'options.changeset: expected a changeset, got {0}', changeset)
return options
}
target = normalizeTarget(target)
options = normalizeOptions(options)
let pw
try {
pw = new PrintWriter(new FileWriter(target))
const writer = OsmWriterFactory.createOsmWriter(
pw,
options.osmConform,
options.version)
if (options.changeset) {
writer.setChangeset(options.changeset)
}
try {
this.ds.getReadLock().lock()
writer.header()
writer.writeContent(this.ds)
writer.footer()
} finally {
this.ds.getReadLock().unlock()
}
} finally {
pw && pw.close()
}
}
/**
* Queries the dataset
* <p>
* <strong>Signatures</strong>
* <dl>
* <dt><code class="signature">query(josmSearchExpression,?options)</code>
* </dt>
* <dd class="param-desc">Queries the dataset using the JOSM search expression
* <code>josmSearchExpression</code>.
* <code>josmSearchExpression</code> is a string as you would enter it in
* the JOSM search dialog. <code>options</code> is an (optional) object
* with named parameters, see below.</dd>
*
* <dt><code class="signature">query(predicate,?options)</code></dt>
* <dd class="param-desc">Queries the dataset using a javascript predicate function
* <code>predicate</code>. <code>predicate</code> is a javascript
* function which accepts a object as parameter and replies
* true, when it matches for the object ans false otherwise.
* <code>options</code> is an (optional) object with named parameters,
* see below.</dd>
* </dl>
*
* The parameter <code>options</code> consist of the following (optional)
* named parameters:
* <dl>
* <dt><code class="signature">allElements</code> : boolean
* (Deprecated parameter names:
* <code class="signature">all</code>)</dt>
* <dd class="param-desc">If true, searches <em>all</em> objects in the dataset. If false,
* ignores incomplete or deleted
* objects. Default: false.</dd>
*
* <dt><code class="signature">caseSensitive</code> : boolean</dt>
* <dd class="param-desc"><strong>Only applicable for searches with a JOSM search
* expression</strong>. If true, searches case sensitive. If false,
* searches case insensitive. Default: false.</dd>
*
* <dt><code class="signature">regexSearch</code> : boolean (Deprecated
* parameter names:
* <code class="signature">withRegexp</code>,
* <code class="signature">regexpSearch</code>)</dt>
* <dd class="param-desc"><strong>Only applicable for searches with a JOSM search
* expression</strong>. If true, the search expression contains regular
* expressions. If false, it includes only plain strings for searching.
* Default: false.</dd>
*
* <dt><code class="signature">mapCSSSearch</code></dt>
* <dd class="param-desc"><strong>Only applies for searches with a JOSM search
* expression</strong>.
* Default: false.</dd>
* </dl>
*
* @example
* import { DataSetUtil } from 'josm/ds'
* const dsutil = new DataSetUtil()
* // add or load primitives to query
* // ...
*
* // query restaurants
* const result1 = dsutil.query('amenity=restaurant')
*
* // query all nodes with a type query
* const result2 = dsutil.query('type:node')
*
* // query using a custom predicate - all primitives
* // with exactly two tags
* const result3 = dsutil.query((primitive) => {
* primitive.getKeys().size() === 2
* })
*
* @param {string|function} expression the match expression
* @param {object} [options] additional named parameters
* @instance
*/
query (expression, options) {
const SearchSetting = Java.type('org.openstreetmap.josm.data.osm.search.SearchSetting')
const SearchCompiler = Java.type('org.openstreetmap.josm.data.osm.search.SearchCompiler')
options = options || {}
switch (arguments.length) {
case 0: return []
case 1:
case 2:
if (util.isString(expression)) {
const ss = new SearchSetting()
ss.caseSensitive = Boolean(options.caseSensitive)
ss.regexSearch =
Boolean(options.regexSearch) ||
Boolean(options.regexpSearch) ||
Boolean(options.withRegexp)
ss.allElements =
Boolean(options.all) ||
Boolean(options.allElements)
ss.mapCSSSearch = Boolean(options.mapCSSSearch)
ss.text = expression
const matcher = SearchCompiler.compile(ss)
let predicate
if (ss.allElements) {
predicate = (matcher) => (obj) => {
return matcher.match(obj)
}
} else {
predicate = (matcher) => (obj) => {
return obj.isUsable() && matcher.match(obj)
}
}
return collect(this.ds.allPrimitives(), predicate(matcher))
} else if (util.isFunction(expression)) {
const all =
Boolean(options.all) ||
Boolean(options.allElements)
let predicate = expression
if (!all) {
predicate = (obj) => {
return obj.isUsable() && expression(obj)
}
}
return collect(this.ds.allPrimitives(), predicate)
} else {
util.assert(false,
'expression: Unexpected type of argument, got {0}',
arguments[0])
}
break
default:
util.assert(false,
'Expected a predicate, got {0} arguments', arguments.length)
}
}
}