smartdown-gallery
Version:
Example Smartdown documents and associated resources that demonstrate various Smartdown features and serve as raw material for other Smartdown demos.
183 lines (125 loc) • 6.4 kB
Markdown
### TypeScript
As of Smartdown v1.0.20, the Smartdown engine is being reconstructed using [Typescript](). As of v1.0.21, Smartdown supports the dynamic compilation of Typescript in the browser via `typescript` playables.
References:
- [Using the Compiler API](https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API)
#### A Typescript Playable
For our first example, we'll create a little `typescript` playable that just listens for changes to the `Name` variable and adjusts its `div` content accordingly. We'll use the `/debug` qualifier on the playable to allow us to view the augmented code that will transpile typescript into javascript.
The source for this playable is encoded in Smartdown like this:
````markdown
```javascript /typescript/playable/autoplay/debug
// SOURCE goes here
```
````
with `// SOURCE goes here` being replaced by:
```javascript /typescript
const myDiv = this.div;
myDiv.style.background = 'lavender !important';
myDiv.style.color = 'magenta !important';
myDiv.style.padding = '10px 2px';
myDiv.style.margin = '10px 2px';
this.dependOn = ['Name'];
this.depend = function(): void {
const msg: string = ['Nice', 'to', 'meet', 'you'].join(' ');
myDiv.innerHTML = `<p>${msg}, <b>${env.Name}</b>!</p>`;
};
```
---
[What is your name?](:?Name)
```javascript /typescript/playable/autoplay/debug
const myDiv = this.div;
myDiv.style.background = 'lavender !important';
myDiv.style.color = 'magenta !important';
myDiv.style.padding = '10px 2px';
myDiv.style.margin = '10px 2px';
this.dependOn.Name = (): void => {
const msg: string = ['Nice', 'to', 'meet', 'you'].join(' ');
myDiv.innerHTML = `<p>${msg}, <b>${env.Name}</b>!</p>`;
};
```
#### Detecting source errors with the playable's console
The augmented code that Smartdown generates around Typescript to transpile it to Javascript has been recently (v1.0.24) improved so that syntax errors detected during transpilation are reported via the Smartdown per-playable console, which is a new feature (see [Javascript](:@Javascript)).
Let's give this feature a try by creating a TypeScript playable that is *syntactically* incorrect because it lacks a closing single quote on a string declaration. This playable is NOT autoplay, so you will need to click the `Play` button to see stuff happen:
```javascript /typescript/playable
const msg: string = 'I better not forget the closing quote...;
this.div.innerHTML = `<h1>${msg}</h1`;
```
Here's an example which is syntactically correct, but should fail Typescript's typechecking. Because Smartdown's usage of the Typescript transpiler **does not currently** use the typechecker, this playable will be transpiled successfully into Javascript.
```javascript /typescript/playable
const n: number = 'This is definitely NOT a number';
this.div.innerHTML = `<h1>n: ${n}</h1`;
```
#### Invoking the TypeScript Transpiler Explicitly
Before Smartdown had a proper `typescript` playable language type, I prototyped the capability by using an ordinary Javascript playable and then using `smartdown.import` to dynamically load the TypeScript compiler via the [jsDelivr]() CDN, followed by transpiling some example source and then generating a `Function` and invoking it with the current playable's context. For the most part, the following playable is patterned after the *augmented code* generated by Smartdown when processing a Typescript playable.
---
[String to uppercase](:?String)
[Uppercased String](:!StringUpper)
```javascript /playable
//smartdown.import=https://cdn.jsdelivr.net/npm/typescript/lib/typescript.min.js
const source =
`
this.dependOn = ['String'];
this.depend = function() {
const upper: string = env.String.toUpperCase();
smartdown.setVariable('StringUpper', upper);
}
`;
// https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#transpiling-a-single-file
// compilerOptions?: CompilerOptions;
// fileName?: string;
// reportDiagnostics?: boolean;
// moduleName?: string;
// renamedDependencies?: Map<string>;
let result = ts.transpileModule(source, {
compilerOptions: {
module: ts.ModuleKind.CommonJS,
target: 'es6',
allowJs: true,
checkJs: true,
},
reportDiagnostics: true,
});
if (result.diagnostics.length > 0) {
console.log('result.diagnostics');
console.log(result.diagnostics);
}
smartdown.runFunction(
result.outputText,
this,
[...arguments],
playable.language,
this.div);
```
##### Using `await` without a wrapper.
As of SD v1.0.25, Javascript playable sources are wrapped with an `async` function wrapper so that `await` can be used within the source of the playable. This is exercised in a [Javascript](:@Javascript) example, but let's make sure it works with TypeScript.
```javascript /typescript/playable
console.log('Hello from the typescript playable');
const response: any = await fetch('https://unpkg.com/smartdown/package.json');
const myJson: any = await response.json();
smartdown.setVariable('Package', myJson);
```
[package.json](:!Package|json)
##### ES6 Modules in Typescript
- https://stackoverflow.com/questions/53733138/how-do-i-type-check-a-snippet-of-typescript-code-in-memory
- https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API
Preliminary capability that allows a transpiled Typescript playable to execute as an ES6 Module by using the `/module` qualifier. As with ordinary Javascript ES6 Playables, you must implement a `start()` function which will receive a reference to the playable via `playable` and to the Smartdown variables via `env`. The signature for `start()` is still in flux, and we may implement a corresponding `stop()` hook.
*Possibly this should be moved to the [ES6](:@ES6) card, but it is here for now.*
---
[What is your name?](:?NameA)
```javascript /typescript/playable/debug/module
import * as Lib from './gallery/ExtensionsES6Module.js';
export default function start(playable, env) {
const log = this.log;
log('start', this, playable, env);
this.div.innerHTML = `<h1>Waiting for dependency</h1>`;
this.dependOn.NameA = () => {
smartdown.setVariable('NameB', env.NameA.toUpperCase());
this.div.innerHTML = `<h1>Hello from an ES6 Module A. ${env.NameA}</h1>`;
};
const nums = [12, 23, 34, 45];
log('sum', Lib.sum(...nums));
log('mult', Lib.mult(...nums));
Lib.note.note = 'ModuleA was here';
}
```
---
[Back to Home](:@Home)