Skip to content

Commit

Permalink
Fix spelling, add comments and fix .props not returning props that ar…
Browse files Browse the repository at this point in the history
…e not in the resources classdefs #700
  • Loading branch information
Polleps committed Nov 7, 2024
1 parent 40ad7ff commit edce8ba
Show file tree
Hide file tree
Showing 14 changed files with 128 additions and 90 deletions.
9 changes: 8 additions & 1 deletion browser/cli/src/generatePropTypeMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,12 @@ const generateLine = (subject: string, reverseMapping: ReverseMapping) => {
const resource = store.getResourceLoading<Core.Property>(subject);
const datatype = resource.props.datatype as Datatype;

return `[${reverseMapping[subject]}]: ${DatatypeToTSTypeMap[datatype]}`;
const type = DatatypeToTSTypeMap[datatype];

if (!type) {
console.error(`Unknown datatype ${datatype} on property ${resource.title}`);
process.exit(1);
}

return `[${reverseMapping[subject]}]: ${type}`;
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export async function getCurrentResource(
url: URL
): Promise<Resource | undefined> {
const store = getStore();
// Svelte uses a special fetch function that inlines responses during server-side rendering. To make sure the store can make use of this we need to inject the fetch function into the store.
// Svelte uses a special fetch function that inlines responses during server-side rendering.
// To make sure the store can make use of this we need to inject the fetch function into the store.
store.injectFetch(fetchOverride);

const path = url.pathname;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,3 @@ import { PUBLIC_WEBSITE_RESOURCE } from '$env/static/public';
export const appState = $state({
currentSubject: PUBLIC_WEBSITE_RESOURCE
});

export const setCurrentSubject = (value: string) => {
appState.currentSubject = value;
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import VStack from '$lib/components/Layout/VStack.svelte';
import { getStore } from '$lib/atomic/getStore';
// We set the store on the AtomicStoreContext so it can be accessed by `getResource()`.
const store = getStore();
createAtomicStoreContext(store);
</script>
Expand Down
14 changes: 10 additions & 4 deletions browser/data-browser/src/routes/Sandbox.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { useResource, type Core } from '@tomic/react';
import { ContainerFull } from '../components/Containers';

export function Sandbox(): JSX.Element {
const properties = useResource<Core.Property>(
'https://atomicdata.dev/properties/properties',
);

if (properties.loading) {
return <p>Loading...</p>;
}

return (
<main>
<ContainerFull>
<h1>Sandbox</h1>
<p>
Welcome to the sandbox. This is a place to test components in
isolation.
</p>
<p>{properties.props.datatype ?? 'nothing'}</p>
</ContainerFull>
</main>
);
Expand Down
2 changes: 1 addition & 1 deletion browser/lib/src/ontologies/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ declare module '../index.js' {
[core.properties.write]: string[];
[core.properties.publicKey]: string;
[core.properties.instances]: string[];
[core.properties.properties]: undefined;
[core.properties.properties]: string[];
[core.properties.classes]: string[];
[core.properties.isLocked]: boolean;
[core.properties.localId]: string;
Expand Down
125 changes: 65 additions & 60 deletions browser/lib/src/ontologies/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,35 @@ export const server = {
'https://atomicdata.dev/ontology/server/class/endpoint-response',
},
properties: {
drives: 'https://atomicdata.dev/properties/drives',
results: 'https://atomicdata.dev/properties/endpoint/results',
property: 'https://atomicdata.dev/properties/search/property',
redirectAgent: 'https://atomicdata.dev/properties/invite/redirectAgent',
agent: 'https://atomicdata.dev/properties/invite/agent',
publicKey: 'https://atomicdata.dev/properties/invite/publicKey',
target: 'https://atomicdata.dev/properties/invite/target',
usagesLeft: 'https://atomicdata.dev/properties/invite/usagesLeft',
users: 'https://atomicdata.dev/properties/invite/users',
write: 'https://atomicdata.dev/properties/invite/write',
filename: 'https://atomicdata.dev/properties/filename',
filesize: 'https://atomicdata.dev/properties/filesize',
downloadUrl: 'https://atomicdata.dev/properties/downloadURL',
mimetype: 'https://atomicdata.dev/properties/mimetype',
altText: 'https://atomicdata.dev/ontology/server/property/alt-text',
attachments: 'https://atomicdata.dev/properties/attachments',
createdBy: 'https://atomicdata.dev/properties/createdBy',
checksum: 'https://atomicdata.dev/properties/checksum',
internalId: 'https://atomicdata.dev/properties/internalId',
children: 'https://atomicdata.dev/properties/children',
parameters: 'https://atomicdata.dev/properties/endpoint/parameters',
destination: 'https://atomicdata.dev/properties/destination',
status: 'https://atomicdata.dev/ontology/server/property/status',
responseMessage:
'https://atomicdata.dev/ontology/server/property/response-message',
createdBy: 'https://atomicdata.dev/properties/createdBy',
defaultOntology:
'https://atomicdata.dev/ontology/server/property/default-ontology',
imageWidth: 'https://atomicdata.dev/properties/imageWidth',
destination: 'https://atomicdata.dev/properties/destination',
downloadUrl: 'https://atomicdata.dev/properties/downloadURL',
drives: 'https://atomicdata.dev/properties/drives',
filename: 'https://atomicdata.dev/properties/filename',
filesize: 'https://atomicdata.dev/properties/filesize',
imageHeight: 'https://atomicdata.dev/properties/imageHeight',
imageWidth: 'https://atomicdata.dev/properties/imageWidth',
internalId: 'https://atomicdata.dev/properties/internalId',
mimetype: 'https://atomicdata.dev/properties/mimetype',
parameters: 'https://atomicdata.dev/properties/endpoint/parameters',
property: 'https://atomicdata.dev/properties/search/property',
publicKey: 'https://atomicdata.dev/properties/invite/publicKey',
redirectAgent: 'https://atomicdata.dev/properties/invite/redirectAgent',
responseMessage:
'https://atomicdata.dev/ontology/server/property/response-message',
results: 'https://atomicdata.dev/properties/endpoint/results',
status: 'https://atomicdata.dev/ontology/server/property/status',
target: 'https://atomicdata.dev/properties/invite/target',
usagesLeft: 'https://atomicdata.dev/properties/invite/usagesLeft',
users: 'https://atomicdata.dev/properties/invite/users',
write: 'https://atomicdata.dev/properties/invite/write',
},
__classDefs: {
['https://atomicdata.dev/classes/Error']: [
Expand Down Expand Up @@ -76,6 +77,7 @@ export const server = {
'https://atomicdata.dev/properties/internalId',
'https://atomicdata.dev/properties/imageWidth',
'https://atomicdata.dev/properties/imageHeight',
'https://atomicdata.dev/ontology/server/property/alt-text',
],
['https://atomicdata.dev/classes/Invite']: [
'https://atomicdata.dev/properties/invite/target',
Expand Down Expand Up @@ -139,7 +141,8 @@ declare module '../index.js' {
| typeof server.properties.mimetype
| typeof server.properties.internalId
| typeof server.properties.imageWidth
| typeof server.properties.imageHeight;
| typeof server.properties.imageHeight
| typeof server.properties.altText;
};
[server.classes.invite]: {
requires: BaseProps | typeof server.properties.target;
Expand All @@ -159,60 +162,62 @@ declare module '../index.js' {
}

interface PropTypeMapping {
[server.properties.agent]: string;
[server.properties.altText]: string;
[server.properties.attachments]: string[];
[server.properties.checksum]: string;
[server.properties.children]: string[];
[server.properties.createdBy]: string;
[server.properties.defaultOntology]: string;
[server.properties.destination]: string;
[server.properties.downloadUrl]: string;
[server.properties.drives]: string[];
[server.properties.results]: string[];
[server.properties.filename]: string;
[server.properties.filesize]: number;
[server.properties.imageHeight]: number;
[server.properties.imageWidth]: number;
[server.properties.internalId]: string;
[server.properties.mimetype]: string;
[server.properties.parameters]: string[];
[server.properties.property]: string;
[server.properties.redirectAgent]: string;
[server.properties.agent]: string;
[server.properties.publicKey]: string;
[server.properties.redirectAgent]: string;
[server.properties.responseMessage]: string;
[server.properties.results]: string[];
[server.properties.status]: number;
[server.properties.target]: string;
[server.properties.usagesLeft]: number;
[server.properties.users]: string[];
[server.properties.write]: boolean;
[server.properties.filename]: string;
[server.properties.filesize]: number;
[server.properties.downloadUrl]: string;
[server.properties.mimetype]: string;
[server.properties.attachments]: string[];
[server.properties.createdBy]: string;
[server.properties.checksum]: string;
[server.properties.internalId]: string;
[server.properties.children]: string[];
[server.properties.parameters]: string[];
[server.properties.destination]: string;
[server.properties.status]: number;
[server.properties.responseMessage]: string;
[server.properties.defaultOntology]: string;
[server.properties.imageWidth]: number;
[server.properties.imageHeight]: number;
}

interface PropSubjectToNameMapping {
[server.properties.agent]: 'agent';
[server.properties.altText]: 'altText';
[server.properties.attachments]: 'attachments';
[server.properties.checksum]: 'checksum';
[server.properties.children]: 'children';
[server.properties.createdBy]: 'createdBy';
[server.properties.defaultOntology]: 'defaultOntology';
[server.properties.destination]: 'destination';
[server.properties.downloadUrl]: 'downloadUrl';
[server.properties.drives]: 'drives';
[server.properties.results]: 'results';
[server.properties.filename]: 'filename';
[server.properties.filesize]: 'filesize';
[server.properties.imageHeight]: 'imageHeight';
[server.properties.imageWidth]: 'imageWidth';
[server.properties.internalId]: 'internalId';
[server.properties.mimetype]: 'mimetype';
[server.properties.parameters]: 'parameters';
[server.properties.property]: 'property';
[server.properties.redirectAgent]: 'redirectAgent';
[server.properties.agent]: 'agent';
[server.properties.publicKey]: 'publicKey';
[server.properties.redirectAgent]: 'redirectAgent';
[server.properties.responseMessage]: 'responseMessage';
[server.properties.results]: 'results';
[server.properties.status]: 'status';
[server.properties.target]: 'target';
[server.properties.usagesLeft]: 'usagesLeft';
[server.properties.users]: 'users';
[server.properties.write]: 'write';
[server.properties.filename]: 'filename';
[server.properties.filesize]: 'filesize';
[server.properties.downloadUrl]: 'downloadUrl';
[server.properties.mimetype]: 'mimetype';
[server.properties.attachments]: 'attachments';
[server.properties.createdBy]: 'createdBy';
[server.properties.checksum]: 'checksum';
[server.properties.internalId]: 'internalId';
[server.properties.children]: 'children';
[server.properties.parameters]: 'parameters';
[server.properties.destination]: 'destination';
[server.properties.status]: 'status';
[server.properties.responseMessage]: 'responseMessage';
[server.properties.defaultOntology]: 'defaultOntology';
[server.properties.imageWidth]: 'imageWidth';
[server.properties.imageHeight]: 'imageHeight';
}
}
6 changes: 3 additions & 3 deletions browser/lib/src/ontology.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,17 @@ export type InferTypeOfValueInTriple<
: JSONValue,
> = Returns;

type QuickAccesKnownPropType<Class extends OptionalClass> = {
type QuickAccessKnownPropType<Class extends OptionalClass> = {
[Prop in keyof PropsOfClass<Class> as PropSubjectToNameMapping[Prop]]: InferTypeOfValueInTriple<
Class,
Prop
>;
};

/** Type of the dynamically created resource.props field */
export type QuickAccesPropType<Class extends OptionalClass = UnknownClass> =
export type QuickAccessPropType<Class extends OptionalClass = UnknownClass> =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Class extends UnknownClass ? any : QuickAccesKnownPropType<Class>;
Class extends UnknownClass ? any : QuickAccessKnownPropType<Class>;

export type OptionalClass = keyof Classes | UnknownClass;

Expand Down
20 changes: 16 additions & 4 deletions browser/lib/src/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ import { server } from './ontologies/server.js';

import {
getKnownClassDefBySubject,
getKnownNameBySubject,
type InferTypeOfValueInTriple,
type OptionalClass,
type QuickAccesPropType,
type QuickAccessPropType,
} from './ontology.js';
import type { Store } from './store.js';
import { properties, instances, urls } from './urls.js';
Expand Down Expand Up @@ -100,7 +101,7 @@ export class Resource<C extends OptionalClass = any> {
return this._subject;
}

/** A human readable title for the resource, returns first of eighter: name, shortname, filename or subject */
/** A human readable title for the resource, returns first of either: name, shortname, filename or subject */
public get title(): string {
return (this.get(core.properties.name) ??
this.get(core.properties.shortname) ??
Expand All @@ -112,7 +113,7 @@ export class Resource<C extends OptionalClass = any> {
* Dynamic prop accessor, only works for known properties registered via an ontology.
* @example const description = resource.props.description
*/
public get props(): QuickAccesPropType<C> {
public get props(): QuickAccessPropType<C> {
const defaultProps = {
parent: core.properties.parent,
isA: core.properties.isA,
Expand All @@ -128,20 +129,31 @@ export class Resource<C extends OptionalClass = any> {
.filter(def => def !== undefined);

const getPropSubject = (name: string) => {
// Check if the property is a default property
if (name in defaultProps) {
return defaultProps[name];
}

// Check if the property is defined in any of the classes
for (const def of defs) {
const value = def[name];

if (value !== undefined) {
return value;
}
}

// Check if any of its propvals have the name
for (const key of this.propvals.keys()) {
const propName = getKnownNameBySubject(key);

if (propName === name) {
return key;
}
}
};

return new Proxy({} as QuickAccesPropType<C>, {
return new Proxy({} as QuickAccessPropType<C>, {
get(_target, propName) {
const propSubject = getPropSubject(propName as string);

Expand Down
7 changes: 4 additions & 3 deletions browser/svelte/src/lib/stores/getResource.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import { getStoreFromContext } from './store.js';

/**
* Starts fetching a resource and adds it to the store.
* An empty resource will be returned immediately that updates when the resource is fetched.
* This way you can start rendering UI that
* Unless the resource was found in the cache, an empty resource will be returned immediately that updates when the resource is fetched.
* This way you can start rendering UI without having to wait for the resource to be fetched.
* To check if the resource is ready, use `resource.loading`.
* Only works in components contexts. If you want to fetch a resource outside of a component, use `await store.getResource()`.
* Only works in component contexts. If you want to fetch a resource outside of a component, use `await store.getResource()`.
*
* You need to pass the subject as a function that returns a string to make it reactive.
*
Expand Down Expand Up @@ -76,6 +76,7 @@ export function getResource<T extends OptionalClass = never>(
};
});

// Returning the resource directly would break the reactivity so we need to proxy it.
return new Proxy(resource, {
get(_, prop) {
return resource[prop as keyof Resource];
Expand Down
7 changes: 4 additions & 3 deletions docs/src/js-lib/resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ const category = resource.get(

## Writing Data

Writing data is done using the `.set` method (works on any resource) or by asigning to the props accessor (only works on annotated resources).
Writing data is done using the `.set` method (works on any resource) or by assigning to the props accessor (only works on annotated resources).

### Using .props:
### Using .props

```typescript
import { type Article } from './ontologies/article';
Expand All @@ -89,7 +89,7 @@ await resource.save();
Setting values via `resource.props` does not validate the value against the properties datatype.
Use the `resource.set()` method when you want to validate the value.

### Using .set():
### Using .set()

```typescript
import { core } from '@tomic/lib';
Expand Down Expand Up @@ -146,6 +146,7 @@ await resource.save();
> For example: `resource.props.likedBy.push('https://my-atomicserver.com/users/1')` will not work.
**Parameters**

| Name | Type | Description |
|----------|-----------|-----------------------------------------------------------------------------------------------------|
| property | string | Subject of the property to push to |
Expand Down
2 changes: 1 addition & 1 deletion docs/src/js-lib/store.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ It takes an object with the following options
| Name | Type | Description |
|-----------|---------------------|------------------------------------------------------------------------------------------------------------------------------------------|
| serverUrl | string | URL of your atomic server |
| agent | [Agent](./agent.md) | **(optional)** The agent the store should use to fetch resources and to sign commits when editting resources, defaults to a public agent |
| agent | [Agent](./agent.md) | **(optional)** The agent the store should use to fetch resources and to sign commits when editing resources, defaults to a public agent |

```typescript
const store = new Store({
Expand Down
Loading

0 comments on commit edce8ba

Please sign in to comment.