├── screenshots
├── screenshot1.png
└── screenshot2.png
├── .npmignore
├── tsconfig.json
├── src
├── svelte
│ ├── Welcome.svelte
│ ├── Logo.svelte
│ └── App.svelte
├── types
│ └── index.d.ts
├── vendor
│ ├── pluginUtils.d.ts
│ ├── tsWorker.d.ts
│ ├── typescript-vfs.d.ts
│ ├── playground.d.ts
│ └── sandbox.d.ts
└── index.ts
├── .gitignore
├── package.json
├── rollup.config.js
├── scripts
└── open-playground.js
├── CONTRIBUTING.md
└── README.md
/screenshots/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/just214/typescript-playground-plugin-svelte/HEAD/screenshots/screenshot1.png
--------------------------------------------------------------------------------
/screenshots/screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/just214/typescript-playground-plugin-svelte/HEAD/screenshots/screenshot2.png
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | .gitignore
3 | rollup.config.jss
4 | !dist
5 | scripts
6 | .vscode
7 | yarn*
8 | tsconfig.json
9 | rollup*
10 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "esModuleInterop": true,
5 | "noEmit": true,
6 | "typeRoots": ["src/types", "src/vendor"]
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/svelte/Welcome.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
TypeScript Playground Plugin
6 | with Svelte!
7 |
8 |
9 |
10 |
11 |
23 |
--------------------------------------------------------------------------------
/src/types/index.d.ts:
--------------------------------------------------------------------------------
1 | import {ShowModal, FlashInfo} from '../index'
2 |
3 | declare module "*.jpeg";
4 | declare module "*.jpg";
5 | declare module "*.png";
6 | declare module '*.svg' {
7 | const content: any
8 | export default content;
9 | }
10 |
11 | declare global {
12 | interface Window {
13 | playground: {
14 | ui: {
15 | showModal: ShowModal;
16 | flashInfo: FlashInfo;
17 | };
18 | };
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/vendor/pluginUtils.d.ts:
--------------------------------------------------------------------------------
1 | import { Node } from "typescript";
2 | /** Creates a set of util functions which is exposed to Plugins to make it easier to build consistent UIs */
3 | export declare const createUtils: (sb: any) => {
4 | /** Use this to make a few dumb element generation funcs */
5 | el: (str: string, el: string, container: Element) => void;
6 | /** Get a relative URL for something in your dist folder depending on if you're in dev mode or not */
7 | requireURL: (path: string) => string;
8 | /** Returns a div which has an interactive AST a TypeScript AST by passing in the root node */
9 | createASTTree: (node: Node) => HTMLDivElement;
10 | };
11 | export declare type PluginUtils = ReturnType;
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 |
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 |
10 | # Runtime data
11 | pids
12 | *.pid
13 | *.seed
14 | *.pid.lock
15 |
16 | # Directory for instrumented libs generated by jscoverage/JSCover
17 | lib-cov
18 |
19 | # Coverage directory used by tools like istanbul
20 | coverage
21 |
22 | # nyc test coverage
23 | .nyc_output
24 |
25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
26 | .grunt
27 |
28 | # Bower dependency directory (https://bower.io/)
29 | bower_components
30 |
31 | # node-waf configuration
32 | .lock-wscript
33 |
34 | # Compiled binary addons (http://nodejs.org/api/addons.html)
35 | build/Release
36 |
37 | # Dependency directories
38 | node_modules/
39 | jspm_packages/
40 |
41 | # Typescript v1 declaration files
42 | typings/
43 |
44 | # Optional npm cache directory
45 | .npm
46 |
47 | # Optional eslint cache
48 | .eslintcache
49 |
50 | # Optional REPL history
51 | .node_repl_history
52 |
53 | # Output of 'npm pack'
54 | *.tgz
55 |
56 | # dotenv environment variables file
57 | .env
58 |
59 | # gatsby files
60 | .cache/
61 | public
62 |
63 | # Mac files
64 | .DS_Store
65 |
66 | # Yarn
67 | yarn-error.log
68 | .pnp/
69 | .pnp.js
70 | # Yarn Integrity file
71 | .yarn-integrity
72 | dist
73 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "typescript-playground-plugin-svelte",
3 | "description": "Easily create TypeScript Playground Plugins with Svelte.",
4 | "version": "0.0.1",
5 | "main": "dist/index.js",
6 | "keywords": [
7 | "playground-plugin"
8 | ],
9 | "license": "MIT",
10 | "scripts": {
11 | "start": "npm run watch",
12 | "watch": "cross-env NODE_ENV=development rollup -c -w",
13 | "build": "cross-env NODE_ENV=production rollup -c"
14 | },
15 | "devDependencies": {
16 | "@rollup/plugin-commonjs": "^11.0.2",
17 | "@rollup/plugin-image": "^2.0.4",
18 | "@rollup/plugin-json": "^4.0.2",
19 | "@rollup/plugin-node-resolve": "^7.1.1",
20 | "@rollup/plugin-replace": "^2.3.1",
21 | "@rollup/plugin-typescript": "^3.0.0",
22 | "chalk": "^3.0.0",
23 | "concurrently": "^5.1.0",
24 | "cross-env": "^7.0.1",
25 | "get-chrome-tabs": "^1.0.0",
26 | "monaco-editor": "^0.20.0",
27 | "node-fetch": "^2.6.0",
28 | "rollup": "^1.32.0",
29 | "rollup-plugin-analyzer": "^3.2.2",
30 | "rollup-plugin-execute": "^1.1.1",
31 | "rollup-plugin-progress": "^1.1.1",
32 | "rollup-plugin-serve": "^1.0.1",
33 | "rollup-plugin-svelte": "^5.1.1",
34 | "rollup-plugin-terser": "^5.2.0",
35 | "serve": "^11.3.0",
36 | "svelte": "^3.19.1",
37 | "typescript": "latest"
38 | },
39 | "dependencies": {
40 | "tslib": "^1.11.1"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import typescript from "@rollup/plugin-typescript";
2 | import replace from "@rollup/plugin-replace";
3 | import node from "@rollup/plugin-node-resolve";
4 | import commonjs from "@rollup/plugin-commonjs";
5 | import json from "@rollup/plugin-json";
6 | import svelte from "rollup-plugin-svelte";
7 | import image from "@rollup/plugin-image";
8 | import execute from "rollup-plugin-execute";
9 | import progress from "rollup-plugin-progress";
10 | import { terser } from "rollup-plugin-terser";
11 | import serve from "rollup-plugin-serve";
12 | import analyze from "rollup-plugin-analyzer";
13 |
14 | const isProd = process.env.NODE_ENV === "production";
15 |
16 | export default {
17 | input: `src/index.ts`,
18 | output: {
19 | name: "index",
20 | dir: "dist",
21 | format: "amd"
22 | },
23 | plugins: [
24 | isProd &&
25 | analyze({
26 | summaryOnly: true
27 | }),
28 | progress(),
29 | execute("node scripts/open-playground"),
30 | image(),
31 | typescript({ tsconfig: "tsconfig.json" }),
32 |
33 | svelte({
34 | // enable run-time checks when not in production
35 | dev: !isProd
36 | }),
37 | replace({
38 | "process.env.NODE_ENV": JSON.stringify(
39 | isProd ? "production" : "development"
40 | )
41 | }),
42 | node({
43 | browser: true,
44 | dedupe: ["svelte"]
45 | }),
46 | commonjs(),
47 | // Minify
48 | isProd && terser(),
49 | json(),
50 | !isProd &&
51 | serve({
52 | contentBase: "dist",
53 | port: 5000
54 | })
55 | ]
56 | };
57 |
--------------------------------------------------------------------------------
/scripts/open-playground.js:
--------------------------------------------------------------------------------
1 | /*
2 | This script is responsible for opening the TypeScript Playground in Chrome on the first
3 | build when running the "start" script. It also provides some useful console messages.
4 |
5 | It is called by rollup-plugin-execute in rollup.config.js
6 | */
7 | const exec = require("child_process").exec;
8 | const getChromeTabs = require("get-chrome-tabs");
9 | const chalk = require("chalk");
10 |
11 | const PLAYGROUND_URL = "https://www.typescriptlang.org/v2/en/play";
12 |
13 | function openPlayground() {
14 | exec(`open-cli ${PLAYGROUND_URL} -- 'google chrome'`, function(err) {
15 | if (err) {
16 | console.log(
17 | chalk.red("Error opening the TypeScript Playground. Please try again.")
18 | );
19 | } else {
20 | const message = chalk.green(
21 | '\n🚀 The TypeScript Playground was opened in Chrome. To view your plugin, select "Options > Connect to localhost:5000/index.js" in the Playground sidebar and refresh the browser tab.'
22 | );
23 | console.log(message);
24 | }
25 | });
26 | }
27 |
28 | let tabList = [];
29 |
30 | getChromeTabs()
31 | .then(tabs => {
32 | tabList = tabs;
33 | })
34 | .catch(err => {
35 | return err;
36 | })
37 | .finally(() => {
38 | const isPlaygroundOpen = tabList.find(tab =>
39 | tab.url.includes(PLAYGROUND_URL)
40 | );
41 | if (!isPlaygroundOpen) {
42 | openPlayground();
43 | } else {
44 | console.log(
45 | chalk.green(
46 | "\n🚀 Your plugin has been updated. Please refresh the TypeScript Playground Chrome tab to see your changes."
47 | )
48 | );
49 | }
50 | });
51 |
--------------------------------------------------------------------------------
/src/svelte/Logo.svelte:
--------------------------------------------------------------------------------
1 |
40 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing to a TypeScript Playground Plugin
2 |
3 | ## Contributing
4 |
5 | You can use `yarn start` to set up both a copy of Rollup to generate the JS, and Serve to host it.
6 |
7 | ```sh
8 | yarn start
9 | ```
10 |
11 | Then set up the TypeScript playground to connect to a dev plugin at `http://localhost:5000/index.js`.
12 |
13 | #### Plugin API
14 |
15 | The plugin API is documented in the [interface PlaygroundPlugin in `./src/vendor/playground.d.ts`](src/vendor/playground.d.ts)
16 |
17 | Roughly:
18 |
19 | - There are a set of mounting and un-mounting functions which you can use to handle your UI in the sidebar
20 | - There are `modelChanged` methods, which are shortcuts to knowing when the code in monaco editor has changed
21 |
22 | ### Sandbox
23 |
24 | The plugins are passed copies of the TypeScript sandbox, which is a high level API wrapper to the [`monaco-editor`](https://microsoft.github.io/monaco-editor/). You can learn more about the sandbox on [the TypeScript website](http://www.typescriptlang.org/v2/dev/sandbox/
25 |
26 | #### Rollup
27 |
28 | [Rollup](https://rollupjs.org) is a JavaScript bundler, that will take all of the TypeScript + JavaScript code you reference and then create an AMD bundle for it all. AMD bundles are used in Monaco, TypeScript Sandbox and the Playground - so, this is used for consistency with the rest of the ecosystem.
29 |
30 | #### Serve
31 |
32 | [Serve](https://github.com/zeit/serve) is used to make a web-server for the dist folder.
33 |
34 | ## Deployment
35 |
36 | This module should be deployed to npm when you would like the world to see it, this may mean making your code handle a staging vs production environment (because the URLs will be different.)
37 |
38 | For example, this is how you can handle getting the URL for a CSS file which is included in your `dist` folder:
39 |
40 | ```ts
41 | const isDev = document.location.host.includes('localhost')
42 | const unpkgURL = 'https://unpkg.com/typescript-playground-presentation-mode@latest/dist/slideshow.css'
43 | const cssHref = isDev ? 'http://localhost:5000/slideshow.css' : unpkgURL
44 | ```
45 |
46 | ### Post-Deploy
47 |
48 | Once this is deployed, you can test it on the TypeScript playground by passing in the name of your plugin on npm to the custom plugin box. This is effectively your staging environment.
49 |
50 | Once you're happy and it's polished, you can apply to have it in the default plugin list.
51 |
52 | ## Support
53 |
54 | Ask questions either on the TypeScript Website issues](https://github.com/microsoft/TypeScript-Website/issues), or in the [TypeScript Community Discord](https://discord.gg/typescript) - in the TypeScript Website channel.
55 |
--------------------------------------------------------------------------------
/src/svelte/App.svelte:
--------------------------------------------------------------------------------
1 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | {#each $markers as marker}
63 | Line {marker.startLineNumber}:
64 | {marker.message}
65 | {/each}
66 |
67 |
68 |
121 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import App from "./svelte/App.svelte";
3 | import { writable, readable, get } from "svelte/store";
4 | import { PluginUtils } from "./vendor/pluginUtils";
5 |
6 | export type FlashInfo = (message: string) => void;
7 |
8 | export type ShowModal = {
9 | (code: string, subtitle?: string, links?: string[]): void;
10 | };
11 |
12 | // });
13 | // return () => disposable.dispose();
14 |
15 | // Store Objects
16 | const __sandbox = writable({}); // Internal...for Markers
17 | const markers = readable([], set => {
18 | const sandbox = get(__sandbox);
19 | const disposable = sandbox.editor.onDidChangeModelDecorations(() => {
20 | const allMarkers = sandbox.monaco.editor
21 | .getModelMarkers({})
22 | .map((marker, index) => {
23 | return {
24 | ...marker,
25 | key: index.toString()
26 | };
27 | });
28 | set(allMarkers);
29 |
30 | return () => disposable.dispose();
31 | });
32 | });
33 | const model = writable({});
34 | const code = writable(""); // Has to be writable for the modelChanged events.
35 | const debounce = writable(true);
36 |
37 | function makePlugin(utils: PluginUtils) {
38 | const customPlugin: import("./vendor/playground").PlaygroundPlugin = {
39 | id: "svelte",
40 | displayName: "Svelte", // The tab label
41 | // willMount: (sandbox, container) => {
42 | // // Not used
43 | // },
44 | didMount: (sandbox, container) => {
45 | function useDebounce(opt: boolean = true) {
46 | debounce.set(opt);
47 | }
48 |
49 | function formatCode() {
50 | sandbox.editor.getAction("editor.action.formatDocument").run();
51 | }
52 |
53 | function setCode(userCode, options?: { format: boolean }) {
54 | sandbox.setText(userCode);
55 | if (options) {
56 | options.format && formatCode();
57 | }
58 | }
59 |
60 | const { flashInfo, showModal } = window.playground.ui;
61 |
62 | const props = {
63 | sandbox,
64 | container,
65 | useDebounce,
66 | setCode,
67 | formatCode,
68 | code,
69 | model,
70 | flashInfo,
71 | showModal,
72 | utils,
73 | markers
74 | };
75 |
76 | // Mount the app and pass in the store objects as props
77 | new App({
78 | target: container,
79 | props
80 | });
81 | },
82 | modelChanged: (sandbox, _model) => {
83 | if (!get(debounce)) {
84 | code.set(sandbox.getText());
85 | model.set(_model);
86 | __sandbox.set(sandbox);
87 | }
88 | },
89 | modelChangedDebounce(sandbox, _model) {
90 | if (get(debounce)) {
91 | code.set(sandbox.getText());
92 | model.set(_model);
93 | __sandbox.set(sandbox);
94 | }
95 | }
96 | // willUnmount: (sandbox, container) => {
97 | // // Not used
98 | // },
99 | // didUnmount: (sandbox, container) => {
100 | // // Not used
101 | // }
102 | };
103 | return customPlugin;
104 | }
105 |
106 | export default makePlugin;
107 |
--------------------------------------------------------------------------------
/src/vendor/tsWorker.d.ts:
--------------------------------------------------------------------------------
1 | import ts from 'typescript';
2 | export declare class TypeScriptWorker implements ts.LanguageServiceHost {
3 | private _ctx;
4 | private _extraLibs;
5 | private _languageService;
6 | private _compilerOptions;
7 | constructor(ctx: any, createData: any);
8 | getCompilationSettings(): ts.CompilerOptions;
9 | getScriptFileNames(): string[];
10 | private _getModel;
11 | getScriptVersion(fileName: string): string;
12 | getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined;
13 | getScriptKind?(fileName: string): ts.ScriptKind;
14 | getCurrentDirectory(): string;
15 | getDefaultLibFileName(options: ts.CompilerOptions): string;
16 | isDefaultLibFileName(fileName: string): boolean;
17 | private static clearFiles;
18 | getSyntacticDiagnostics(fileName: string): Promise;
19 | getSemanticDiagnostics(fileName: string): Promise;
20 | getSuggestionDiagnostics(fileName: string): Promise;
21 | getCompilerOptionsDiagnostics(fileName: string): Promise;
22 | getCompletionsAtPosition(fileName: string, position: number): Promise;
23 | getCompletionEntryDetails(fileName: string, position: number, entry: string): Promise;
24 | getSignatureHelpItems(fileName: string, position: number): Promise;
25 | getQuickInfoAtPosition(fileName: string, position: number): Promise;
26 | getOccurrencesAtPosition(fileName: string, position: number): Promise | undefined>;
27 | getDefinitionAtPosition(fileName: string, position: number): Promise | undefined>;
28 | getReferencesAtPosition(fileName: string, position: number): Promise;
29 | getNavigationBarItems(fileName: string): Promise;
30 | getFormattingEditsForDocument(fileName: string, options: ts.FormatCodeOptions): Promise;
31 | getFormattingEditsForRange(fileName: string, start: number, end: number, options: ts.FormatCodeOptions): Promise;
32 | getFormattingEditsAfterKeystroke(fileName: string, postion: number, ch: string, options: ts.FormatCodeOptions): Promise;
33 | findRenameLocations(fileName: string, positon: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename: boolean): Promise;
34 | getRenameInfo(fileName: string, positon: number, options: ts.RenameInfoOptions): Promise;
35 | getEmitOutput(fileName: string): Promise;
36 | getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: ts.FormatCodeOptions): Promise>;
37 | updateExtraLibs(extraLibs: IExtraLibs): void;
38 | }
39 | export interface IExtraLib {
40 | content: string;
41 | version: number;
42 | }
43 | export interface IExtraLibs {
44 | [path: string]: IExtraLib;
45 | }
46 |
--------------------------------------------------------------------------------
/src/vendor/typescript-vfs.d.ts:
--------------------------------------------------------------------------------
1 |
2 | declare type System = import('typescript').System;
3 | declare type CompilerOptions = import('typescript').CompilerOptions;
4 | declare type TS = typeof import('typescript');
5 | export interface VirtualTypeScriptEnvironment {
6 | sys: System;
7 | languageService: import('typescript').LanguageService;
8 | getSourceFile: (fileName: string) => import('typescript').SourceFile | undefined;
9 | createFile: (fileName: string, content: string) => void;
10 | updateFile: (fileName: string, content: string, replaceTextSpan?: import('typescript').TextSpan) => void;
11 | }
12 | /**
13 | * Makes a virtual copy of the TypeScript environment. This is the main API you want to be using with
14 | * typescript-vfs. A lot of the other exposed functions are used by this function to get set up.
15 | *
16 | * @param sys an object which conforms to the TS Sys (a shim over read/write access to the fs)
17 | * @param rootFiles a list of files which are considered inside the project
18 | * @param ts a copy pf the TypeScript module
19 | * @param compilerOptions the options for this compiler run
20 | */
21 | export declare function createVirtualTypeScriptEnvironment(sys: System, rootFiles: string[], ts: TS, compilerOptions?: CompilerOptions): VirtualTypeScriptEnvironment;
22 | /**
23 | * Grab the list of lib files for a particular target, will return a bit more than necessary (by including
24 | * the dom) but that's OK
25 | *
26 | * @param target The compiler settings target baseline
27 | * @param ts A copy of the TypeScript module
28 | */
29 | export declare const knownLibFilesForCompilerOptions: (compilerOptions: import("typescript").CompilerOptions, ts: typeof import("typescript")) => string[];
30 | /**
31 | * Sets up a Map with lib contents by grabbing the necessary files from
32 | * the local copy of typescript via the file system.
33 | */
34 | export declare const createDefaultMapFromNodeModules: (compilerOptions: import("typescript").CompilerOptions) => Map;
35 | /**
36 | * Create a virtual FS Map with the lib files from a particular TypeScript
37 | * version based on the target, Always includes dom ATM.
38 | *
39 | * @param options The compiler target, which dictates the libs to set up
40 | * @param version the versions of TypeScript which are supported
41 | * @param cache should the values be stored in local storage
42 | * @param ts a copy of the typescript import
43 | * @param lzstring an optional copy of the lz-string import
44 | * @param fetcher an optional replacement for the global fetch function (tests mainly)
45 | * @param storer an optional replacement for the localStorage global (tests mainly)
46 | */
47 | export declare const createDefaultMapFromCDN: (options: import("typescript").CompilerOptions, version: string, cache: boolean, ts: typeof import("typescript"), lzstring?: any | undefined, fetcher?: typeof fetch | undefined, storer?: Storage | undefined) => Promise