@tpluscode/rdfine
Advanced tools
Comparing version 0.1.1 to 0.1.2
@@ -5,2 +5,15 @@ # Changelog | ||
### [0.1.2](https://github.com/tpluscode/rdfine/compare/v0.1.1...v0.1.2) (2020-01-09) | ||
### Features | ||
* read-only support for rdf lists ([1849150](https://github.com/tpluscode/rdfine/commit/1849150f659a62e125d351da9613ba815ab4f890)) | ||
### Bug Fixes | ||
* decorators fail to apply with babel ([dcd0ca0](https://github.com/tpluscode/rdfine/commit/dcd0ca0c9386d2ccc4ea03fc6d7b56aec0027fa3)) | ||
* strict property throws when initialized declaratively ([a7088ff](https://github.com/tpluscode/rdfine/commit/a7088ff33df3e6620374743adc0c6f06fc99124c)) | ||
### [0.1.1](https://github.com/tpluscode/rdfine/compare/v0.1.0...v0.1.1) (2020-01-08) | ||
@@ -7,0 +20,0 @@ |
import ns from '@rdfjs/namespace'; | ||
export function namespace(stringOrNamespace) { | ||
return (classOrDescriptor) => { | ||
classOrDescriptor.__ns = typeof stringOrNamespace === 'string' | ||
? ns(stringOrNamespace) : stringOrNamespace; | ||
function setNamespace(clazz, stringOrNamespace) { | ||
clazz.__ns = typeof stringOrNamespace === 'string' | ||
? ns(stringOrNamespace) : stringOrNamespace; | ||
} | ||
const legacyNamespace = (stringOrNamespace, clazz) => { | ||
setNamespace(clazz, stringOrNamespace); | ||
return clazz; | ||
}; | ||
const standardNamespace = (stringOrNamespace, descriptor) => { | ||
const { kind, elements } = descriptor; | ||
return { | ||
kind, | ||
elements, | ||
// This callback is called once the class is otherwise fully defined | ||
finisher(clazz) { | ||
setNamespace(clazz, stringOrNamespace); | ||
}, | ||
}; | ||
} | ||
}; | ||
export const namespace = (stringOrNamespace) => (classOrDescriptor) => (typeof classOrDescriptor === 'function') | ||
? legacyNamespace(stringOrNamespace, classOrDescriptor) | ||
: standardNamespace(stringOrNamespace, classOrDescriptor); |
import { getPath } from '../path'; | ||
import rdf from 'rdf-data-model'; | ||
import { xsd } from '../vocabs'; | ||
import { isList, enumerateList } from '../rdf-list'; | ||
function getNode(r, path) { | ||
@@ -10,52 +11,100 @@ return path | ||
} | ||
function propertyDecorator(options) { | ||
function createProperty(proto, name, options) { | ||
const { path, array, fromTerm, toTerm, assertSetValue, valueTypeName, initial, strict } = options; | ||
return (protoOrDescriptor, name) => { | ||
Object.defineProperty(protoOrDescriptor, name, { | ||
get() { | ||
const pathNodes = getPath(protoOrDescriptor, name, path); | ||
const node = getNode(this, pathNodes); | ||
const values = node.map(quad => { | ||
return fromTerm.call(this, quad); | ||
}); | ||
if (array === true) { | ||
return values; | ||
Object.defineProperty(proto, name, { | ||
get() { | ||
const pathNodes = getPath(proto, name, path); | ||
const node = getNode(this, pathNodes); | ||
const values = node.map((quad, index) => { | ||
if (isList(quad)) { | ||
if (index > 0) { | ||
throw new Error('Lists of lists are not supported'); | ||
} | ||
return enumerateList(this, quad, fromTerm.bind(this)); | ||
} | ||
if (values.length > 1) { | ||
throw new Error('Multiple terms found where 0..1 was expected'); | ||
return fromTerm.call(this, quad); | ||
}); | ||
if (array === true) { | ||
if (values.length === 1 && Array.isArray(values[0])) { | ||
return [...values[0]]; | ||
} | ||
if (strict && values.length === 0) { | ||
throw new Error(`Object not found for property ${name.toString()}`); | ||
return values; | ||
} | ||
if (values.length > 1) { | ||
throw new Error('Multiple terms found where 0..1 was expected'); | ||
} | ||
if (Array.isArray(values[0])) { | ||
throw new Error('RDF List found where 0..1 object was expected'); | ||
} | ||
if (this.__initialized && strict && values.length === 0) { | ||
throw new Error(`Object not found for property ${name}`); | ||
} | ||
return values[0]; | ||
}, | ||
set(value) { | ||
if (!array && Array.isArray(value)) { | ||
throw new Error('Cannot set array to a non-array property'); | ||
} | ||
const pathNodes = getPath(proto, name, path); | ||
const subject = pathNodes.length === 1 ? this._node : getNode(this, pathNodes.slice(0, pathNodes.length - 1)); | ||
const lastPredicate = pathNodes[pathNodes.length - 1]; | ||
subject.out(lastPredicate).forEach(obj => { | ||
if (isList(obj)) { | ||
throw new Error('Setting RDF Lists is not supported'); | ||
} | ||
return values[0]; | ||
}, | ||
set(value) { | ||
if (!array && Array.isArray(value)) { | ||
throw new Error('Cannot set array to a non-array property'); | ||
} | ||
const pathNodes = getPath(protoOrDescriptor, name, path); | ||
const subject = pathNodes.length === 1 ? this._node : getNode(this, pathNodes.slice(0, pathNodes.length - 1)); | ||
const lastPredicate = pathNodes[pathNodes.length - 1]; | ||
subject.deleteOut(lastPredicate); | ||
if (value === null || typeof value === 'undefined') { | ||
return; | ||
} | ||
if (!assertSetValue(value)) { | ||
const pathStr = pathNodes.map(p => `<${p}>`).join('/'); | ||
throw new Error(`Unexpected value for path ${pathStr}. Expecting a ${valueTypeName} or RDF/JS term`); | ||
} | ||
if (typeof value === 'object' && 'termType' in value) { | ||
subject.addOut(lastPredicate, value); | ||
return; | ||
} | ||
subject.addOut(lastPredicate, toTerm(value)); | ||
}, | ||
}); | ||
if (typeof initial !== 'undefined') { | ||
if (!Object.hasOwnProperty.call(protoOrDescriptor.constructor, '__defaults')) { | ||
protoOrDescriptor.constructor.__defaults = new Map(); | ||
}); | ||
subject.deleteOut(lastPredicate); | ||
if (value === null || typeof value === 'undefined') { | ||
return; | ||
} | ||
protoOrDescriptor.constructor.__defaults.set(name.toString(), initial); | ||
if (!assertSetValue(value)) { | ||
const pathStr = pathNodes.map(p => `<${p}>`).join('/'); | ||
throw new Error(`Unexpected value for path ${pathStr}. Expecting a ${valueTypeName} or RDF/JS term`); | ||
} | ||
if (typeof value === 'object' && 'termType' in value) { | ||
subject.addOut(lastPredicate, value); | ||
return; | ||
} | ||
subject.addOut(lastPredicate, toTerm(value)); | ||
}, | ||
}); | ||
if (typeof initial !== 'undefined') { | ||
if (!Object.hasOwnProperty.call(proto.constructor, '__defaults')) { | ||
proto.constructor.__defaults = new Map(); | ||
} | ||
proto.constructor.__defaults.set(name, initial); | ||
} | ||
} | ||
const legacyProperty = (options, proto, name) => { | ||
createProperty(proto, name.toString(), options); | ||
}; | ||
const standardProperty = (options, element) => { | ||
return { | ||
kind: 'field', | ||
key: Symbol(), | ||
placement: 'own', | ||
descriptor: {}, | ||
// When @babel/plugin-proposal-decorators implements initializers, | ||
// do this instead of the initializer below. See: | ||
// https://github.com/babel/babel/issues/9260 extras: [ | ||
// { | ||
// kind: 'initializer', | ||
// placement: 'own', | ||
// initializer: descriptor.initializer, | ||
// } | ||
// ], | ||
initializer() { | ||
if (typeof element.initializer === 'function') { | ||
this[element.key] = element.initializer.call(this); | ||
} | ||
}, | ||
finisher(clazz) { | ||
createProperty(clazz.prototype, element.key.toString(), options); | ||
}, | ||
}; | ||
}; | ||
function propertyDecorator(options) { | ||
return (protoOrDescriptor, name) => (name !== undefined) | ||
? legacyProperty(options, protoOrDescriptor, name) | ||
: standardProperty(options, protoOrDescriptor); | ||
} | ||
@@ -62,0 +111,0 @@ export function property(options = {}) { |
@@ -7,2 +7,3 @@ import cf from 'clownface'; | ||
constructor(node) { | ||
this.__initialized = false; | ||
let contexts; | ||
@@ -34,4 +35,5 @@ if ('_context' in node) { | ||
}); | ||
return true; | ||
}); | ||
this.__initializeProperties(); | ||
this.__initialized = this.__initializeProperties(); | ||
} | ||
@@ -38,0 +40,0 @@ get id() { |
@@ -7,8 +7,23 @@ "use strict"; | ||
const namespace_1 = __importDefault(require("@rdfjs/namespace")); | ||
function namespace(stringOrNamespace) { | ||
return (classOrDescriptor) => { | ||
classOrDescriptor.__ns = typeof stringOrNamespace === 'string' | ||
? namespace_1.default(stringOrNamespace) : stringOrNamespace; | ||
function setNamespace(clazz, stringOrNamespace) { | ||
clazz.__ns = typeof stringOrNamespace === 'string' | ||
? namespace_1.default(stringOrNamespace) : stringOrNamespace; | ||
} | ||
const legacyNamespace = (stringOrNamespace, clazz) => { | ||
setNamespace(clazz, stringOrNamespace); | ||
return clazz; | ||
}; | ||
const standardNamespace = (stringOrNamespace, descriptor) => { | ||
const { kind, elements } = descriptor; | ||
return { | ||
kind, | ||
elements, | ||
// This callback is called once the class is otherwise fully defined | ||
finisher(clazz) { | ||
setNamespace(clazz, stringOrNamespace); | ||
}, | ||
}; | ||
} | ||
exports.namespace = namespace; | ||
}; | ||
exports.namespace = (stringOrNamespace) => (classOrDescriptor) => (typeof classOrDescriptor === 'function') | ||
? legacyNamespace(stringOrNamespace, classOrDescriptor) | ||
: standardNamespace(stringOrNamespace, classOrDescriptor); |
@@ -9,2 +9,3 @@ "use strict"; | ||
const vocabs_1 = require("../vocabs"); | ||
const rdf_list_1 = require("../rdf-list"); | ||
function getNode(r, path) { | ||
@@ -16,52 +17,100 @@ return path | ||
} | ||
function propertyDecorator(options) { | ||
function createProperty(proto, name, options) { | ||
const { path, array, fromTerm, toTerm, assertSetValue, valueTypeName, initial, strict } = options; | ||
return (protoOrDescriptor, name) => { | ||
Object.defineProperty(protoOrDescriptor, name, { | ||
get() { | ||
const pathNodes = path_1.getPath(protoOrDescriptor, name, path); | ||
const node = getNode(this, pathNodes); | ||
const values = node.map(quad => { | ||
return fromTerm.call(this, quad); | ||
}); | ||
if (array === true) { | ||
return values; | ||
Object.defineProperty(proto, name, { | ||
get() { | ||
const pathNodes = path_1.getPath(proto, name, path); | ||
const node = getNode(this, pathNodes); | ||
const values = node.map((quad, index) => { | ||
if (rdf_list_1.isList(quad)) { | ||
if (index > 0) { | ||
throw new Error('Lists of lists are not supported'); | ||
} | ||
return rdf_list_1.enumerateList(this, quad, fromTerm.bind(this)); | ||
} | ||
if (values.length > 1) { | ||
throw new Error('Multiple terms found where 0..1 was expected'); | ||
return fromTerm.call(this, quad); | ||
}); | ||
if (array === true) { | ||
if (values.length === 1 && Array.isArray(values[0])) { | ||
return [...values[0]]; | ||
} | ||
if (strict && values.length === 0) { | ||
throw new Error(`Object not found for property ${name.toString()}`); | ||
return values; | ||
} | ||
if (values.length > 1) { | ||
throw new Error('Multiple terms found where 0..1 was expected'); | ||
} | ||
if (Array.isArray(values[0])) { | ||
throw new Error('RDF List found where 0..1 object was expected'); | ||
} | ||
if (this.__initialized && strict && values.length === 0) { | ||
throw new Error(`Object not found for property ${name}`); | ||
} | ||
return values[0]; | ||
}, | ||
set(value) { | ||
if (!array && Array.isArray(value)) { | ||
throw new Error('Cannot set array to a non-array property'); | ||
} | ||
const pathNodes = path_1.getPath(proto, name, path); | ||
const subject = pathNodes.length === 1 ? this._node : getNode(this, pathNodes.slice(0, pathNodes.length - 1)); | ||
const lastPredicate = pathNodes[pathNodes.length - 1]; | ||
subject.out(lastPredicate).forEach(obj => { | ||
if (rdf_list_1.isList(obj)) { | ||
throw new Error('Setting RDF Lists is not supported'); | ||
} | ||
return values[0]; | ||
}, | ||
set(value) { | ||
if (!array && Array.isArray(value)) { | ||
throw new Error('Cannot set array to a non-array property'); | ||
} | ||
const pathNodes = path_1.getPath(protoOrDescriptor, name, path); | ||
const subject = pathNodes.length === 1 ? this._node : getNode(this, pathNodes.slice(0, pathNodes.length - 1)); | ||
const lastPredicate = pathNodes[pathNodes.length - 1]; | ||
subject.deleteOut(lastPredicate); | ||
if (value === null || typeof value === 'undefined') { | ||
return; | ||
} | ||
if (!assertSetValue(value)) { | ||
const pathStr = pathNodes.map(p => `<${p}>`).join('/'); | ||
throw new Error(`Unexpected value for path ${pathStr}. Expecting a ${valueTypeName} or RDF/JS term`); | ||
} | ||
if (typeof value === 'object' && 'termType' in value) { | ||
subject.addOut(lastPredicate, value); | ||
return; | ||
} | ||
subject.addOut(lastPredicate, toTerm(value)); | ||
}, | ||
}); | ||
if (typeof initial !== 'undefined') { | ||
if (!Object.hasOwnProperty.call(protoOrDescriptor.constructor, '__defaults')) { | ||
protoOrDescriptor.constructor.__defaults = new Map(); | ||
}); | ||
subject.deleteOut(lastPredicate); | ||
if (value === null || typeof value === 'undefined') { | ||
return; | ||
} | ||
protoOrDescriptor.constructor.__defaults.set(name.toString(), initial); | ||
if (!assertSetValue(value)) { | ||
const pathStr = pathNodes.map(p => `<${p}>`).join('/'); | ||
throw new Error(`Unexpected value for path ${pathStr}. Expecting a ${valueTypeName} or RDF/JS term`); | ||
} | ||
if (typeof value === 'object' && 'termType' in value) { | ||
subject.addOut(lastPredicate, value); | ||
return; | ||
} | ||
subject.addOut(lastPredicate, toTerm(value)); | ||
}, | ||
}); | ||
if (typeof initial !== 'undefined') { | ||
if (!Object.hasOwnProperty.call(proto.constructor, '__defaults')) { | ||
proto.constructor.__defaults = new Map(); | ||
} | ||
proto.constructor.__defaults.set(name, initial); | ||
} | ||
} | ||
const legacyProperty = (options, proto, name) => { | ||
createProperty(proto, name.toString(), options); | ||
}; | ||
const standardProperty = (options, element) => { | ||
return { | ||
kind: 'field', | ||
key: Symbol(), | ||
placement: 'own', | ||
descriptor: {}, | ||
// When @babel/plugin-proposal-decorators implements initializers, | ||
// do this instead of the initializer below. See: | ||
// https://github.com/babel/babel/issues/9260 extras: [ | ||
// { | ||
// kind: 'initializer', | ||
// placement: 'own', | ||
// initializer: descriptor.initializer, | ||
// } | ||
// ], | ||
initializer() { | ||
if (typeof element.initializer === 'function') { | ||
this[element.key] = element.initializer.call(this); | ||
} | ||
}, | ||
finisher(clazz) { | ||
createProperty(clazz.prototype, element.key.toString(), options); | ||
}, | ||
}; | ||
}; | ||
function propertyDecorator(options) { | ||
return (protoOrDescriptor, name) => (name !== undefined) | ||
? legacyProperty(options, protoOrDescriptor, name) | ||
: standardProperty(options, protoOrDescriptor); | ||
} | ||
@@ -68,0 +117,0 @@ function property(options = {}) { |
@@ -12,2 +12,3 @@ "use strict"; | ||
constructor(node) { | ||
this.__initialized = false; | ||
let contexts; | ||
@@ -39,4 +40,5 @@ if ('_context' in node) { | ||
}); | ||
return true; | ||
}); | ||
this.__initializeProperties(); | ||
this.__initialized = this.__initializeProperties(); | ||
} | ||
@@ -43,0 +45,0 @@ get id() { |
/// <reference types="rdfjs__namespace" /> | ||
import { NamespaceBuilder } from '@rdfjs/namespace'; | ||
import ns from '@rdfjs/namespace'; | ||
import { RdfResource } from '../RdfResource'; | ||
import { ClassDescriptor } from '.'; | ||
declare type Constructor<T = RdfResource> = { | ||
@@ -8,4 +9,4 @@ new (...args: any[]): T; | ||
}; | ||
export declare function namespace(stringOrNamespace: string | NamespaceBuilder): <T extends RdfResource<import("rdf-js").DatasetCore<import("rdf-js").Quad>>>(classOrDescriptor: Constructor<T>) => void; | ||
export declare const namespace: (stringOrNamespace: string | ns.NamespaceBuilder) => (classOrDescriptor: ClassDescriptor | Constructor<RdfResource<import("rdf-js").DatasetCore<import("rdf-js").Quad>>>) => any; | ||
export {}; | ||
//# sourceMappingURL=namespace.d.ts.map |
import { BlankNode, Literal, NamedNode, Term } from 'rdf-js'; | ||
import RdfResource from '../RdfResource'; | ||
import { RdfResource } from '../RdfResource'; | ||
import { PropRef } from '../path'; | ||
import { Constructor, Mixin } from '../ResourceFactory'; | ||
import { ClassElement } from './index'; | ||
interface AccessorOptions { | ||
@@ -14,6 +15,6 @@ array?: boolean; | ||
} | ||
export declare function property<R extends RdfResource>(options?: AccessorOptions & TermOptions<R>): (protoOrDescriptor: any, name: string | number | symbol) => any; | ||
export declare function property<R extends RdfResource>(options?: AccessorOptions & TermOptions<R>): (protoOrDescriptor: RdfResource<import("rdf-js").DatasetCore<import("rdf-js").Quad>> | ClassElement, name?: string | number | symbol | undefined) => any; | ||
export declare namespace property { | ||
var literal: <R extends RdfResource<import("rdf-js").DatasetCore<import("rdf-js").Quad>>>(options?: AccessorOptions & LiteralOptions<R>) => (protoOrDescriptor: any, name: string | number | symbol) => any; | ||
var resource: <R extends RdfResource<import("rdf-js").DatasetCore<import("rdf-js").Quad>>>(options?: AccessorOptions & ResourceOptions<R>) => (protoOrDescriptor: any, name: string | number | symbol) => any; | ||
var literal: <R extends RdfResource<import("rdf-js").DatasetCore<import("rdf-js").Quad>>>(options?: AccessorOptions & LiteralOptions<R>) => (protoOrDescriptor: RdfResource<import("rdf-js").DatasetCore<import("rdf-js").Quad>> | ClassElement, name?: string | number | symbol | undefined) => any; | ||
var resource: <R extends RdfResource<import("rdf-js").DatasetCore<import("rdf-js").Quad>>>(options?: AccessorOptions & ResourceOptions<R>) => (protoOrDescriptor: RdfResource<import("rdf-js").DatasetCore<import("rdf-js").Quad>> | ClassElement, name?: string | number | symbol | undefined) => any; | ||
} | ||
@@ -20,0 +21,0 @@ interface LiteralOptions<R extends RdfResource> { |
@@ -13,2 +13,3 @@ import { NamedNode, DatasetCore, BlankNode } from 'rdf-js'; | ||
readonly _node: SingleContextClownface<D, NamedNode | BlankNode>; | ||
private readonly __initialized; | ||
private readonly __initializeProperties; | ||
@@ -15,0 +16,0 @@ static __ns?: any; |
{ | ||
"name": "@tpluscode/rdfine", | ||
"version": "0.1.1", | ||
"version": "0.1.2", | ||
"description": "RDF/JS idiomatic, native, enjoyable", | ||
@@ -16,3 +16,5 @@ "main": "dist/node/index.js", | ||
"build:web": "tsc -p tsconfig.web.json", | ||
"test": "jest --coverage", | ||
"test": "npm run test:ts-node; npm run test:babel", | ||
"test:ts-node": "jest --coverage", | ||
"test:babel": "jest --coverage -c jest.babel.config.js", | ||
"example": "ts-node -P tsconfig.example.json src/example/index.ts https://sources.wikibus.org/brochures" | ||
@@ -34,2 +36,7 @@ }, | ||
"devDependencies": { | ||
"@babel/plugin-proposal-class-properties": "^7.5.5", | ||
"@babel/plugin-proposal-decorators": "^7.4.4", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.5.5", | ||
"@babel/preset-env": "^7.5.5", | ||
"@babel/preset-typescript": "^7.3.3", | ||
"@commitlint/cli": "^8.2.0", | ||
@@ -36,0 +43,0 @@ "@commitlint/config-conventional": "^8.2.0", |
@@ -83,3 +83,3 @@ ## RDFine _/rɪdɪˈfaɪn/_ | ||
import { namedNode } from 'rdf-data-model' | ||
import { factory } from '@tpluscode/rdfine' | ||
import { RdfResourceImpl } from '@tpluscode/rdfine' | ||
import { Person, PersonMixin } from './Person' | ||
@@ -93,3 +93,3 @@ | ||
const person = factory.createEntity<Person>({ | ||
const person = RdfResourceImpl.factory.createEntity<Person>({ | ||
dataset, | ||
@@ -126,1 +126,25 @@ term: namedNode('http://example.com/gh/tpluscode') | ||
``` | ||
## Using with babel | ||
1. `npm i -D @babel/preset-env @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties` | ||
1. Configure babel (for example with `.babelrc`) | ||
``` | ||
{ | ||
"presets": [ | ||
[ | ||
"@babel/env" | ||
], | ||
"plugins": [ | ||
[ | ||
"@babel/plugin-proposal-decorators", | ||
{ | ||
"decoratorsBeforeExport": true | ||
} | ||
], | ||
[ | ||
"@babel/proposal-class-properties" | ||
] | ||
] | ||
} | ||
``` |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
55747
43
981
148
34