Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
jgreywolf committed Dec 5, 2023
2 parents 0e6546b + cd5f294 commit 528055b
Show file tree
Hide file tree
Showing 5 changed files with 283 additions and 14 deletions.
134 changes: 124 additions & 10 deletions openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,51 @@ components:
- title
Document:
type: object
description: |
MermaidChart document that may contain a diagram.
properties:
documentID:
type: string
projectID:
type: string
title:
type: string
required:
- documentID
- projectID
- title
DiagramDocument:
type: object
description: |
MermaidChart diagram document, without any Document metadata.
properties:
documentID:
description: |
The id of the document that this diagram is linked to.
type: string
format: uuid
major:
type: integer
minor:
type: integer
title:
id:
type: string
format: uuid
description: |
The id of this diagram, required for `setDocument()`.
code:
type: string
description: |
The Mermaid
[`application/vnd.mermaid`](https://www.iana.org/assignments/media-types/application/vnd.mermaid)
code for this diagram.
required:
- documentID
- projectID
- major
- minor
- title
- id
MCDocument:
description: |
MermaidChart diagram document.
allOf:
- $ref: "#/components/schemas/Document"
- $ref: "#/components/schemas/DiagramDocument"

securitySchemes:
bearer_auth:
Expand Down Expand Up @@ -127,7 +155,35 @@ paths:
schema:
type: array
items:
$ref: '#/components/schemas/Document'
$ref: '#/components/schemas/MCDocument'
post:
tags:
- project
summary: Add a new document to the project.
operationId: createDocument
parameters:
- name: projectID
in: path
required: true
description: The ID of the project to add a document to.
schema:
type: string
requestBody:
description: Currently unused, as long as it's not a form.
required: true
content:
application/json:
schema:
type: object
responses:
'200':
description: |
The newly created diagram document.
content:
application/json:
schema:
$ref: '#/components/schemas/MCDocument'

/app/projects/{projectID}/diagrams/{documentID}/version/{version}:
get:
tags:
Expand Down Expand Up @@ -159,7 +215,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/Document'
$ref: '#/components/schemas/MCDocument'

/rest-api/documents/{documentID}:
get:
Expand Down Expand Up @@ -193,9 +249,67 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/Document'
$ref: '#/components/schemas/MCDocument'
'404':
description: File Not Found
put:
tags:
- document
summary: Update the given document.
operationId: setDocument
parameters:
- name: documentID
in: path
required: true
description: The ID of the document to update.
schema:
type: string
requestBody:
description: Document and diagram settings to update.
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/MCDocument'
security:
- mermaidchart_auth: []
responses:
'200':
description: |
Update status.
content:
application/json:
schema:
type: object
# TODO: update this once MC-1060 is fixed.
# properties:
# result:
# type: string
# enum:
# - ok
# - failed
delete:
tags:
- document
summary: Delete the given document.
operationId: deleteDocument
parameters:
- name: documentID
in: path
required: true
description: The ID of the document to delete.
schema:
type: string
security:
- mermaidchart_auth: []
responses:
'200':
description: The deleted document.
content:
application/json:
schema:
# currently only returns the document, no diagram data!!!!
$ref: '#/components/schemas/Document'

/raw/{documentID}:
get:
Expand Down
4 changes: 4 additions & 0 deletions packages/sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Compile an ESM version of this codebase for Node.JS v18.
- Add `MermaidChart#getDiagram(diagramID)` function to get a diagram.
- Add `MermaidChart#createDocument(projectID)` function to create a digram in a project.
- Add `MermaidChart#setDocument(document)` function to update a diagram.
- Add `MermaidChart#deleteDocument(documentID)` function to delete a diagram.

### Fixed

- Fix `MCDocument` `major`/`minor` type to `number`.
- Add `code` field to `MCDocument` type

### Fixed

Expand Down
88 changes: 87 additions & 1 deletion packages/sdk/src/index.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
* E2E tests
*/
import { MermaidChart } from './index.js';
import { beforeAll, describe, expect, it } from 'vitest';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';

import process from 'node:process';
import { AxiosError } from 'axios';
import { MCDocument } from './types.js';

// hard-coded, replace with your own project,
// or ask alois is you want this to be shared with your account
const testProjectId = '316557b3-cb6f-47ed-acf7-fcfb7ce188d5';

let client: MermaidChart;

Expand Down Expand Up @@ -40,6 +45,86 @@ const documentMatcher = expect.objectContaining({
minor: expect.any(Number),
});

/**
* Cleanup created documents at the end of this test.
*/
const documentsToDelete = new Set<MCDocument["documentID"]>();
afterAll(async() => {
await Promise.all(Array.from(documentsToDelete).map(async(document) => {
if (documentsToDelete.delete(document)) {
await client.deleteDocument(document);
}
}));
});

describe('createDocument', () => {
it('should create document in project', async() => {
const existingDocuments = await client.getDocuments(testProjectId);

const newDocument = await client.createDocument(testProjectId);

documentsToDelete.add(newDocument.documentID);

expect(newDocument).toStrictEqual(documentMatcher);

const updatedProjectDocuments = await client.getDocuments(testProjectId);

expect(existingDocuments).not.toContainEqual(newDocument);
expect(updatedProjectDocuments).toContainEqual(newDocument);
});
});

describe('setDocument', () => {
it('should set document', async() => {
const newDocument = await client.createDocument(testProjectId);
documentsToDelete.add(newDocument.documentID);

const code = `flowchart LR
A(Generated by<br><code>@mermaidchart/sdk</code><br>E2E tests)`;

await client.setDocument({
documentID: newDocument.documentID,
id: newDocument.id, // diagram ID
title: "@mermaidchart/sdk E2E test diagram",
code,
});

const updatedDoc = await client.getDocument({
documentID: newDocument.documentID,
});
expect(updatedDoc).toMatchObject({
title: "@mermaidchart/sdk E2E test diagram",
code,
});
});

// TODO: this function never seems to return an error, see MC-1060
it.skip('should throw an error on invalid data', async() => {
const newDocument = await client.createDocument(testProjectId);
documentsToDelete.add(newDocument.documentID);

await expect(client.setDocument({
documentID: newDocument.documentID,
// @ts-expect-error not setting diagram `id` should throw an error
id: null,
})).rejects.toThrowError("400"); // should throw HTTP 400 error
});
});

describe('deleteDocument', () => {
it('should delete document', async() => {
const newDocument = await client.createDocument(testProjectId);

expect(await client.getDocuments(testProjectId)).toContainEqual(newDocument);

const deletedDoc = await client.deleteDocument(newDocument.documentID);

expect(deletedDoc.projectID).toStrictEqual(newDocument.projectID);

expect(await client.getDocuments(testProjectId)).not.toContainEqual(newDocument);
});
});

describe("getDocument", () => {
it("should get publicly shared diagram", async() => {
const latestDocument = await client.getDocument({
Expand Down Expand Up @@ -73,3 +158,4 @@ describe("getDocument", () => {
expect(error?.response?.status).toBe(404);
});
});

42 changes: 42 additions & 0 deletions packages/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { RequiredParameterMissingError, OAuthError } from './errors.js';
import { URLS } from './urls.js';
import type {
AuthState,
Document,
InitParams,
AuthorizationData,
MCUser,
Expand Down Expand Up @@ -181,6 +182,14 @@ export class MermaidChart {
return projects.data;
}

public async createDocument(projectID: string) {
const newDocument = await this.axios.post<MCDocument>(
URLS.rest.projects.get(projectID).documents,
{}, // force sending empty JSON to avoid triggering CSRF check
);
return newDocument.data;
}

public async getEditURL(
document: Pick<MCDocument, 'documentID' | 'major' | 'minor' | 'projectID'>,
) {
Expand All @@ -195,6 +204,39 @@ export class MermaidChart {
return data;
}

/**
* Update the given document.
*
* @param document The document to update.
*/
public async setDocument(
document: Pick<MCDocument, 'id' | 'documentID'> & Partial<MCDocument>,
) {
const {data} = await this.axios.put<{result: "ok"} | {result: "failed", error: any}>(
URLS.rest.documents.pick(document).self,
document,
);

if (data.result === "failed") {
throw new Error(
`setDocument(${JSON.stringify({documentID: document.documentID})} failed due to ${JSON.stringify(data.error)}`
);
}
}

/**
* Delete the given document.
* @param documentID The ID of the document to delete.
* @returns Metadata about the deleted document.
*/
public async deleteDocument(documentID: MCDocument['documentID']) {
const deletedDocument = await this.axios.delete<Document>(
URLS.rest.documents.pick({documentID}).self,
{}, // force sending empty JSON to avoid triggering CSRF check
);
return deletedDocument.data;
}

public async getRawDocument(
document: Pick<MCDocument, 'documentID' | 'major' | 'minor'>,
theme: 'light' | 'dark',
Expand Down
29 changes: 26 additions & 3 deletions packages/sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,35 @@ export interface MCProject {
title: string;
}

export interface MCDocument {
documentID: string;
/**
* MermaidChart diagram document.
*/
export type MCDocument = Document & DiagramDocument;

/**
* MermaidChart document that may contain a diagram.
*/
export interface Document {
projectID: string;
title: string;
}

/**
* MermaidChart diagram document, without any {@link Document} metadata.
*/
export interface DiagramDocument {
/** The id of this diagram, required for `setDocument()` */
id: string;
/** The id of the document that this diagram is linked to. */
documentID: string;
major: number;
minor: number;
title: string;
/**
* The Mermaid
* [`application/vnd.mermaid`](https://www.iana.org/assignments/media-types/application/vnd.mermaid)
* code for this diagram.
*/
code?: string;
}

export interface AuthorizationData {
Expand Down

0 comments on commit 528055b

Please sign in to comment.