diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 5de3a147e..75890d3ed 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -8,7 +8,15 @@ module.exports = { 'prettier' ], plugins: ['svelte3', 'tailwindcss', '@typescript-eslint'], - ignorePatterns: ['docs/*', '*.cjs', '*.md', 'snapshots.js', 'svelte.config.js', 'package.json'], + ignorePatterns: [ + 'docs/*', + '*.cjs', + '*.md', + 'snapshots.js', + 'svelte.config.js', + 'package.json', + 'tsconfig.json' + ], overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], settings: { 'svelte3/typescript': () => require('typescript') diff --git a/package.json b/package.json index 68fa4b293..2f4589eba 100644 --- a/package.json +++ b/package.json @@ -1,69 +1,68 @@ { - "name": "mermaid-live-editor", - "version": "2.0.67", - "scripts": { - "dev": "svelte-kit dev", - "build": "svelte-kit build", - "preview": "svelte-kit preview", - "lint": "prettier --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .", - "lint:fix": "prettier --write --plugin-search-dir=. . && eslint --fix --ignore-path .gitignore .", - "format": "prettier --write --plugin-search-dir=. .", - "pre-commit": "lint-staged", - "postinstall": "husky install" - }, - "devDependencies": { - "@cypress/snapshot": "^2.1.7", - "@sveltejs/adapter-static": "1.0.0-next.11", - "@sveltejs/kit": "^1.0.0-next.109", - "@types/mermaid": "^8.2.6", - "@typescript-eslint/eslint-plugin": "^4.26.0", - "@typescript-eslint/parser": "^4.26.0", - "autoprefixer": "^10.2.6", - "chai": "^4.3.4", - "cssnano": "^5.0.5", - "cypress": "^7.4.0", - "cypress-localstorage-commands": "^1.4.5", - "eslint": "^7.27.0", - "eslint-config-prettier": "^8.1.0", - "eslint-plugin-cypress": "^2.11.3", - "eslint-plugin-mocha": "^9.0.0", - "eslint-plugin-postcss-modules": "^1.2.1", - "eslint-plugin-svelte3": "^3.2.0", - "eslint-plugin-tailwindcss": "^1.9.1", - "husky": "^6.0.0", - "lint-staged": "^11.0.0", - "mocha": "^8.4.0", - "postcss": "^8.3.0", - "postcss-load-config": "^3.0.1", - "prettier": "~2.3.0", - "prettier-plugin-svelte": "^2.3.0", - "svelte": "^3.34.0", - "svelte-preprocess": "^4.7.1", - "tailwindcss": "^2.1.4", - "tslib": "^2.0.0", - "typescript": "^4.3.2" - }, - "type": "module", - "dependencies": { - "@octokit/rest": "^18.3.0", - "@analytics/google-analytics": "^0.5.3", - "@macfja/svelte-persistent-store": "^1.1.1", - "analytics": "^0.7.5", - "js-base64": "^3.6.1", - "mermaid": "^8.10.1", - "moment": "^2.29.1", - "monaco-editor": "^0.24.0", - "random-word-slugs": "^0.0.2" - }, - "lint-staged": { - "*.{ts,svelte,js,css,md,json}": [ - "prettier --plugin-search-dir=. --write", - "eslint --ignore-path .gitignore " - ] - }, - "volta": { - "node": "14.16.1", - "yarn": "1.22.10", - "npm": "7.11.2" - } -} \ No newline at end of file + "name": "mermaid-live-editor", + "version": "2.0.67", + "scripts": { + "dev": "svelte-kit dev", + "build": "svelte-kit build", + "preview": "svelte-kit preview", + "lint": "prettier --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .", + "lint:fix": "prettier --write --plugin-search-dir=. . && eslint --fix --ignore-path .gitignore .", + "format": "prettier --write --plugin-search-dir=. .", + "pre-commit": "lint-staged", + "postinstall": "husky install" + }, + "devDependencies": { + "@cypress/snapshot": "^2.1.7", + "@sveltejs/adapter-static": "1.0.0-next.11", + "@sveltejs/kit": "^1.0.0-next.109", + "@types/mermaid": "^8.2.6", + "@typescript-eslint/eslint-plugin": "^4.26.0", + "@typescript-eslint/parser": "^4.26.0", + "autoprefixer": "^10.2.6", + "chai": "^4.3.4", + "cssnano": "^5.0.5", + "cypress": "^7.4.0", + "cypress-localstorage-commands": "^1.4.5", + "eslint": "^7.27.0", + "eslint-config-prettier": "^8.1.0", + "eslint-plugin-cypress": "^2.11.3", + "eslint-plugin-mocha": "^9.0.0", + "eslint-plugin-postcss-modules": "^1.2.1", + "eslint-plugin-svelte3": "^3.2.0", + "eslint-plugin-tailwindcss": "^1.9.1", + "husky": "^6.0.0", + "lint-staged": "^11.0.0", + "mocha": "^8.4.0", + "postcss": "^8.3.0", + "postcss-load-config": "^3.0.1", + "prettier": "~2.3.0", + "prettier-plugin-svelte": "^2.3.0", + "svelte": "^3.34.0", + "svelte-preprocess": "^4.7.1", + "tailwindcss": "^2.1.4", + "tslib": "^2.0.0", + "typescript": "^4.3.2" + }, + "type": "module", + "dependencies": { + "@analytics/google-analytics": "^0.5.3", + "@macfja/svelte-persistent-store": "^1.1.1", + "analytics": "^0.7.5", + "js-base64": "^3.6.1", + "mermaid": "^8.10.1", + "moment": "^2.29.1", + "monaco-editor": "^0.24.0", + "random-word-slugs": "^0.0.2" + }, + "lint-staged": { + "*.{ts,svelte,js,css,md,json}": [ + "prettier --plugin-search-dir=. --write", + "eslint --ignore-path .gitignore " + ] + }, + "volta": { + "node": "14.16.1", + "yarn": "1.22.10", + "npm": "7.11.2" + } +} diff --git a/src/gist-utils.js b/src/gist-utils.js deleted file mode 100644 index 74b23622b..000000000 --- a/src/gist-utils.js +++ /dev/null @@ -1,29 +0,0 @@ -import { Octokit } from '@octokit/rest'; - -const octokit = new Octokit({ - userAgent: 'mermaid-live-editor', - baseUrl: 'https://api.github.com', -}); - -const isValidGist = (files) => { - return 'config.json' in files && 'mermaid.diagram' in files; -}; - -const getFileContent = async (file) => { - if (file.truncated) { - return await (await fetch(file.raw_url)).text(); - } - return file.content; -}; - -export const getMermaidData = async (gist_id) => { - const gist = await octokit.gists.get({ - gist_id, - }); - const files = gist.data.files; - if (isValidGist(files)) { - const config = await getFileContent(files['config.json']); - const code = await getFileContent(files['mermaid.diagram']); - return { config, code }; - } -}; diff --git a/src/lib/util/fileLoaders/gist.ts b/src/lib/util/fileLoaders/gist.ts new file mode 100644 index 000000000..57a354e76 --- /dev/null +++ b/src/lib/util/fileLoaders/gist.ts @@ -0,0 +1,29 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +const isValidGist = (files: any): boolean => { + return 'diagram.mmd' in files; +}; + +const getFileContent = async (file: any): Promise => { + if (file.truncated) { + return await (await fetch(file.raw_url)).text(); + } + return file.content; +}; + +export const getGistData = async (gistURL: string): Promise<{ code: string; config?: string }> => { + const gistID = gistURL.split('/').pop(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const { files } = await (await fetch(`https://api.github.com/gists/${gistID}`)).json(); + + if (isValidGist(files)) { + const code = await getFileContent(files['diagram.mmd']); + if (!('config.json' in files)) { + return { code }; + } + const config = await getFileContent(files['config.json']); + return { config, code }; + } else { + throw 'Invalid gist provided'; + } +}; diff --git a/src/lib/util/fileLoaders/loader.ts b/src/lib/util/fileLoaders/loader.ts new file mode 100644 index 000000000..24144d292 --- /dev/null +++ b/src/lib/util/fileLoaders/loader.ts @@ -0,0 +1,29 @@ +import { getGistData } from './gist'; +import { updateCode, updateConfig } from '../state'; +type MermaidData = { code: string; config?: string }; +type Loader = (url: string) => Promise; +const loaders: Record = { + gist: getGistData +}; + +export const loadDataFromUrl = async (): Promise => { + const searchParams = new URLSearchParams(window.location.search); + let code: string, config: string; + if (searchParams.has('code')) { + code = await (await fetch(searchParams.get('code'))).text(); + } + if (searchParams.has('config')) { + config = await (await fetch(searchParams.get('config'))).text(); + } + + if (!code) { + for (const [key, value] of searchParams.entries()) { + if (key in loaders) { + ({ code, config } = await loaders[key](value)); + break; + } + } + } + code && updateCode(code, true, true); + config && updateConfig(config, true); +}; diff --git a/src/lib/util/util.ts b/src/lib/util/util.ts index 482dab1cf..1536ff3a8 100644 --- a/src/lib/util/util.ts +++ b/src/lib/util/util.ts @@ -1,6 +1,7 @@ import type { State } from '$lib/types'; import { initURLSubscription, loadState, updateCodeStore } from './state'; import { analytics, initAnalytics } from './stats'; +import { loadDataFromUrl } from './fileLoaders/loader'; export const loadStateFromURL = (): void => { loadState(window.location.hash.slice(1)); @@ -14,6 +15,7 @@ export const syncDiagram = (): void => { export const initHandler = async (): Promise => { loadStateFromURL(); + await loadDataFromUrl(); syncDiagram(); initURLSubscription(); await initAnalytics(); diff --git a/tsconfig.json b/tsconfig.json index 975f193c0..e82fd2974 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "moduleResolution": "node", "module": "es2020", - "lib": ["es2020", "ESNext"], + "lib": ["es2020", "ESNext", "DOM.Iterable"], "target": "es2019", /** svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript