diff --git a/.eleventy.js b/.eleventy.js index a399c0b..8cf5319 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -1,9 +1,3 @@ -// let markdown = require("markdown-it")({ -// html: true -// }).use(require('markdown-it-table-of-contents'), { -// includeLevel: [2, 3], // specify the heading levels to include in the TOC -// containerClass: 'md-toc', -// }).use(require('markdown-it-anchor'), {}) const path = require("path"); const { readFile } = require("fs/promises"); @@ -14,13 +8,12 @@ const md = markdownIt({ // const markdownItToc = require("markdown-it-table-of-contents"); module.exports = function(eleventyConfig) { - markdownTemplateEngine: "njk", - eleventyConfig.addPassthroughCopy("./src/pages/"); + eleventyConfig.addPassthroughCopy("./src/pages"); eleventyConfig.addPassthroughCopy("./src/style"); eleventyConfig.addPassthroughCopy("./src/images"); //eleventyConfig.addPlugin(require("libs/shikiji")); // eleventyConfig.addNunjucksShortcode( - // "markdown", + // "markdown", // content => { // const renderedContent = markdown.render(content); // const toc = renderedContent.match(/
[\s\S]*?<\/div>/); @@ -40,16 +33,16 @@ module.exports = function(eleventyConfig) { const highlighter = await getHighlighter({ langAlias: { kdl: "KDL" }, }); - const theme = JSON.parse(await readFile(path.join(__dirname, "dark_modern.json"), "utf8")); + const theme = JSON.parse(await readFile(path.join(__dirname, "github_light_default.json"), "utf8")); await highlighter.loadTheme(theme); await highlighter.loadLanguage("css", "js", "json", "shell", "tsx", "typescript"); md.use( fromHighlighter(highlighter, { - theme: "dark-modern", + theme: "github-light-default", transformers: [transformerNotationErrorLevel(), transformerNotationWordHighlight()], }), ); - + md.use(require("markdown-it-table-of-contents"), { includeLevel: [2, 3], containerClass: "md-toc", @@ -77,7 +70,7 @@ module.exports = function(eleventyConfig) { // }) // } // }); - + }); return { diff --git a/dist/JSProgrammers/index.html b/dist/JSProgrammers/index.html index 3a4eb34..a2dcfe2 100644 --- a/dist/JSProgrammers/index.html +++ b/dist/JSProgrammers/index.html @@ -19,110 +19,110 @@
-

TypeScript for JavaScript Programmers

+

TypeScript for JavaScript Programmers

TypeScript stands in an unusual relationship to JavaScript. TypeScript offers all of JavaScript's features, and an additional layer on top of these: TypeScript's type system.

For example, JavaScript provides language primitives like string and number, but it doesn't check that you've consistently assigned these. TypeScript does.

This means that your existing working JavaScript code is also TypeScript code. The main benefit of TypeScript is that it can highlight unexpected behavior in your code, lowering the chance of bugs.

This tutorial provides a brief overview of TypeScript, focusing on its type system.

-

Types by Inference

+

Types by Inference

TypeScript knows the JavaScript language and will generate types for you in many cases. For example in creating a variable and assigning it to a particular value, TypeScript will use the value as its type.

-
let helloWorld = "Hello World";
-//  ^?
-
+
let helloWorld = "Hello World";
+//  ^?
+

By understanding how JavaScript works, TypeScript can build a type-system that accepts JavaScript code but has types. This offers a type-system without needing to add extra characters to make types explicit in your code. That's how TypeScript knows that helloWorld is a string in the above example.

You may have written JavaScript in Visual Studio Code, and had editor auto-completion. Visual Studio Code uses TypeScript under the hood to make it easier to work with JavaScript.

-

Defining Types

+

Defining Types

You can use a wide variety of design patterns in JavaScript. However, some design patterns make it difficult for types to be inferred automatically (for example, patterns that use dynamic programming). To cover these cases, TypeScript supports an extension of the JavaScript language, which offers places for you to tell TypeScript what the types should be.

For example, to create an object with an inferred type which includes name: string and id: number, you can write:

-
const user = {
-  name: "Hayes", // [!code --]
-  id: 0,// [!code ++]
-};
-
+
const user = {
+  name: "Hayes", // [!code --]
+  id: 0,// [!code ++]
+};
+

You can explicitly describe this object's shape using an interface declaration:

-
interface User {
-  name: string;
-  id: number;
-}
-
+
interface User {
+  name: string;
+  id: number;
+}
+

You can then declare that a JavaScript object conforms to the shape of your new interface by using syntax like : TypeName after a variable declaration:

-
interface User {
-  name: string;
-  id: number;
-}
-// ---cut---
-const user: User = {
-  name: "Hayes",
-  id: 0,
-};
-
+
interface User {
+  name: string;
+  id: number;
+}
+// ---cut---
+const user: User = {
+  name: "Hayes",
+  id: 0,
+};
+

If you provide an object that doesn't match the interface you have provided, TypeScript will warn you:

-
// @errors: 2322
-interface User {
-  name: string;
-  id: number;
-}
-
-const user: User = {
-  username: "Hayes",  // [!code word:username]
-  id: 0,
-};
-
+
// @errors: 2322
+interface User {
+  name: string;
+  id: number;
+}
+
+const user: User = {
+  username: "Hayes",  
+  id: 0,
+};
+

Since JavaScript supports classes and object-oriented programming, so does TypeScript. You can use an interface declaration with classes:

-
interface User {
-  name: string;
-  id: number;
-}
-
-class UserAccount {
-  name: string;
-  id: number;
-
-  constructor(name: string, id: number) {
-    this.name = name;
-    this.id = id;
-  }
-}
-
-const user: User = new UserAccount("Murphy", 1);
-
+
interface User {
+  name: string;
+  id: number;
+}
+
+class UserAccount {
+  name: string;
+  id: number;
+
+  constructor(name: string, id: number) {
+    this.name = name;
+    this.id = id;
+  }
+}
+
+const user: User = new UserAccount("Murphy", 1);
+

You can use interfaces to annotate parameters and return values to functions:

-
// @noErrors
-interface User {
-  name: string;
-  id: number;
-}
-// ---cut---
-function deleteUser(user: User) {
-  // ...
-}
-
-function getAdminUser(): User {
-  //...
-}
-
+
// @noErrors
+interface User {
+  name: string;
+  id: number;
+}
+// ---cut---
+function deleteUser(user: User) {
+  // ...
+}
+
+function getAdminUser(): User {
+  //...
+}
+

There is already a small set of primitive types available in JavaScript: boolean, bigint, null, number, string, symbol, and undefined, which you can use in an interface. TypeScript extends this list with a few more, such as any (allow anything), unknown (ensure someone using this type declares what the type is), never (it's not possible that this type could happen), and void (a function which returns undefined or has no return value).

You'll see that there are two syntaxes for building types: Interfaces and Types. You should prefer interface. Use type when you need specific features.

-

Composing Types

+

Composing Types

With TypeScript, you can create complex types by combining simple ones. There are two popular ways to do so: with unions, and with generics.

-

Unions

+

Unions

With a union, you can declare that a type could be one of many types. For example, you can describe a boolean type as being either true or false:

-
type MyBool = true | false;
-
+
type MyBool = true | false;
+

Note: If you hover over MyBool above, you'll see that it is classed as boolean. That's a property of the Structural Type System. More on this below.

A popular use-case for union types is to describe the set of string or number literals that a value is allowed to be:

-
type WindowStates = "open" | "closed" | "minimized";
-type LockStates = "locked" | "unlocked";
-type PositiveOddNumbersUnderTen = 1 | 3 | 5 | 7 | 9;
-
+
type WindowStates = "open" | "closed" | "minimized";
+type LockStates = "locked" | "unlocked";
+type PositiveOddNumbersUnderTen = 1 | 3 | 5 | 7 | 9;
+

Unions provide a way to handle different types too. For example, you may have a function that takes an array or a string:

-
function getLength(obj: string | string[]) {
-  return obj.length;
-}
-
+
function getLength(obj: string | string[]) {
+  return obj.length;
+}
+

To learn the type of a variable, use typeof:

@@ -160,100 +160,100 @@

Unions

For example, you can make a function return different values depending on whether it is passed a string or an array:

-
function wrapInArray(obj: string | string[]) {
-  if (typeof obj === "string") {
-    return [obj];
-//          ^?
-  }
-  return obj;
-}
-
-

Generics

+
function wrapInArray(obj: string | string[]) {
+  if (typeof obj === "string") {
+    return [obj];
+//          ^?
+  }
+  return obj;
+}
+
+

Generics

Generics provide variables to types. A common example is an array. An array without generics could contain anything. An array with generics can describe the values that the array contains.

-
type StringArray = Array<string>;
-type NumberArray = Array<number>;
-type ObjectWithNameArray = Array<{ name: string }>;
-
+
type StringArray = Array<string>;
+type NumberArray = Array<number>;
+type ObjectWithNameArray = Array<{ name: string }>;
+

You can declare your own types that use generics:

-
// @errors: 2345
-interface Backpack<Type> {
-  add: (obj: Type) => void;
-  get: () => Type;
-}
-
-// This line is a shortcut to tell TypeScript there is a
-// constant called `backpack`, and to not worry about where it came from.
-declare const backpack: Backpack<string>;
-
-// object is a string, because we declared it above as the variable part of Backpack.
-const object = backpack.get();
-
-// Since the backpack variable is a string, you can't pass a number to the add function.
-backpack.add(23);
-
-

Structural Type System

+
// @errors: 2345
+interface Backpack<Type> {
+  add: (obj: Type) => void;
+  get: () => Type;
+}
+
+// This line is a shortcut to tell TypeScript there is a
+// constant called `backpack`, and to not worry about where it came from.
+declare const backpack: Backpack<string>;
+
+// object is a string, because we declared it above as the variable part of Backpack.
+const object = backpack.get();
+
+// Since the backpack variable is a string, you can't pass a number to the add function.
+backpack.add(23);
+
+

Structural Type System

One of TypeScript's core principles is that type checking focuses on the shape that values have. This is sometimes called "duck typing" or "structural typing".

In a structural type system, if two objects have the same shape, they are considered to be of the same type.

-
interface Point {
-  x: number;
-  y: number;
-}
-
-function logPoint(p: Point) {
-  console.log(`${p.x}, ${p.y}`);
-}
-
-// logs "12, 26"
-const point = { x: 12, y: 26 };
-logPoint(point);
-
+
interface Point {
+  x: number;
+  y: number;
+}
+
+function logPoint(p: Point) {
+  console.log(`${p.x}, ${p.y}`);
+}
+
+// logs "12, 26"
+const point = { x: 12, y: 26 };
+logPoint(point);
+

The point variable is never declared to be a Point type. However, TypeScript compares the shape of point to the shape of Point in the type-check. They have the same shape, so the code passes.

The shape-matching only requires a subset of the object's fields to match.

-
// @errors: 2345
-interface Point {
-  x: number;
-  y: number;
-}
-
-function logPoint(p: Point) {
-  console.log(`${p.x}, ${p.y}`);
-}
-// ---cut---
-const point3 = { x: 12, y: 26, z: 89 };
-logPoint(point3); // logs "12, 26"
-
-const rect = { x: 33, y: 3, width: 30, height: 80 };
-logPoint(rect); // logs "33, 3"
-
-const color = { hex: "#187ABF" };
-logPoint(color);
-
+
// @errors: 2345
+interface Point {
+  x: number;
+  y: number;
+}
+
+function logPoint(p: Point) {
+  console.log(`${p.x}, ${p.y}`);
+}
+// ---cut---
+const point3 = { x: 12, y: 26, z: 89 };
+logPoint(point3); // logs "12, 26"
+
+const rect = { x: 33, y: 3, width: 30, height: 80 };
+logPoint(rect); // logs "33, 3"
+
+const color = { hex: "#187ABF" };
+logPoint(color);
+

There is no difference between how classes and objects conform to shapes:

-
// @errors: 2345
-interface Point {
-  x: number;
-  y: number;
-}
-
-function logPoint(p: Point) {
-  console.log(`${p.x}, ${p.y}`);
-}
-// ---cut---
-class VirtualPoint {
-  x: number;
-  y: number;
-
-  constructor(x: number, y: number) {
-    this.x = x;
-    this.y = y;
-  }
-}
-
-const newVPoint = new VirtualPoint(13, 56);
-logPoint(newVPoint); // logs "13, 56"
-
+
// @errors: 2345
+interface Point {
+  x: number;
+  y: number;
+}
+
+function logPoint(p: Point) {
+  console.log(`${p.x}, ${p.y}`);
+}
+// ---cut---
+class VirtualPoint {
+  x: number;
+  y: number;
+
+  constructor(x: number, y: number) {
+    this.x = x;
+    this.y = y;
+  }
+}
+
+const newVPoint = new VirtualPoint(13, 56);
+logPoint(newVPoint); // logs "13, 56"
+

If the object or class has all the required properties, TypeScript will say they match, regardless of the implementation details.

-

Next Steps

+

Next Steps

This was a brief overview of the syntax and tools used in everyday TypeScript. From here, you can:

diff --git a/dist/NewProgrammer/index.html b/dist/NewProgrammer/index.html index 37be2ec..eb0e70e 100644 --- a/dist/NewProgrammer/index.html +++ b/dist/NewProgrammer/index.html @@ -19,13 +19,13 @@
-

TypeScript for the New Programmer

+

TypeScript for the New Programmer

Congratulations on choosing TypeScript as one of your first languages — you're already making good decisions!

You've probably already heard that TypeScript is a "flavor" or "variant" of JavaScript. The relationship between TypeScript (TS) and JavaScript (JS) is rather unique among modern programming languages, so learning more about this relationship will help you understand how TypeScript adds to JavaScript.

-

What is JavaScript? A Brief History

+

What is JavaScript? A Brief History

JavaScript (also known as ECMAScript) started its life as a simple scripting language for browsers. At the time it was invented, it was expected to be used for short snippets of code embedded in a web page — writing more than a few dozen lines of code would have been somewhat unusual. Due to this, early web browsers executed such code pretty slowly. @@ -41,64 +41,67 @@

What is JavaScript? A Brief History

  • JavaScript's equality operator (==) coerces its operands, leading to unexpected behavior:

    -
    if ("" == 0) {
    -  // It is! But why??
    -}
    -if (1 < x < 3) {
    -  // True for *any* value of x!
    -}
    -
    +
    if ("" == 0) {
    +  // It is! But why??
    +}
    +if (1 < x < 3) {
    +  // True for *any* value of x!
    +}
    +
  • JavaScript also allows accessing properties which aren't present:

    -
    const obj = { width: 10, height: 15 };
    -// Why is this NaN? Spelling is hard!
    -const area = obj.width * obj.heigth;
    -
    +
    const obj = { width: 10, height: 15 };
    +// Why is this NaN? Spelling is hard!
    +const area = obj.width * obj.heigth;
    +

Most programming languages would throw an error when these sorts of errors occur, some would do so during compilation — before any code is running. When writing small programs, such quirks are annoying but manageable; when writing applications with hundreds or thousands of lines of code, these constant surprises are a serious problem.

-

TypeScript: A Static Type Checker

+

TypeScript: A Static Type Checker

We said earlier that some languages wouldn't allow those buggy programs to run at all. Detecting errors in code without running it is referred to as static checking. Determining what's an error and what's not based on the kinds of values being operated on is known as static type checking.

TypeScript checks a program for errors before execution, and does so based on the kinds of values, making it a static type checker. For example, the last example above has an error because of the type of obj. Here's the error TypeScript found:

-
// @errors: 2551
-const obj = { width: 10, height: 15 };
-const area = obj.width * obj.heigth;
-
-

A Typed Superset of JavaScript

+
const obj = { width: 10, height: 15 };
+const area = obj.width * obj.heigth;
+Property 'heigth' does not exist on type '{ width: number; height: number; }'. Did you mean 'height'?
+
+
+

A Typed Superset of JavaScript

How does TypeScript relate to JavaScript, though?

-

Syntax

+

Syntax

TypeScript is a language that is a superset of JavaScript: JS syntax is therefore legal TS. Syntax refers to the way we write text to form a program. For example, this code has a syntax error because it's missing a ):

-
// @errors: 1005
-let a = (4
-
+
// @errors: 1005
+let a = (4
+')' expected 
+
+

TypeScript doesn't consider any JavaScript code to be an error because of its syntax. This means you can take any working JavaScript code and put it in a TypeScript file without worrying about exactly how it is written.

-

Types

+

Types

However, TypeScript is a typed superset, meaning that it adds rules about how different kinds of values can be used. The earlier error about obj.heigth was not a syntax error: it is an error of using some kind of value (a type) in an incorrect way.

As another example, this is JavaScript code that you can run in your browser, and it will log a value:

-
console.log(4 / []);
-
+
console.log(4 / []);
+

This syntactically-legal program logs Infinity. TypeScript, though, considers division of number by an array to be a nonsensical operation, and will issue an error:

-
// @errors: 2363
-console.log(4 / []);
-
+
// @errors: 2363
+console.log(4 / []);
+

It's possible you really did intend to divide a number by an array, perhaps just to see what happens, but most of the time, though, this is a programming mistake. TypeScript's type checker is designed to allow correct programs through while still catching as many common errors as possible. (Later, we'll learn about settings you can use to configure how strictly TypeScript checks your code.)

If you move some code from a JavaScript file to a TypeScript file, you might see type errors depending on how the code is written. These may be legitimate problems with the code, or TypeScript being overly conservative. Throughout this guide we'll demonstrate how to add various TypeScript syntax to eliminate such errors.

-

Runtime Behavior

+

Runtime Behavior

TypeScript is also a programming language that preserves the runtime behavior of JavaScript. For example, dividing by zero in JavaScript produces Infinity instead of throwing a runtime exception. As a principle, TypeScript never changes the runtime behavior of JavaScript code.

@@ -109,7 +112,7 @@

Runtime Behavior

specification. (Since the immediately preceding text was raving about how JS code can be used in TS.) --> -

Erased Types

+

Erased Types

Roughly speaking, once TypeScript's compiler is done with checking your code, it erases the types to produce the resulting "compiled" code. This means that once your code is compiled, the resulting plain JS code has no type information.

This also means that TypeScript never changes the behavior of your program based on the types it inferred. @@ -123,7 +126,7 @@

Erased Types

with an example --- something like `?.` would be good in showing readers that this document is maintained.) --> -

Learning JavaScript and TypeScript

+

Learning JavaScript and TypeScript

We frequently see the question "Should I learn JavaScript or TypeScript?".

The answer is that you can't learn TypeScript without learning JavaScript! TypeScript shares syntax and runtime behavior with JavaScript, so anything you learn about JavaScript is helping you learn TypeScript at the same time.

@@ -132,7 +135,7 @@

Learning JavaScript and TypeScript

If you find yourself searching for something like "how to sort a list in TypeScript", remember: TypeScript is JavaScript's runtime with a compile-time type checker. The way you sort a list in TypeScript is the same way you do so in JavaScript. If you find a resource that uses TypeScript directly, that's great too, but don't limit yourself to thinking you need TypeScript-specific answers for everyday questions about how to accomplish runtime tasks.

-

Next Steps

+

Next Steps

This was a brief overview of the syntax and tools used in everyday TypeScript. From here, you can:

  • @@ -173,7 +176,7 @@

    Next Steps

diff --git a/dist/TS for Functional Programmers/index.html b/dist/TS for Functional Programmers/index.html index 37e057f..2adeaac 100644 --- a/dist/TS for Functional Programmers/index.html +++ b/dist/TS for Functional Programmers/index.html @@ -19,7 +19,7 @@
-

TypeScript for Functional Programmers

+

TypeScript for Functional Programmers

TypeScript began its life as an attempt to bring traditional object-oriented types @@ -35,7 +35,7 @@

This introduction does not cover object-oriented programming. In practice, object-oriented programs in TypeScript are similar to those in other popular languages with OO features.

-

Prerequisites

+

Prerequisites

In this introduction, I assume you know the following:

  • How to program in JavaScript, the good parts.
  • @@ -50,8 +50,8 @@

    Prerequisites

    The C++ Programming Language is a good place to learn about C-style type syntax. Unlike C++, TypeScript uses postfix types, like so: x: string instead of string x.

    -

    Concepts not in Haskell

    -

    Built-in types

    +

    Concepts not in Haskell

    +

    Built-in types

    JavaScript defines 8 built-in types:

    @@ -107,7 +107,7 @@

    Built-in types

  • undefined
  • object
  • -

    Other important TypeScript types

    +

    Other important TypeScript types

    @@ -150,63 +150,63 @@

    Other important TypeScript types

    1. Function syntax includes parameter names. This is pretty hard to get used to!

      -
      let fst: (a: any, b: any) => any = (a, b) => a;
      -
      -// or more precisely:
      -
      -let fst: <T, U>(a: T, b: U) => T = (a, b) => a;
      -
      +
      let fst: (a: any, b: any) => any = (a, b) => a;
      +
      +// or more precisely:
      +
      +let fst: <T, U>(a: T, b: U) => T = (a, b) => a;
      +
    2. Object literal type syntax closely mirrors object literal value syntax:

      -
      let o: { n: number; xs: object[] } = { n: 1, xs: [] };
      -
      +
      let o: { n: number; xs: object[] } = { n: 1, xs: [] };
      +
    3. [T, T] is a subtype of T[]. This is different than Haskell, where tuples are not related to lists.

    -

    Boxed types

    +

    Boxed types

    JavaScript has boxed equivalents of primitive types that contain the methods that programmers associate with those types. TypeScript reflects this with, for example, the difference between the primitive type number and the boxed type Number. The boxed types are rarely needed, since their methods return primitives.

    -
    (1).toExponential();
    -// equivalent to
    -Number.prototype.toExponential.call(1);
    -
    +
    (1).toExponential();
    +// equivalent to
    +Number.prototype.toExponential.call(1);
    +

    Note that calling a method on a numeric literal requires it to be in parentheses to aid the parser.

    -

    Gradual typing

    +

    Gradual typing

    TypeScript uses the type any whenever it can't tell what the type of an expression should be. Compared to Dynamic, calling any a type is an overstatement. It just turns off the type checker wherever it appears. For example, you can push any value into an any[] without marking the value in any way:

    -
    // with "noImplicitAny": false in tsconfig.json, anys: any[]
    -const anys = [];
    -anys.push(1);
    -anys.push("oh no");
    -anys.push({ anything: "goes" });
    -
    +
    // with "noImplicitAny": false in tsconfig.json, anys: any[]
    +const anys = [];
    +anys.push(1);
    +anys.push("oh no");
    +anys.push({ anything: "goes" });
    +

    And you can use an expression of type any anywhere:

    -
    anys.map(anys[1]); // oh no, "oh no" is not a function
    -
    +
    anys.map(anys[1]); // oh no, "oh no" is not a function
    +

    any is contagious, too — if you initialize a variable with an expression of type any, the variable has type any too.

    -
    let sepsis = anys[0] + anys[1]; // this could mean anything
    -
    +
    let sepsis = anys[0] + anys[1]; // this could mean anything
    +

    To get an error when TypeScript produces an any, use "noImplicitAny": true, or "strict": true in tsconfig.json.

    -

    Structural typing

    +

    Structural typing

    Structural typing is a familiar concept to most functional programmers, although Haskell and most MLs are not structurally typed. Its basic form is pretty simple:

    -
    // @strict: false
    -let o = { x: "hi", extra: 1 }; // ok
    -let o2: { x: string } = o; // ok
    -
    +
    // @strict: false
    +let o = { x: "hi", extra: 1 }; // ok
    +let o2: { x: string } = o; // ok
    +

    Here, the object literal { x: "hi", extra: 1 } has a matching literal type { x: string, extra: number }. That type is assignable to { x: string } since @@ -218,43 +218,43 @@

    Structural typing

    type Two below. They both have a property p: string. (Type aliases behave differently from interfaces with respect to recursive definitions and type parameters, however.)

    -
    // @errors: 2322
    -type One = { p: string };
    -interface Two {
    -  p: string;
    -}
    -class Three {
    -  p = "Hello";
    -}
    -
    -let x: One = { p: "hi" };
    -let two: Two = x;
    -two = new Three();
    -
    -

    Unions

    +
    // @errors: 2322
    +type One = { p: string };
    +interface Two {
    +  p: string;
    +}
    +class Three {
    +  p = "Hello";
    +}
    +
    +let x: One = { p: "hi" };
    +let two: Two = x;
    +two = new Three();
    +
    +

    Unions

    In TypeScript, union types are untagged. In other words, they are not discriminated unions like data in Haskell. However, you can often discriminate types in a union using built-in tags or other properties.

    -
    function start(
    -  arg: string | string[] | (() => string) | { s: string }
    -): string {
    -  // this is super common in JavaScript
    -  if (typeof arg === "string") {
    -    return commonCase(arg);
    -  } else if (Array.isArray(arg)) {
    -    return arg.map(commonCase).join(",");
    -  } else if (typeof arg === "function") {
    -    return commonCase(arg());
    -  } else {
    -    return commonCase(arg.s);
    -  }
    -
    -  function commonCase(s: string): string {
    -    // finally, just convert a string to another string
    -    return s;
    -  }
    -}
    -
    +
    function start(
    +  arg: string | string[] | (() => string) | { s: string }
    +): string {
    +  // this is super common in JavaScript
    +  if (typeof arg === "string") {
    +    return commonCase(arg);
    +  } else if (Array.isArray(arg)) {
    +    return arg.map(commonCase).join(",");
    +  } else if (typeof arg === "function") {
    +    return commonCase(arg());
    +  } else {
    +    return commonCase(arg.s);
    +  }
    +
    +  function commonCase(s: string): string {
    +    // finally, just convert a string to another string
    +    return s;
    +  }
    +}
    +

    string, Array and Function have built-in type predicates, conveniently leaving the object type for the else branch. It is possible, however, to generate unions that are difficult to @@ -309,33 +309,33 @@

    Unions

    Note that functions and arrays are objects at runtime, but have their own predicates.

    -

    Intersections

    +

    Intersections

    In addition to unions, TypeScript also has intersections:

    -
    type Combined = { a: number } & { b: string };
    -type Conflicting = { a: number } & { a: string };
    -
    +
    type Combined = { a: number } & { b: string };
    +type Conflicting = { a: number } & { a: string };
    +

    Combined has two properties, a and b, just as if they had been written as one object literal type. Intersection and union are recursive in case of conflicts, so Conflicting.a: number & string.

    -

    Unit types

    +

    Unit types

    Unit types are subtypes of primitive types that contain exactly one primitive value. For example, the string "foo" has the type "foo". Since JavaScript has no built-in enums, it is common to use a set of well-known strings instead. Unions of string literal types allow TypeScript to type this pattern:

    -
    declare function pad(s: string, n: number, direction: "left" | "right"): string;
    -pad("hi", 10, "left");
    -
    +
    declare function pad(s: string, n: number, direction: "left" | "right"): string;
    +pad("hi", 10, "left");
    +

    When needed, the compiler widens — converts to a supertype — the unit type to the primitive type, such as "foo" to string. This happens when using mutability, which can hamper some uses of mutable variables:

    -
    // @errors: 2345
    -declare function pad(s: string, n: number, direction: "left" | "right"): string;
    -// ---cut---
    -let s = "right";
    -pad("hi", 10, s); // error: 'string' is not assignable to '"left" | "right"'
    -
    +
    // @errors: 2345
    +declare function pad(s: string, n: number, direction: "left" | "right"): string;
    +// ---cut---
    +let s = "right";
    +pad("hi", 10, s); // error: 'string' is not assignable to '"left" | "right"'
    +

    Here's how the error happens:

    • "right": "right"
    • @@ -345,22 +345,22 @@

      Unit types

      You can work around this with a type annotation for s, but that in turn prevents assignments to s of variables that are not of type "left" | "right".

      -
      declare function pad(s: string, n: number, direction: "left" | "right"): string;
      -// ---cut---
      -let s: "left" | "right" = "right";
      -pad("hi", 10, s);
      -
      -

      Concepts similar to Haskell

      -

      Contextual typing

      +
      declare function pad(s: string, n: number, direction: "left" | "right"): string;
      +// ---cut---
      +let s: "left" | "right" = "right";
      +pad("hi", 10, s);
      +
      +

      Concepts similar to Haskell

      +

      Contextual typing

      TypeScript has some obvious places where it can infer types, like variable declarations:

      -
      let s = "I'm a string!";
      -
      +
      let s = "I'm a string!";
      +

      But it also infers types in a few other places that you may not expect if you've worked with other C-syntax languages:

      -
      declare function map<T, U>(f: (t: T) => U, ts: T[]): U[];
      -let sns = map((n) => n.toString(), [1, 2, 3]);
      -
      +
      declare function map<T, U>(f: (t: T) => U, ts: T[]): U[];
      +let sns = map((n) => n.toString(), [1, 2, 3]);
      +

      Here, n: number in this example also, despite the fact that T and U have not been inferred before the call. In fact, after [1,2,3] has been used to infer T=number, the return type of n => n.toString() @@ -369,16 +369,16 @@

      Contextual typing

      Note that inference will work in any order, but intellisense will only work left-to-right, so TypeScript prefers to declare map with the array first:

      -
      declare function map<T, U>(ts: T[], f: (t: T) => U): U[];
      -
      +
      declare function map<T, U>(ts: T[], f: (t: T) => U): U[];
      +

      Contextual typing also works recursively through object literals, and on unit types that would otherwise be inferred as string or number. And it can infer return types from context:

      -
      declare function run<T>(thunk: (t: T) => void): T;
      -let i: { inference: string } = run((o) => {
      -  o.inference = "INSERT STATE HERE";
      -});
      -
      +
      declare function run<T>(thunk: (t: T) => void): T;
      +let i: { inference: string } = run((o) => {
      +  o.inference = "INSERT STATE HERE";
      +});
      +

      The type of o is determined to be { inference: string } because

      1. Declaration initializers are contextually typed by the @@ -393,81 +393,81 @@

        Contextual typing

        properties you'd have in a real program. Altogether, this feature can make TypeScript's inference look a bit like a unifying type inference engine, but it is not.

        -

        Type aliases

        +

        Type aliases

        Type aliases are mere aliases, just like type in Haskell. The compiler will attempt to use the alias name wherever it was used in the source code, but does not always succeed.

        -
        type Size = [number, number];
        -let x: Size = [101.1, 999.9];
        -
        +
        type Size = [number, number];
        +let x: Size = [101.1, 999.9];
        +

        The closest equivalent to newtype is a tagged intersection:

        -
        type FString = string & { __compileTimeOnly: any };
        -
        +
        type FString = string & { __compileTimeOnly: any };
        +

        An FString is just like a normal string, except that the compiler thinks it has a property named __compileTimeOnly that doesn't actually exist. This means that FString can still be assigned to string, but not the other way round.

        -

        Discriminated Unions

        +

        Discriminated Unions

        The closest equivalent to data is a union of types with discriminant properties, normally called discriminated unions in TypeScript:

        -
        type Shape =
        -  | { kind: "circle"; radius: number }
        -  | { kind: "square"; x: number }
        -  | { kind: "triangle"; x: number; y: number };
        -
        +
        type Shape =
        +  | { kind: "circle"; radius: number }
        +  | { kind: "square"; x: number }
        +  | { kind: "triangle"; x: number; y: number };
        +

        Unlike Haskell, the tag, or discriminant, is just a property in each object type. Each variant has an identical property with a different unit type. This is still a normal union type; the leading | is an optional part of the union type syntax. You can discriminate the members of the union using normal JavaScript code:

        -
        type Shape =
        -  | { kind: "circle"; radius: number }
        -  | { kind: "square"; x: number }
        -  | { kind: "triangle"; x: number; y: number };
        -
        -function area(s: Shape) {
        -  if (s.kind === "circle") {
        -    return Math.PI * s.radius * s.radius;
        -  } else if (s.kind === "square") {
        -    return s.x * s.x;
        -  } else {
        -    return (s.x * s.y) / 2;
        -  }
        -}
        -
        +
        type Shape =
        +  | { kind: "circle"; radius: number }
        +  | { kind: "square"; x: number }
        +  | { kind: "triangle"; x: number; y: number };
        +
        +function area(s: Shape) {
        +  if (s.kind === "circle") {
        +    return Math.PI * s.radius * s.radius;
        +  } else if (s.kind === "square") {
        +    return s.x * s.x;
        +  } else {
        +    return (s.x * s.y) / 2;
        +  }
        +}
        +

        Note that the return type of area is inferred to be number because TypeScript knows the function is total. If some variant is not covered, the return type of area will be number | undefined instead.

        Also, unlike Haskell, common properties show up in any union, so you can usefully discriminate multiple members of the union:

        -
        type Shape =
        -  | { kind: "circle"; radius: number }
        -  | { kind: "square"; x: number }
        -  | { kind: "triangle"; x: number; y: number };
        -// ---cut---
        -function height(s: Shape) {
        -  if (s.kind === "circle") {
        -    return 2 * s.radius;
        -  } else {
        -    // s.kind: "square" | "triangle"
        -    return s.x;
        -  }
        -}
        -
        -

        Type Parameters

        +
        type Shape =
        +  | { kind: "circle"; radius: number }
        +  | { kind: "square"; x: number }
        +  | { kind: "triangle"; x: number; y: number };
        +// ---cut---
        +function height(s: Shape) {
        +  if (s.kind === "circle") {
        +    return 2 * s.radius;
        +  } else {
        +    // s.kind: "square" | "triangle"
        +    return s.x;
        +  }
        +}
        +
        +

        Type Parameters

        Like most C-descended languages, TypeScript requires declaration of type parameters:

        -
        function liftArray<T>(t: T): Array<T> {
        -  return [t];
        -}
        -
        +
        function liftArray<T>(t: T): Array<T> {
        +  return [t];
        +}
        +

        There is no case requirement, but type parameters are conventionally single uppercase letters. Type parameters can also be constrained to a type, which behaves a bit like type class constraints:

        -
        function firstish<T extends { length: number }>(t1: T, t2: T): T {
        -  return t1.length > t2.length ? t1 : t2;
        -}
        -
        +
        function firstish<T extends { length: number }>(t1: T, t2: T): T {
        +  return t1.length > t2.length ? t1 : t2;
        +}
        +

        TypeScript can usually infer type arguments from a call based on the type of the arguments, so type arguments are usually not needed.

        Because TypeScript is structural, it doesn't need type parameters as @@ -475,89 +475,89 @@

        Type Parameters

        function polymorphic. Type parameters should only be used to propagate type information, such as constraining parameters to be the same type:

        -
        function length<T extends ArrayLike<unknown>>(t: T): number {}
        -
        -function length(t: ArrayLike<unknown>): number {}
        -
        +
        function length<T extends ArrayLike<unknown>>(t: T): number {}
        +
        +function length(t: ArrayLike<unknown>): number {}
        +

        In the first length, T is not necessary; notice that it's only referenced once, so it's not being used to constrain the type of the return value or other parameters.

        -

        Higher-kinded types

        +

        Higher-kinded types

        TypeScript does not have higher kinded types, so the following is not legal:

        -
        function length<T extends ArrayLike<unknown>, U>(m: T<U>) {}
        -
        -

        Point-free programming

        +
        function length<T extends ArrayLike<unknown>, U>(m: T<U>) {}
        +
        +

        Point-free programming

        Point-free programming — heavy use of currying and function composition — is possible in JavaScript, but can be verbose. In TypeScript, type inference often fails for point-free programs, so you'll end up specifying type parameters instead of value parameters. The result is so verbose that it's usually better to avoid point-free programming.

        -

        Module system

        +

        Module system

        JavaScript's modern module syntax is a bit like Haskell's, except that any file with import or export is implicitly a module:

        -
        import { value, Type } from "npm-package";
        -import { other, Types } from "./local-package";
        -import * as prefix from "../lib/third-package";
        -
        +
        import { value, Type } from "npm-package";
        +import { other, Types } from "./local-package";
        +import * as prefix from "../lib/third-package";
        +

        You can also import commonjs modules — modules written using node.js' module system:

        -
        import f = require("single-function-package");
        -
        +
        import f = require("single-function-package");
        +

        You can export with an export list:

        -
        export { f };
        -
        -function f() {
        -  return g();
        -}
        -function g() {} // g is not exported
        -
        +
        export { f };
        +
        +function f() {
        +  return g();
        +}
        +function g() {} // g is not exported
        +

        Or by marking each export individually:

        -
        export function f() { return g() }
        -function g() { }
        -
        +
        export function f() { return g() }
        +function g() { }
        +

        The latter style is more common but both are allowed, even in the same file.

        -

        readonly and const

        +

        readonly and const

        In JavaScript, mutability is the default, although it allows variable declarations with const to declare that the reference is immutable. The referent is still mutable:

        -
        const a = [1, 2, 3];
        -a.push(102); // ):
        -a[0] = 101; // D:
        -
        +
        const a = [1, 2, 3];
        +a.push(102); // ):
        +a[0] = 101; // D:
        +

        TypeScript additionally has a readonly modifier for properties.

        -
        interface Rx {
        -  readonly x: number;
        -}
        -let rx: Rx = { x: 1 };
        -rx.x = 12; // error
        -
        +
        interface Rx {
        +  readonly x: number;
        +}
        +let rx: Rx = { x: 1 };
        +rx.x = 12; // error
        +

        It also ships with a mapped type Readonly<T> that makes all properties readonly:

        -
        interface X {
        -  x: number;
        -}
        -let rx: Readonly<X> = { x: 1 };
        -rx.x = 12; // error
        -
        +
        interface X {
        +  x: number;
        +}
        +let rx: Readonly<X> = { x: 1 };
        +rx.x = 12; // error
        +

        And it has a specific ReadonlyArray<T> type that removes side-affecting methods and prevents writing to indices of the array, as well as special syntax for this type:

        -
        let a: ReadonlyArray<number> = [1, 2, 3];
        -let b: readonly number[] = [1, 2, 3];
        -a.push(102); // error
        -b[0] = 101; // error
        -
        +
        let a: ReadonlyArray<number> = [1, 2, 3];
        +let b: readonly number[] = [1, 2, 3];
        +a.push(102); // error
        +b[0] = 101; // error
        +

        You can also use a const-assertion, which operates on arrays and object literals:

        -
        let a = [1, 2, 3] as const;
        -a.push(102); // error
        -a[0] = 101; // error
        -
        +
        let a = [1, 2, 3] as const;
        +a.push(102); // error
        +a[0] = 101; // error
        +

        However, none of these options are the default, so they are not consistently used in TypeScript code.

        -

        Next Steps

        +

        Next Steps

        This doc is a high level overview of the syntax and types you would use in everyday code. From here you should:

diff --git a/dist/TS for OOPers/index.html b/dist/TS for OOPers/index.html index f807ede..7c18019 100644 --- a/dist/TS for OOPers/index.html +++ b/dist/TS for OOPers/index.html @@ -19,108 +19,108 @@
-

TypeScript for Java/C# Programmers

+

TypeScript for Java/C# Programmers

TypeScript stands in an unusual relationship to JavaScript. TypeScript offers all of JavaScript's features, and an additional layer on top of these: TypeScript's type system.

For example, JavaScript provides language primitives like string and number, but it doesn't check that you've consistently assigned these. TypeScript does.

This means that your existing working JavaScript code is also TypeScript code. The main benefit of TypeScript is that it can highlight unexpected behavior in your code, lowering the chance of bugs.

This tutorial provides a brief overview of TypeScript, focusing on its type system.

-

Types by Inference

+

Types by Inference

TypeScript knows the JavaScript language and will generate types for you in many cases. For example in creating a variable and assigning it to a particular value, TypeScript will use the value as its type.

-
let helloWorld = "Hello World";
-//  ^?
-
+
let helloWorld = "Hello World";
+//  ^?
+

By understanding how JavaScript works, TypeScript can build a type-system that accepts JavaScript code but has types. This offers a type-system without needing to add extra characters to make types explicit in your code. That's how TypeScript knows that helloWorld is a string in the above example.

You may have written JavaScript in Visual Studio Code, and had editor auto-completion. Visual Studio Code uses TypeScript under the hood to make it easier to work with JavaScript.

-

Defining Types

+

Defining Types

You can use a wide variety of design patterns in JavaScript. However, some design patterns make it difficult for types to be inferred automatically (for example, patterns that use dynamic programming). To cover these cases, TypeScript supports an extension of the JavaScript language, which offers places for you to tell TypeScript what the types should be.

For example, to create an object with an inferred type which includes name: string and id: number, you can write:

-
const user = {
-  name: "Hayes",
-  id: 0,
-};
-
+
const user = {
+  name: "Hayes",
+  id: 0,
+};
+

You can explicitly describe this object's shape using an interface declaration:

-
interface User {
-  name: string;
-  id: number;
-}
-
+
interface User {
+  name: string;
+  id: number;
+}
+

You can then declare that a JavaScript object conforms to the shape of your new interface by using syntax like : TypeName after a variable declaration:

-
interface User {
-  name: string;
-  id: number;
-}
-// ---cut---
-const user: User = {
-  name: "Hayes",
-  id: 0,
-};
-
+
interface User {
+  name: string;
+  id: number;
+}
+// ---cut---
+const user: User = {
+  name: "Hayes",
+  id: 0,
+};
+

If you provide an object that doesn't match the interface you have provided, TypeScript will warn you:

-
// @errors: 2322
-interface User {
-  name: string;
-  id: number;
-}
-
-const user: User = {
-  username: "Hayes",
-  id: 0,
-};
-
+
// @errors: 2322
+interface User {
+  name: string;
+  id: number;
+}
+
+const user: User = {
+  username: "Hayes",
+  id: 0,
+};
+

Since JavaScript supports classes and object-oriented programming, so does TypeScript. You can use an interface declaration with classes:

-
interface User {
-  name: string;
-  id: number;
-}
-
-class UserAccount {
-  name: string;
-  id: number;
-
-  constructor(name: string, id: number) {
-    this.name = name;
-    this.id = id;
-  }
-}
-
-const user: User = new UserAccount("Murphy", 1);
-
+
interface User {
+  name: string;
+  id: number;
+}
+
+class UserAccount {
+  name: string;
+  id: number;
+
+  constructor(name: string, id: number) {
+    this.name = name;
+    this.id = id;
+  }
+}
+
+const user: User = new UserAccount("Murphy", 1);
+

You can use interfaces to annotate parameters and return values to functions:

-
// @noErrors
-interface User {
-  name: string;
-  id: number;
-}
-// ---cut---
-function deleteUser(user: User) {
-  // ...
-}
-
-function getAdminUser(): User {
-  //...
-}
-
+
// @noErrors
+interface User {
+  name: string;
+  id: number;
+}
+// ---cut---
+function deleteUser(user: User) {
+  // ...
+}
+
+function getAdminUser(): User {
+  //...
+}
+

There is already a small set of primitive types available in JavaScript: boolean, bigint, null, number, string, symbol, and undefined, which you can use in an interface. TypeScript extends this list with a few more, such as any (allow anything), unknown (ensure someone using this type declares what the type is), never (it's not possible that this type could happen), and void (a function which returns undefined or has no return value).

You'll see that there are two syntaxes for building types: Interfaces and Types. You should prefer interface. Use type when you need specific features.

-

Composing Types

+

Composing Types

With TypeScript, you can create complex types by combining simple ones. There are two popular ways to do so: with unions, and with generics.

-

Unions

+

Unions

With a union, you can declare that a type could be one of many types. For example, you can describe a boolean type as being either true or false:

-
type MyBool = true | false;
-
+
type MyBool = true | false;
+

Note: If you hover over MyBool above, you'll see that it is classed as boolean. That's a property of the Structural Type System. More on this below.

A popular use-case for union types is to describe the set of string or number literals that a value is allowed to be:

-
type WindowStates = "open" | "closed" | "minimized";
-type LockStates = "locked" | "unlocked";
-type PositiveOddNumbersUnderTen = 1 | 3 | 5 | 7 | 9;
-
+
type WindowStates = "open" | "closed" | "minimized";
+type LockStates = "locked" | "unlocked";
+type PositiveOddNumbersUnderTen = 1 | 3 | 5 | 7 | 9;
+

Unions provide a way to handle different types too. For example, you may have a function that takes an array or a string:

-
function getLength(obj: string | string[]) {
-  return obj.length;
-}
-
+
function getLength(obj: string | string[]) {
+  return obj.length;
+}
+

To learn the type of a variable, use typeof:

@@ -158,100 +158,100 @@

Unions

For example, you can make a function return different values depending on whether it is passed a string or an array:

-
function wrapInArray(obj: string | string[]) {
-  if (typeof obj === "string") {
-    return [obj];
-//          ^?
-  }
-  return obj;
-}
-
-

Generics

+
function wrapInArray(obj: string | string[]) {
+  if (typeof obj === "string") {
+    return [obj];
+//          ^?
+  }
+  return obj;
+}
+
+

Generics

Generics provide variables to types. A common example is an array. An array without generics could contain anything. An array with generics can describe the values that the array contains.

-
type StringArray = Array<string>;
-type NumberArray = Array<number>;
-type ObjectWithNameArray = Array<{ name: string }>;
-
+
type StringArray = Array<string>;
+type NumberArray = Array<number>;
+type ObjectWithNameArray = Array<{ name: string }>;
+

You can declare your own types that use generics:

-
// @errors: 2345
-interface Backpack<Type> {
-  add: (obj: Type) => void;
-  get: () => Type;
-}
-
-// This line is a shortcut to tell TypeScript there is a
-// constant called `backpack`, and to not worry about where it came from.
-declare const backpack: Backpack<string>;
-
-// object is a string, because we declared it above as the variable part of Backpack.
-const object = backpack.get();
-
-// Since the backpack variable is a string, you can't pass a number to the add function.
-backpack.add(23);
-
-

Structural Type System

+
// @errors: 2345
+interface Backpack<Type> {
+  add: (obj: Type) => void;
+  get: () => Type;
+}
+
+// This line is a shortcut to tell TypeScript there is a
+// constant called `backpack`, and to not worry about where it came from.
+declare const backpack: Backpack<string>;
+
+// object is a string, because we declared it above as the variable part of Backpack.
+const object = backpack.get();
+
+// Since the backpack variable is a string, you can't pass a number to the add function.
+backpack.add(23);
+
+

Structural Type System

One of TypeScript's core principles is that type checking focuses on the shape that values have. This is sometimes called "duck typing" or "structural typing".

In a structural type system, if two objects have the same shape, they are considered to be of the same type.

-
interface Point {
-  x: number;
-  y: number;
-}
-
-function logPoint(p: Point) {
-  console.log(`${p.x}, ${p.y}`);
-}
-
-// logs "12, 26"
-const point = { x: 12, y: 26 };
-logPoint(point);
-
+
interface Point {
+  x: number;
+  y: number;
+}
+
+function logPoint(p: Point) {
+  console.log(`${p.x}, ${p.y}`);
+}
+
+// logs "12, 26"
+const point = { x: 12, y: 26 };
+logPoint(point);
+

The point variable is never declared to be a Point type. However, TypeScript compares the shape of point to the shape of Point in the type-check. They have the same shape, so the code passes.

The shape-matching only requires a subset of the object's fields to match.

-
// @errors: 2345
-interface Point {
-  x: number;
-  y: number;
-}
-
-function logPoint(p: Point) {
-  console.log(`${p.x}, ${p.y}`);
-}
-// ---cut---
-const point3 = { x: 12, y: 26, z: 89 };
-logPoint(point3); // logs "12, 26"
-
-const rect = { x: 33, y: 3, width: 30, height: 80 };
-logPoint(rect); // logs "33, 3"
-
-const color = { hex: "#187ABF" };
-logPoint(color);
-
+
// @errors: 2345
+interface Point {
+  x: number;
+  y: number;
+}
+
+function logPoint(p: Point) {
+  console.log(`${p.x}, ${p.y}`);
+}
+// ---cut---
+const point3 = { x: 12, y: 26, z: 89 };
+logPoint(point3); // logs "12, 26"
+
+const rect = { x: 33, y: 3, width: 30, height: 80 };
+logPoint(rect); // logs "33, 3"
+
+const color = { hex: "#187ABF" };
+logPoint(color);
+

There is no difference between how classes and objects conform to shapes:

-
// @errors: 2345
-interface Point {
-  x: number;
-  y: number;
-}
-
-function logPoint(p: Point) {
-  console.log(`${p.x}, ${p.y}`);
-}
-// ---cut---
-class VirtualPoint {
-  x: number;
-  y: number;
-
-  constructor(x: number, y: number) {
-    this.x = x;
-    this.y = y;
-  }
-}
-
-const newVPoint = new VirtualPoint(13, 56);
-logPoint(newVPoint); // logs "13, 56"
-
+
// @errors: 2345
+interface Point {
+  x: number;
+  y: number;
+}
+
+function logPoint(p: Point) {
+  console.log(`${p.x}, ${p.y}`);
+}
+// ---cut---
+class VirtualPoint {
+  x: number;
+  y: number;
+
+  constructor(x: number, y: number) {
+    this.x = x;
+    this.y = y;
+  }
+}
+
+const newVPoint = new VirtualPoint(13, 56);
+logPoint(newVPoint); // logs "13, 56"
+

If the object or class has all the required properties, TypeScript will say they match, regardless of the implementation details.

-

Next Steps

+

Next Steps

This was a brief overview of the syntax and tools used in everyday TypeScript. From here, you can:

  • Read the full Handbook from start to finish
  • diff --git a/dist/The Handbook/index.html b/dist/The Handbook/index.html index c99d607..cd32b7d 100644 --- a/dist/The Handbook/index.html +++ b/dist/The Handbook/index.html @@ -19,15 +19,15 @@
    -

    The TypeScript Handbook

    +

    The TypeScript Handbook

    -

    About this Handbook

    +

    About this Handbook

    Over 20 years after its introduction to the programming community, JavaScript is now one of the most widespread cross-platform languages ever created. Starting as a small scripting language for adding trivial interactivity to webpages, JavaScript has grown to be a language of choice for both frontend and backend applications of every size. While the size, scope, and complexity of programs written in JavaScript has grown exponentially, the ability of the JavaScript language to express the relationships between different units of code has not. Combined with JavaScript's rather peculiar runtime semantics, this mismatch between language and program complexity has made JavaScript development a difficult task to manage at scale.

    The most common kinds of errors that programmers write can be described as type errors: a certain kind of value was used where a different kind of value was expected. This could be due to simple typos, a failure to understand the API surface of a library, incorrect assumptions about runtime behavior, or other errors. The goal of TypeScript is to be a static typechecker for JavaScript programs - in other words, a tool that runs before your code runs (static) and ensures that the types of the program are correct (typechecked).

    If you are coming to TypeScript without a JavaScript background, with the intention of TypeScript being your first language, we recommend you first start reading the documentation on either the Microsoft Learn JavaScript tutorial or read JavaScript at the Mozilla Web Docs. If you have experience in other languages, you should be able to pick up JavaScript syntax quite quickly by reading the handbook.

    -

    How is this Handbook Structured

    +

    How is this Handbook Structured

    The handbook is split into two sections:

    • @@ -47,12 +47,12 @@

      How is this Handbook Structured

      The reference section below the handbook in the navigation is built to provide a richer understanding of how a particular part of TypeScript works. You can read it top-to-bottom, but each section aims to provide a deeper explanation of a single concept - meaning there is no aim for continuity.

    -

    Non-Goals

    +

    Non-Goals

    The Handbook is also intended to be a concise document that can be comfortably read in a few hours. Certain topics won't be covered in order to keep things short.

    Specifically, the Handbook does not fully introduce core JavaScript basics like functions, classes, and closures. Where appropriate, we'll include links to background reading that you can use to read up on those concepts.

    The Handbook also isn't intended to be a replacement for a language specification. In some cases, edge cases or formal descriptions of behavior will be skipped in favor of high-level, easier-to-understand explanations. Instead, there are separate reference pages that more precisely and formally describe many aspects of TypeScript's behavior. The reference pages are not intended for readers unfamiliar with TypeScript, so they may use advanced terminology or reference topics you haven't read about yet.

    Finally, the Handbook won't cover how TypeScript interacts with other tools, except where necessary. Topics like how to configure TypeScript with webpack, rollup, parcel, react, babel, closure, lerna, rush, bazel, preact, vue, angular, svelte, jquery, yarn, or npm are out of scope - you can find these resources elsewhere on the web.

    -

    Get Started

    +

    Get Started

    Before getting started with The Basics, we recommend reading one of the following introductory pages. These introductions are intended to highlight key similarities and differences between TypeScript and your favored programming language, and clear up common misconceptions specific to those languages.

    diff --git a/dist/_includes/home.njk b/dist/_includes/home.njk index 51c30d9..8a3dbeb 100644 --- a/dist/_includes/home.njk +++ b/dist/_includes/home.njk @@ -7,71 +7,91 @@
    -

    TypeScript is JavaScript with syntax for types

    +

    TypeScript is JavaScript with syntax for types +

    TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale.

    -
    -
    -
    - -
    -
    ts
    const user = {
    firstName: "Angela",
    lastName: "Davis",
    role: "Professor",
    }
     
    console.log(user.name)
    Property 'name' does not exist on type '{ firstName: string; lastName: string; role: string; }'.2339Property 'name' does not exist on type '{ firstName: string; lastName: string; role: string; }'.
     
    -
    -
    -
    tsx
    import express from "express"
    const app = express()
     
    app.get("/", function (req, res) {
    res.sen
             
    })
     
    app.listen(3000)
     
    -
    -
    -
    ts
    interface User {
    id: number
    firstName: string
    lastName: string
    role: string
    }
     
    function updateUser(id: number, update: Partial<User>) {
    const user = getUser(id)
    const newUser = { ...user, ...update }
    saveUser(id, newUser)
    }
     
    -
    -
    -
    tsx
    import * as React from "react";
     
    interface UserThumbnailProps {
    img: string;
    alt: string;
    url: string;
    }
     
    export const UserThumbnail = (props: UserThumbnailProps) =>
    <a href={props.url}>
    <img src={props.img} alt={props.alt} />
    </a>
     
    -
    - -
    + tablinks = document.getElementsByClassName("tablinks"); + for (i = 0; i < tablinks.length; i++) { + tablinks[i].className = tablinks[i] + .className + .replace(" active", ""); + } + document + .getElementById(tab) + .style + .display = "block"; + evt.currentTarget.className += " active"; + } + document + .getElementById("defaultOpen") + .click(); +
    +
-

TypeScript 5.4 is now available

+

+ TypeScript 5.4 is now available +

@@ -120,7 +140,7 @@
- +
@@ -133,7 +153,7 @@
- +
@@ -148,7 +168,8 @@

Describe your data

-

Describe the shape of your objects and functions in your code.

+

+ Describe the shape of your objects and functions in your code.

Making it possible to see documentation and issues in your editor.

@@ -174,319 +195,336 @@
ts
type Result = "pass" | "fail"
 
function verify(result: Result) {
if (result === "pass") {
console.log("Passed")
} else {
console.log("Failed")
}
}
 
-

TypeScript file.

- - -
-
ts
type Result = "pass" | "fail"
 
function verify(result: Result) {
if (result === "pass") {
console.log("Passed")
} else {
console.log("Failed")
}
}
 
-

Types are removed.

-
- - -
-
js
 
 
function verify(result) {
if (result === "pass") {
console.log("Passed")
} else {
console.log("Failed")
}
}
 
-

JavaScript file.

-
- - - - - -
-
-

TypeScript Testimonials

-
-
-
-
-

First, we were surprised by the number of small bugs we found when converting our code.

-

Second, we underestimated how powerful the editor integration is.

-

TypeScript was such a boon to our stability and sanity that we started using it for all new code within days of starting the conversion.

-
-
- - - - - - - - - - -
-
-
- - - - - - - - - - - - - - - -

Felix Rieseberg at Slack covered the transition of their desktop app from JavaScript to TypeScript in their blog

- Read -
+

+ TypeScript file.

+ + +
+
ts
type Result = "pass" | "fail"
 
function verify(result: Result) {
if (result === "pass") {
console.log("Passed")
} else {
console.log("Failed")
}
}
 
+

+ Types are removed. +

+
+ + +
+
js
 
 
function verify(result) {
if (result === "pass") {
console.log("Passed")
} else {
console.log("Failed")
}
}
 
+

+ JavaScript file. +

+
+ + +
-
-
-
-

38% [...] bugs preventable with TypeScript according to postmortem analysis

-

With TypeScript, engineers can move faster more safely.

-

End-to-end type safety because the types used by the back-end and the front-end share a source of truth.

+
+
+
+

TypeScript Testimonials

+
+
+
+
+

+ First, we were surprised by the number of small bugs we found when converting our code.

+

+ Second, we underestimated how powerful the editor integration is.

+

TypeScript was such a boon to our stability and sanity that we started using it for all new code within days of starting the conversion.

+
+
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + +

Felix Rieseberg at Slack covered the transition of their desktop app from JavaScript to TypeScript in their blog

+ Read +
-
- - - - - - - - - - - - - -
-
-
- - - - - - - - - - -

Brie Bunge at Airbnb gave a talk at JSConf Hawaiʻi on how Airbnb adopted TypeScript at Scale

- Watch -
-
-
-
-
-

Using TypeScript is simple and pleasant for all Google engineers.

-

Around eight or nine languages are officially supported and TypeScript is one of them.

+
+
+
+

+ 38% [...] bugs preventable with TypeScript according to postmortem analysis

+

With TypeScript, engineers can move faster more safely.

+

End-to-end type safety because the types used by the back-end and the front-end share a source of truth.

+
+
+ + + + + + + + + + + + + +
+
+
+ + + + + + + + + + +

Brie Bunge at Airbnb gave a talk at JSConf Hawaiʻi on how Airbnb adopted TypeScript at Scale

+ Watch +
+
+
+
+
+

Using TypeScript is simple and pleasant for all Google engineers.

+

Around eight or nine languages are officially supported and TypeScript is one of them.

+
+
+ + + + + + + + + +
+
+
+ + + + + + + + +

Rodoslav Kirov and Bowen Ni covered how TypeScript became one of the five languages available at Google at TSConf 2018.

+ Watch +
- -
- - - - - - - - -

Rodoslav Kirov and Bowen Ni covered how TypeScript became one of the five languages available at Google at TSConf 2018.

- Watch + + +
- +
+
+ + +

Loved by Developers

+ +
+ + +
+ +
+

Voted 2nd most loved programming language in the Stack Overflow 2020 Developer survey +

+
+
+ + + + + +
+ + +
+

TypeScript was used by 78% of the 2020 State of JS respondents, with 93% saying they would use it again.

+

TypeScript was given the award for "Most Adopted Technology" based on year-on-year growth.

+
+
+
- - -
-
-
-
- - -

Loved by Developers

- -
- - -
- -
-

Voted 2nd most loved programming language in the Stack Overflow 2020 Developer survey

-
-
- - - - - -
- - -
-

TypeScript was used by 78% of the 2020 State of JS respondents, with 93% saying they would use it again.

-

TypeScript was given the award for "Most Adopted Technology" based on year-on-year growth.

-
-
-
-
-
-
- - \ No newline at end of file + + \ No newline at end of file diff --git a/dist/community/index.html b/dist/community/index.html index d237530..14abdd7 100644 --- a/dist/community/index.html +++ b/dist/community/index.html @@ -3,38 +3,317 @@
-
-

First handbook page! -This iss the community page

- +
+ + + + + + + + + +
+
+

Connect with us

+
+
+
+ +
+
+ + +
+ +

Stack Overflow

+
Engage with your peers and ask questions about TypeScript using the tag 'typescript'
+
+
+ +
+ +

Chat

+
Chat with other TypeScript users in the TypeScript Community Chat.
+
+
+ +
+ +

GitHub

+
Found a bug, or want to give us constructive feedback? Tell us on GitHub +
+
+
+ +
+ +

Twitter

+
Stay up to date. Follow us on Twitter @typescript!
+
+
+ +
+ +

Blog

+
Learn about the latest TypeScript developments via our blog!
+
+
+ +
+ +

Definitely Typed

+
TypeScript definition files. Browse the thousands of available for common libraries and frameworks.
+
+
+
+
+
+

Connect in person

+
+
+

Meetups

+
+
+
logo of Boston TypeScript Club +
+

Boston TypeScript Club

+
🇺🇸
+ Website +
+
+
+
logo of Hamburg TypeScript +
+

Hamburg TypeScript

+
🇩🇪
+ Website +
+
+
+
logo of Krakow TypeScript User Group +
+

Krakow TypeScript User Group

+
🇵🇱
+ Website +
+
+
+
logo of Milano TS +
+

Milano TS

+
🇮🇹
+ Website + Twitter +
+
+
+
logo of Seattle TypeScript +
+

Seattle TypeScript

+
🇺🇸
+ Website +
+
+
+
logo of Sevilla TypeScript +
+

Sevilla TypeScript

+
🇪🇸
+ Website + Twitter +
+
+
+
logo of San Francisco TypeScript Meetup +
+

San Francisco TypeScript Meetup

+
🇺🇸
+ Website +
+
+
+
logo of TypeScript Brazil Meetup +
+

TypeScript Brazil Meetup

+
🇧🇷
+ Twitter +
+
+
+
logo of TypeScript JP +
+

TypeScript JP

+
🇯🇵
+ Website + Twitter +
+
+
+
logo of Paris TypeScript +
+

Paris TypeScript

+
🇫🇷
+ Website + Twitter +
+
+
+
logo of Phoenix TypeScript +
+

Phoenix TypeScript

+
🇺🇸
+ Website +
+
+
+
logo of Wroclaw TypeScript +
+

Wroclaw TypeScript

+
🇵🇱
+ Website + Twitter +
+
+
+
+
+
+
+ + - + + - -
-
+ + - \ No newline at end of file + diff --git a/dist/download/index.html b/dist/download/index.html index 0d458b6..95cfb60 100644 --- a/dist/download/index.html +++ b/dist/download/index.html @@ -3,17 +3,17 @@
-
diff --git a/dist/handbook/index.html b/dist/handbook/index.html index a5deb52..f2071e1 100644 --- a/dist/handbook/index.html +++ b/dist/handbook/index.html @@ -3,17 +3,17 @@
-
@@ -25,134 +25,70 @@ - - - - - - - -
- -
+ + + + + + + +
+ + - + - + + - + -
+ -
-
- -
- - + + diff --git a/dist/images/connect-blog.svg b/dist/images/connect-blog.svg new file mode 100644 index 0000000..85a721f --- /dev/null +++ b/dist/images/connect-blog.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dist/images/connect-definitely-typed.png b/dist/images/connect-definitely-typed.png new file mode 100644 index 0000000..6127f06 Binary files /dev/null and b/dist/images/connect-definitely-typed.png differ diff --git a/dist/images/connect-discord.svg b/dist/images/connect-discord.svg new file mode 100644 index 0000000..4613aa9 --- /dev/null +++ b/dist/images/connect-discord.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dist/images/connect-dt.svg b/dist/images/connect-dt.svg new file mode 100644 index 0000000..e69de29 diff --git a/dist/images/connect-github-icon.png b/dist/images/connect-github-icon.png new file mode 100644 index 0000000..73db1f6 Binary files /dev/null and b/dist/images/connect-github-icon.png differ diff --git a/dist/images/connect-twitter.svg b/dist/images/connect-twitter.svg new file mode 100644 index 0000000..83fde92 --- /dev/null +++ b/dist/images/connect-twitter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dist/images/definitely_typed_logo.png b/dist/images/definitely_typed_logo.png new file mode 100644 index 0000000..6127f06 Binary files /dev/null and b/dist/images/definitely_typed_logo.png differ diff --git a/dist/images/meetupLogos/boston-ts-club.png b/dist/images/meetupLogos/boston-ts-club.png new file mode 100644 index 0000000..1b5b793 Binary files /dev/null and b/dist/images/meetupLogos/boston-ts-club.png differ diff --git a/dist/images/meetupLogos/ktug.jpg b/dist/images/meetupLogos/ktug.jpg new file mode 100644 index 0000000..19ff5c9 Binary files /dev/null and b/dist/images/meetupLogos/ktug.jpg differ diff --git a/dist/images/meetupLogos/phx-ts.jpg b/dist/images/meetupLogos/phx-ts.jpg new file mode 100644 index 0000000..b166d38 Binary files /dev/null and b/dist/images/meetupLogos/phx-ts.jpg differ diff --git a/dist/images/meetupLogos/san-fran-ts.jpg b/dist/images/meetupLogos/san-fran-ts.jpg new file mode 100644 index 0000000..dfb4ee4 Binary files /dev/null and b/dist/images/meetupLogos/san-fran-ts.jpg differ diff --git a/dist/images/meetupLogos/typescript-jp.jpg b/dist/images/meetupLogos/typescript-jp.jpg new file mode 100644 index 0000000..8b2738c Binary files /dev/null and b/dist/images/meetupLogos/typescript-jp.jpg differ diff --git a/dist/images/stack-overflow-img.svg b/dist/images/stack-overflow-img.svg new file mode 100644 index 0000000..7973d2f --- /dev/null +++ b/dist/images/stack-overflow-img.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dist/index.html b/dist/index.html index 734f770..011ced0 100644 --- a/dist/index.html +++ b/dist/index.html @@ -3,17 +3,17 @@
-
@@ -27,71 +27,117 @@
-

TypeScript is JavaScript with syntax for types

+

TypeScript is JavaScript with syntax for types +

TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale.

-
-
-
- -
-
ts
const user = {
firstName: "Angela",
lastName: "Davis",
role: "Professor",
}
 
console.log(user.name)
Property 'name' does not exist on type '{ firstName: string; lastName: string; role: string; }'.2339Property 'name' does not exist on type '{ firstName: string; lastName: string; role: string; }'.
 
-
-
-
tsx
import express from "express"
const app = express()
 
app.get("/", function (req, res) {
res.sen
         
})
 
app.listen(3000)
 
-
-
-
ts
interface User {
id: number
firstName: string
lastName: string
role: string
}
 
function updateUser(id: number, update: Partial<User>) {
const user = getUser(id)
const newUser = { ...user, ...update }
saveUser(id, newUser)
}
 
-
-
-
tsx
import * as React from "react";
 
interface UserThumbnailProps {
img: string;
alt: string;
url: string;
}
 
export const UserThumbnail = (props: UserThumbnailProps) =>
<a href={props.url}>
<img src={props.img} alt={props.alt} />
</a>
 
-
- -
+ tablinks = document.getElementsByClassName("tablinks"); + for (i = 0; i < tablinks.length; i++) { + tablinks[i].className = tablinks[i] + .className + .replace(" active", ""); + } + document + .getElementById(tab) + .style + .display = "block"; + evt.currentTarget.className += " active"; + } + document + .getElementById("defaultOpen") + .click(); +
+ + + + + +
+
@@ -140,7 +186,7 @@

Get Started

- +
@@ -153,7 +199,7 @@

Get Started

- +
@@ -168,7 +214,8 @@

Get Started

Describe your data

-

Describe the shape of your objects and functions in your code.

+

+ Describe the shape of your objects and functions in your code.

Making it possible to see documentation and issues in your editor.

@@ -194,322 +241,341 @@

TypeScript becomes JavaScript via the delete key.

ts
type Result = "pass" | "fail"
 
function verify(result: Result) {
if (result === "pass") {
console.log("Passed")
} else {
console.log("Failed")
}
}
 
-

TypeScript file.

- - -
-
ts
type Result = "pass" | "fail"
 
function verify(result: Result) {
if (result === "pass") {
console.log("Passed")
} else {
console.log("Failed")
}
}
 
-

Types are removed.

-
- - -
-
js
 
 
function verify(result) {
if (result === "pass") {
console.log("Passed")
} else {
console.log("Failed")
}
}
 
-

JavaScript file.

-
- - - -
-
-
-
-

TypeScript Testimonials

-
-
-
-
-

First, we were surprised by the number of small bugs we found when converting our code.

-

Second, we underestimated how powerful the editor integration is.

-

TypeScript was such a boon to our stability and sanity that we started using it for all new code within days of starting the conversion.

-
-
- - - - - - - - - - -
-
-
- - - - - - - - - - - - - - - -

Felix Rieseberg at Slack covered the transition of their desktop app from JavaScript to TypeScript in their blog

- Read -
+

+ TypeScript file.

+ + +
+
ts
type Result = "pass" | "fail"
 
function verify(result: Result) {
if (result === "pass") {
console.log("Passed")
} else {
console.log("Failed")
}
}
 
+

+ Types are removed. +

+
+ + +
+
js
 
 
function verify(result) {
if (result === "pass") {
console.log("Passed")
} else {
console.log("Failed")
}
}
 
+

+ JavaScript file. +

+
+ + +
-
-
-
-

38% [...] bugs preventable with TypeScript according to postmortem analysis

-

With TypeScript, engineers can move faster more safely.

-

End-to-end type safety because the types used by the back-end and the front-end share a source of truth.

+
+
+
+

TypeScript Testimonials

+
+
+
+
+

+ First, we were surprised by the number of small bugs we found when converting our code.

+

+ Second, we underestimated how powerful the editor integration is.

+

TypeScript was such a boon to our stability and sanity that we started using it for all new code within days of starting the conversion.

+
+
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + +

Felix Rieseberg at Slack covered the transition of their desktop app from JavaScript to TypeScript in their blog

+ Read +
-
- - - - - - - - - - - - - -
-
-
- - - - - - - - - - -

Brie Bunge at Airbnb gave a talk at JSConf Hawaiʻi on how Airbnb adopted TypeScript at Scale

- Watch -
-
-
-
-
-

Using TypeScript is simple and pleasant for all Google engineers.

-

Around eight or nine languages are officially supported and TypeScript is one of them.

+
+
+
+

+ 38% [...] bugs preventable with TypeScript according to postmortem analysis

+

With TypeScript, engineers can move faster more safely.

+

End-to-end type safety because the types used by the back-end and the front-end share a source of truth.

+
+
+ + + + + + + + + + + + + +
+
+
+ + + + + + + + + + +

Brie Bunge at Airbnb gave a talk at JSConf Hawaiʻi on how Airbnb adopted TypeScript at Scale

+ Watch +
-
- - - - - - - - - +
+
+
+

Using TypeScript is simple and pleasant for all Google engineers.

+

Around eight or nine languages are officially supported and TypeScript is one of them.

+
+
+ + + + + + + + + +
+
+
+ + + + + + + + +

Rodoslav Kirov and Bowen Ni covered how TypeScript became one of the five languages available at Google at TSConf 2018.

+ Watch +
-
-
- - - - - - - - -

Rodoslav Kirov and Bowen Ni covered how TypeScript became one of the five languages available at Google at TSConf 2018.

- Watch + + + +
- +
+
+ + +

Loved by Developers

+ +
+ + +
+ +
+

Voted 2nd most loved programming language in the Stack Overflow 2020 Developer survey +

+
+
+ + + + + +
+ + +
+

TypeScript was used by 78% of the 2020 State of JS respondents, with 93% saying they would use it again.

+

TypeScript was given the award for "Most Adopted Technology" based on year-on-year growth.

+
+
+
- - -
-
-
-
- - -

Loved by Developers

- -
- - -
- -
-

Voted 2nd most loved programming language in the Stack Overflow 2020 Developer survey

-
-
- - - - - -
- - -
-

TypeScript was used by 78% of the 2020 State of JS respondents, with 93% saying they would use it again.

-

TypeScript was given the award for "Most Adopted Technology" based on year-on-year growth.

-
-
-
-
-
-
- - + + Here we are!!!
  • Start Handbook
  • diff --git a/dist/pages/GetStarted/NewProgrammer.md b/dist/pages/GetStarted/NewProgrammer.md index a5b2ec2..89636e9 100644 --- a/dist/pages/GetStarted/NewProgrammer.md +++ b/dist/pages/GetStarted/NewProgrammer.md @@ -58,9 +58,10 @@ For example, the last example above has an error because of the _type_ of `obj`. Here's the error TypeScript found: ```ts -// @errors: 2551 const obj = { width: 10, height: 15 }; const area = obj.width * obj.heigth; +Property 'heigth' does not exist on type '{ width: number; height: number; }'. Did you mean 'height'? // [!code error] + ``` ### A Typed Superset of JavaScript @@ -76,6 +77,8 @@ For example, this code has a _syntax_ error because it's missing a `)`: ```ts twoslash // @errors: 1005 let a = (4 +')' expected // [!code error] + ``` TypeScript doesn't consider any JavaScript code to be an error because of its syntax. diff --git a/dist/pages/community.md b/dist/pages/community.md index 7e8215a..85f6e2c 100644 --- a/dist/pages/community.md +++ b/dist/pages/community.md @@ -2,6 +2,4 @@ layout: "../_includes/community.njk" title: Start Handbook templateEngineOverride: njk,md ---- -First handbook page! -This iss the community page \ No newline at end of file +--- \ No newline at end of file diff --git a/dist/pages/handbook.md b/dist/pages/handbook.md index 704543d..1aee241 100644 --- a/dist/pages/handbook.md +++ b/dist/pages/handbook.md @@ -1,5 +1,5 @@ --- -layout: "../_includes/handbookBase.njk" +layout: "../_includes/handbook.njk" title: Start Handbook templateEngineOverride: njk,md --- diff --git a/dist/style/community.css b/dist/style/community.css new file mode 100644 index 0000000..cb45c7e --- /dev/null +++ b/dist/style/community.css @@ -0,0 +1,129 @@ +.community.centered { + text-align: center; +} +.main-content-block { + margin: 1rem auto; + max-width: 960px; + + .community { + padding: 0; + } +} +main { + background-color: #faf9f8; +} +.raised { + background-color: #fff; + box-shadow: 0 1.6px 3.6px 0 rgba(0,0,0,.132), 0 0.3px 0.9px 0 rgba(0,0,0,.108); + color: #000; + p { + line-height: 1.4rem; + code { + font-size: 14px; + background-color: #f1f1fe; + font-family: "SF Mono", Menlo, Monaco, Consolas, monospace; + padding: 2px 4px; + } + } + h2, h3 { + line-height: normal; + margin-bottom: 1.5rem; + margin-top: 2rem; + } + h2, h3 { + font-weight: 400; + } + a { + color: #235a97; + } + ul { + padding-left: 10px; + li { + margin-bottom: 10px; + margin-left: 10px; + } + } + li { + line-height: 1.4rem; + code { + font-size: 14px; + background-color: #f1f1fe; + font-family: "SF Mono", Menlo, Monaco, Consolas, monospace; + padding: 2px 4px; + } + } +} +.row, .split-row { + display: flex; + flex-direction: row; + flex-wrap: wrap; +} +.community .sidebar { + background-color: rgba(204, 207, 233, .1); +} +.community .banner-text { + margin-top: 20px; +} +.community .callouts { + display: flex; + flex-wrap: wrap; + margin: 20px 0; + .icon { + background-position: 50%; + background-repeat: no-repeat; + background-size: auto 3.2rem; + display: block; + height: 5rem; + margin: 0 20px 20px; + min-width: 5rem; + transition: background-color .2s ease-out; + width: 5rem; + } + .icon.stackoverflow { + background-color: #5016d9; + background-image: url(../images/stack-overflow-img.svg); + } + .icon.discord { + background-color: #7289da; + background-image: url(../images/connect-discord.svg); + } + .icon.twitter { + background-color: #00a0d1;; + background-image: url(../images/connect-twitter.svg); + } + .icon.blog { + background-color: #d9a216; + background-image: url(../images/connect-blog.svg); + } + .icon.definitelytyped { + background-color: #0077d2; + background-image: url(../images/connect-definitely-typed.png); + } + .icon.bug { + background-color: #4d4d4d; + background-image: url(../images/connect-github-icon.png); + } + .icon.img-circle { + border-radius: 50%; + } +} +.community .callouts .callout { + display: flex; + line-height: 1.4rem; + margin-bottom: 10px; + margin-top: 20px; + width: 48%; +} +.community h3.centered-highlight { + background-color: rgba(204, 207, 233, .1); + padding: 20px; + text-align: center; +} +.community .community-callout-headline { + margin-top: 0; +} +.col1 { + flex: 1 1; + min-width: 250px; + padding: 1rem; +} \ No newline at end of file diff --git a/dist/style/handbook.css b/dist/style/handbook.css new file mode 100644 index 0000000..a90ba5f --- /dev/null +++ b/dist/style/handbook.css @@ -0,0 +1,206 @@ +#doc-layout { + display: flex; + flex-direction: row; + background-color: #faf9f8; +} + +#sidebar { + background-color: #eeeeee; + color: #000; + min-width: 16rem; + ul { + max-height: calc(100vh - 10px); + overflow-x: hidden; + overflow-y: auto; + margin: 0; + padding: 0; + position: sticky; + top: 0; + li { + border-bottom: 1px solid #dfdfdf; + font-size: 1rem; + font-weight: 400; + list-style: none; + min-height: 2.5rem; + padding: 0; + a { + font-weight: 300; + margin-right: -.5rem; + } + button { + font-family: inherit; + background-color: transparent; + border: none; + color: #000; + cursor: pointer; + display: block; + font-size: 1rem; + font-weight: 500; + height: 2.5rem; + padding-left: 1rem; + position: relative; + text-align: left; + width: 100%; + span { + position: absolute; + right: 20px; + } + } + } + li.closed ul { + display: none; + } + li.open { + button span.closed { + display: none; + } + ul { + background-color: #e4e4e4; + } + } + li.highlighted { + background-color: #e3e8ec; + } + } +} + +.content-placeholder { + margin: auto; + max-width: 1200px; + min-width: 0; + padding: 0 2rem; + h1 { + font-size: 3.5rem; + font-weight: 400; + letter-spacing: 0; + line-height: 3.5rem; + } + article { + display: flex; + width: 100%; + #section1 { + margin: 0 auto 1rem; + overflow: hidden; + padding: 2rem; + background-color: #fff; + box-shadow: 0 1.6px 3.6px 0 rgba(0, 0, 0, .132), 0 0.3px 0.9px 0 rgba(0, 0, 0, .108); + color: #000; + scroll-behavior: smooth; + h2 { + font-size: 1.75rem; + margin-bottom: 12px; + margin-top: 32px; + white-space-collapse: preserve; + display: flex; + flex-wrap: wrap; + font-weight: 400; + line-height: 1.3; + } + h3 { + font-size: 1.1875rem; + margin-bottom: 18px; + margin-top: 30px; + white-space-collapse: preserve; + display: flex; + flex-wrap: wrap; + font-weight: 400; + line-height: 1.3; + } + h4 { + display: block; + margin-block-start: 1.33em; + margin-block-end: 1.33em; + margin-inline-start: 0px; + margin-inline-end: 0px; + font-weight: bold; + unicode-bidi: isolate; + } + p { + line-height: 1.4rem; + } + ul { + padding-left: 10px; + li { + margin-bottom: 10px; + margin-left: 10px; + line-height: 1.4rem; + } + } + pre { + clear: both; + top: 10px; + border-bottom: 1px solid #999; + border-left: 1px solid #999; + margin-bottom: 3rem; + padding: 12px; + position: relative; + border-color: #719af4; + } + pre.shiki { + overflow-x: visible; + } + pre .code-container { + overflow: auto; + } + pre code { + font-family: JetBrains Mono, Menlo, Monaco, Consolas, Courier New, monospace; + font-size: 15px; + white-space: pre; + } + pre .error { + align-items: center; + background-color: #fee; + border-left: 2px solid #bf1818; + color: #000; + display: flex; + margin-right: -2px; + position: absolute; + margin-bottom: 4px; + margin-left: -14px; + margin-top: 8px; + padding: 6px 6px 6px 14px; + white-space: pre-wrap; + width: calc(100% - 20px); + } + } + #section2 { + display: block; + margin-bottom: 1rem; + position: sticky; + top: 30px; + flex-shrink: 0; + margin-left: 20px; + width: 13rem; + nav { + margin-bottom: 1rem; + position: sticky; + top: 30px; + } + h5 { + font-size: 16px; + font-weight: 600; + margin: 0; + } + ul { + padding: 0; + max-height: 80vh; + overflow: auto; + li { + list-style: none; + } + a { + border-left: 2px solid transparent; + color: #000; + display: block; + font-size: 14px; + font-weight: 400; + overflow: hidden; + padding-left: 8px; + text-decoration: none; + text-overflow: ellipsis; + white-space: nowrap; + } + } + } + } +} \ No newline at end of file diff --git a/dist/style/handbookBase.css b/dist/style/handbookBase.css index d659afe..d060397 100644 --- a/dist/style/handbookBase.css +++ b/dist/style/handbookBase.css @@ -6,6 +6,11 @@ background-color: #eeeeee; color: #000; min-width: 16rem; + .side-content { + &.open { + background-color: aqua; + } + } table { max-height: calc(100vh - 10px); overflow-x: hidden; @@ -171,6 +176,14 @@ pre { clear: both; top: 10px; + background-color: #fff; + border-bottom: 1px solid #999; + border-left: 1px solid #999; + color: #000; + margin-bottom: 3rem; + overflow-x: auto; + padding: 12px; + position: relative; } article { display: flex; @@ -182,6 +195,14 @@ background-color: #fff;; box-shadow: 0 1.6px 3.6px 0 rgba(255, 255, 255, 0.132); color: #000; + ul { + padding-left: 10px; + li { + margin-bottom: 10px; + margin-left: 10px; + line-height: 1.4rem; + } + } } #section2 { display: block; diff --git a/dist/style/home.css b/dist/style/home.css index 6362eff..fe37425 100644 --- a/dist/style/home.css +++ b/dist/style/home.css @@ -9,6 +9,9 @@ line-height: 2.8rem; margin-top: 0; padding-right: 40px; + strong { + font-weight: 600; + } } h2 { @@ -140,6 +143,10 @@ code { font-size: 14px; line-height: 16px; + data-err { + background:url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") repeat-x 0 100%; + padding-bottom: 3px; + } .error { background-color: #ff000026; color: #ffc5c5; @@ -320,8 +327,8 @@ #migration-stories { min-height: 370px; position: relative; - .slides { - display: none; + .slides.slack { + display: block; } .illustration { .fg { diff --git a/dist/style/style.css b/dist/style/style.css index 08c11b9..f38501c 100644 --- a/dist/style/style.css +++ b/dist/style/style.css @@ -1,4 +1,4 @@ body { - font-family: sans-serif; + font-family: "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif; margin: 0; } \ No newline at end of file diff --git a/dist/tsconfigReference/index.html b/dist/tsconfigReference/index.html index c795831..78ad5c6 100644 --- a/dist/tsconfigReference/index.html +++ b/dist/tsconfigReference/index.html @@ -3,17 +3,17 @@
    -
    diff --git a/github_light_default.json b/github_light_default.json new file mode 100644 index 0000000..06152ed --- /dev/null +++ b/github_light_default.json @@ -0,0 +1,637 @@ +{ + "colors": { + "activityBar.activeBorder": "#fd8c73", + "activityBar.background": "#ffffff", + "activityBar.border": "#d0d7de", + "activityBar.foreground": "#1f2328", + "activityBar.inactiveForeground": "#656d76", + "activityBarBadge.background": "#0969da", + "activityBarBadge.foreground": "#ffffff", + "badge.background": "#0969da", + "badge.foreground": "#ffffff", + "breadcrumb.activeSelectionForeground": "#656d76", + "breadcrumb.focusForeground": "#1f2328", + "breadcrumb.foreground": "#656d76", + "breadcrumbPicker.background": "#ffffff", + "button.background": "#1f883d", + "button.foreground": "#ffffff", + "button.hoverBackground": "#1a7f37", + "button.secondaryBackground": "#ebecf0", + "button.secondaryForeground": "#24292f", + "button.secondaryHoverBackground": "#f3f4f6", + "checkbox.background": "#f6f8fa", + "checkbox.border": "#d0d7de", + "debugConsole.errorForeground": "#cf222e", + "debugConsole.infoForeground": "#57606a", + "debugConsole.sourceForeground": "#9a6700", + "debugConsole.warningForeground": "#7d4e00", + "debugConsoleInputIcon.foreground": "#6639ba", + "debugIcon.breakpointForeground": "#cf222e", + "debugTokenExpression.boolean": "#116329", + "debugTokenExpression.error": "#a40e26", + "debugTokenExpression.name": "#0550ae", + "debugTokenExpression.number": "#116329", + "debugTokenExpression.string": "#0a3069", + "debugTokenExpression.value": "#0a3069", + "debugToolBar.background": "#ffffff", + "descriptionForeground": "#656d76", + "diffEditor.insertedLineBackground": "#aceebb4d", + "diffEditor.insertedTextBackground": "#6fdd8b80", + "diffEditor.removedLineBackground": "#ffcecb4d", + "diffEditor.removedTextBackground": "#ff818266", + "dropdown.background": "#ffffff", + "dropdown.border": "#d0d7de", + "dropdown.foreground": "#1f2328", + "dropdown.listBackground": "#ffffff", + "editor.background": "#ffffff", + "editor.findMatchBackground": "#bf8700", + "editor.findMatchHighlightBackground": "#fae17d80", + "editor.focusedStackFrameHighlightBackground": "#4ac26b66", + "editor.foldBackground": "#6e77811a", + "editor.foreground": "#1f2328", + "editor.lineHighlightBackground": "#eaeef280", + "editor.linkedEditingBackground": "#0969da12", + "editor.selectionHighlightBackground": "#4ac26b40", + "editor.stackFrameHighlightBackground": "#d4a72c66", + "editor.wordHighlightBackground": "#eaeef280", + "editor.wordHighlightBorder": "#afb8c199", + "editor.wordHighlightStrongBackground": "#afb8c14d", + "editor.wordHighlightStrongBorder": "#afb8c199", + "editorBracketHighlight.foreground1": "#0969da", + "editorBracketHighlight.foreground2": "#1a7f37", + "editorBracketHighlight.foreground3": "#9a6700", + "editorBracketHighlight.foreground4": "#cf222e", + "editorBracketHighlight.foreground5": "#bf3989", + "editorBracketHighlight.foreground6": "#8250df", + "editorBracketHighlight.unexpectedBracket.foreground": "#656d76", + "editorBracketMatch.background": "#4ac26b40", + "editorBracketMatch.border": "#4ac26b99", + "editorCursor.foreground": "#0969da", + "editorGroup.border": "#d0d7de", + "editorGroupHeader.tabsBackground": "#f6f8fa", + "editorGroupHeader.tabsBorder": "#d0d7de", + "editorGutter.addedBackground": "#4ac26b66", + "editorGutter.deletedBackground": "#ff818266", + "editorGutter.modifiedBackground": "#d4a72c66", + "editorIndentGuide.activeBackground": "#1f23283d", + "editorIndentGuide.background": "#1f23281f", + "editorInlayHint.background": "#afb8c133", + "editorInlayHint.foreground": "#656d76", + "editorInlayHint.paramBackground": "#afb8c133", + "editorInlayHint.paramForeground": "#656d76", + "editorInlayHint.typeBackground": "#afb8c133", + "editorInlayHint.typeForeground": "#656d76", + "editorLineNumber.activeForeground": "#1f2328", + "editorLineNumber.foreground": "#8c959f", + "editorOverviewRuler.border": "#ffffff", + "editorWhitespace.foreground": "#afb8c1", + "editorWidget.background": "#ffffff", + "errorForeground": "#cf222e", + "focusBorder": "#0969da", + "foreground": "#1f2328", + "gitDecoration.addedResourceForeground": "#1a7f37", + "gitDecoration.conflictingResourceForeground": "#bc4c00", + "gitDecoration.deletedResourceForeground": "#cf222e", + "gitDecoration.ignoredResourceForeground": "#6e7781", + "gitDecoration.modifiedResourceForeground": "#9a6700", + "gitDecoration.submoduleResourceForeground": "#656d76", + "gitDecoration.untrackedResourceForeground": "#1a7f37", + "icon.foreground": "#656d76", + "input.background": "#ffffff", + "input.border": "#d0d7de", + "input.foreground": "#1f2328", + "input.placeholderForeground": "#6e7781", + "keybindingLabel.foreground": "#1f2328", + "list.activeSelectionBackground": "#afb8c133", + "list.activeSelectionForeground": "#1f2328", + "list.focusBackground": "#ddf4ff", + "list.focusForeground": "#1f2328", + "list.highlightForeground": "#0969da", + "list.hoverBackground": "#eaeef280", + "list.hoverForeground": "#1f2328", + "list.inactiveFocusBackground": "#ddf4ff", + "list.inactiveSelectionBackground": "#afb8c133", + "list.inactiveSelectionForeground": "#1f2328", + "minimapSlider.activeBackground": "#8c959f47", + "minimapSlider.background": "#8c959f33", + "minimapSlider.hoverBackground": "#8c959f3d", + "notificationCenterHeader.background": "#f6f8fa", + "notificationCenterHeader.foreground": "#656d76", + "notifications.background": "#ffffff", + "notifications.border": "#d0d7de", + "notifications.foreground": "#1f2328", + "notificationsErrorIcon.foreground": "#cf222e", + "notificationsInfoIcon.foreground": "#0969da", + "notificationsWarningIcon.foreground": "#9a6700", + "panel.background": "#f6f8fa", + "panel.border": "#d0d7de", + "panelInput.border": "#d0d7de", + "panelTitle.activeBorder": "#fd8c73", + "panelTitle.activeForeground": "#1f2328", + "panelTitle.inactiveForeground": "#656d76", + "pickerGroup.border": "#d0d7de", + "pickerGroup.foreground": "#656d76", + "progressBar.background": "#0969da", + "quickInput.background": "#ffffff", + "quickInput.foreground": "#1f2328", + "scrollbar.shadow": "#6e778133", + "scrollbarSlider.activeBackground": "#8c959f47", + "scrollbarSlider.background": "#8c959f33", + "scrollbarSlider.hoverBackground": "#8c959f3d", + "settings.headerForeground": "#1f2328", + "settings.modifiedItemIndicator": "#d4a72c66", + "sideBar.background": "#f6f8fa", + "sideBar.border": "#d0d7de", + "sideBar.foreground": "#1f2328", + "sideBarSectionHeader.background": "#f6f8fa", + "sideBarSectionHeader.border": "#d0d7de", + "sideBarSectionHeader.foreground": "#1f2328", + "sideBarTitle.foreground": "#1f2328", + "statusBar.background": "#ffffff", + "statusBar.border": "#d0d7de", + "statusBar.debuggingBackground": "#cf222e", + "statusBar.debuggingForeground": "#ffffff", + "statusBar.focusBorder": "#0969da80", + "statusBar.foreground": "#656d76", + "statusBar.noFolderBackground": "#ffffff", + "statusBarItem.activeBackground": "#1f23281f", + "statusBarItem.focusBorder": "#0969da", + "statusBarItem.hoverBackground": "#1f232814", + "statusBarItem.prominentBackground": "#afb8c133", + "statusBarItem.remoteBackground": "#eaeef2", + "statusBarItem.remoteForeground": "#1f2328", + "symbolIcon.arrayForeground": "#953800", + "symbolIcon.booleanForeground": "#0550ae", + "symbolIcon.classForeground": "#953800", + "symbolIcon.colorForeground": "#0a3069", + "symbolIcon.constantForeground": "#116329", + "symbolIcon.constructorForeground": "#3e1f79", + "symbolIcon.enumeratorForeground": "#953800", + "symbolIcon.enumeratorMemberForeground": "#0550ae", + "symbolIcon.eventForeground": "#57606a", + "symbolIcon.fieldForeground": "#953800", + "symbolIcon.fileForeground": "#7d4e00", + "symbolIcon.folderForeground": "#7d4e00", + "symbolIcon.functionForeground": "#6639ba", + "symbolIcon.interfaceForeground": "#953800", + "symbolIcon.keyForeground": "#0550ae", + "symbolIcon.keywordForeground": "#a40e26", + "symbolIcon.methodForeground": "#6639ba", + "symbolIcon.moduleForeground": "#a40e26", + "symbolIcon.namespaceForeground": "#a40e26", + "symbolIcon.nullForeground": "#0550ae", + "symbolIcon.numberForeground": "#116329", + "symbolIcon.objectForeground": "#953800", + "symbolIcon.operatorForeground": "#0a3069", + "symbolIcon.packageForeground": "#953800", + "symbolIcon.propertyForeground": "#953800", + "symbolIcon.referenceForeground": "#0550ae", + "symbolIcon.snippetForeground": "#0550ae", + "symbolIcon.stringForeground": "#0a3069", + "symbolIcon.structForeground": "#953800", + "symbolIcon.textForeground": "#0a3069", + "symbolIcon.typeParameterForeground": "#0a3069", + "symbolIcon.unitForeground": "#0550ae", + "symbolIcon.variableForeground": "#953800", + "tab.activeBackground": "#ffffff", + "tab.activeBorder": "#ffffff", + "tab.activeBorderTop": "#fd8c73", + "tab.activeForeground": "#1f2328", + "tab.border": "#d0d7de", + "tab.hoverBackground": "#ffffff", + "tab.inactiveBackground": "#f6f8fa", + "tab.inactiveForeground": "#656d76", + "tab.unfocusedActiveBorder": "#ffffff", + "tab.unfocusedActiveBorderTop": "#d0d7de", + "tab.unfocusedHoverBackground": "#eaeef280", + "terminal.ansiBlack": "#24292f", + "terminal.ansiBlue": "#0969da", + "terminal.ansiBrightBlack": "#57606a", + "terminal.ansiBrightBlue": "#218bff", + "terminal.ansiBrightCyan": "#3192aa", + "terminal.ansiBrightGreen": "#1a7f37", + "terminal.ansiBrightMagenta": "#a475f9", + "terminal.ansiBrightRed": "#a40e26", + "terminal.ansiBrightWhite": "#8c959f", + "terminal.ansiBrightYellow": "#633c01", + "terminal.ansiCyan": "#1b7c83", + "terminal.ansiGreen": "#116329", + "terminal.ansiMagenta": "#8250df", + "terminal.ansiRed": "#cf222e", + "terminal.ansiWhite": "#6e7781", + "terminal.ansiYellow": "#4d2d00", + "terminal.foreground": "#1f2328", + "textBlockQuote.background": "#f6f8fa", + "textBlockQuote.border": "#d0d7de", + "textCodeBlock.background": "#afb8c133", + "textLink.activeForeground": "#0969da", + "textLink.foreground": "#0969da", + "textPreformat.foreground": "#656d76", + "textSeparator.foreground": "#d8dee4", + "titleBar.activeBackground": "#ffffff", + "titleBar.activeForeground": "#656d76", + "titleBar.border": "#d0d7de", + "titleBar.inactiveBackground": "#f6f8fa", + "titleBar.inactiveForeground": "#656d76", + "tree.indentGuidesStroke": "#d8dee4", + "welcomePage.buttonBackground": "#f6f8fa", + "welcomePage.buttonHoverBackground": "#f3f4f6" + }, + "displayName": "GitHub Light Default", + "name": "github-light-default", + "semanticHighlighting": true, + "tokenColors": [ + { + "scope": [ + "comment", + "punctuation.definition.comment", + "string.comment" + ], + "settings": { + "foreground": "#6e7781" + } + }, + { + "scope": [ + "constant.other.placeholder", + "constant.character" + ], + "settings": { + "foreground": "#cf222e" + } + }, + { + "scope": [ + "constant", + "entity.name.constant", + "variable.other.constant", + "variable.other.enummember", + "variable.language", + "entity" + ], + "settings": { + "foreground": "#0550ae" + } + }, + { + "scope": [ + "entity.name", + "meta.export.default", + "meta.definition.variable" + ], + "settings": { + "foreground": "#953800" + } + }, + { + "scope": [ + "variable.parameter.function", + "meta.jsx.children", + "meta.block", + "meta.tag.attributes", + "entity.name.constant", + "meta.object.member", + "meta.embedded.expression" + ], + "settings": { + "foreground": "#1f2328" + } + }, + { + "scope": "entity.name.function", + "settings": { + "foreground": "#8250df" + } + }, + { + "scope": [ + "entity.name.tag", + "support.class.component" + ], + "settings": { + "foreground": "#116329" + } + }, + { + "scope": "keyword", + "settings": { + "foreground": "#cf222e" + } + }, + { + "scope": [ + "storage", + "storage.type" + ], + "settings": { + "foreground": "#cf222e" + } + }, + { + "scope": [ + "storage.modifier.package", + "storage.modifier.import", + "storage.type.java" + ], + "settings": { + "foreground": "#1f2328" + } + }, + { + "scope": [ + "string", + "string punctuation.section.embedded source" + ], + "settings": { + "foreground": "#0a3069" + } + }, + { + "scope": "support", + "settings": { + "foreground": "#0550ae" + } + }, + { + "scope": "meta.property-name", + "settings": { + "foreground": "#0550ae" + } + }, + { + "scope": "variable", + "settings": { + "foreground": "#953800" + } + }, + { + "scope": "variable.other", + "settings": { + "foreground": "#1f2328" + } + }, + { + "scope": "invalid.broken", + "settings": { + "fontStyle": "italic", + "foreground": "#82071e" + } + }, + { + "scope": "invalid.deprecated", + "settings": { + "fontStyle": "italic", + "foreground": "#82071e" + } + }, + { + "scope": "invalid.illegal", + "settings": { + "fontStyle": "italic", + "foreground": "#82071e" + } + }, + { + "scope": "invalid.unimplemented", + "settings": { + "fontStyle": "italic", + "foreground": "#82071e" + } + }, + { + "scope": "carriage-return", + "settings": { + "background": "#cf222e", + "content": "^M", + "fontStyle": "italic underline", + "foreground": "#f6f8fa" + } + }, + { + "scope": "message.error", + "settings": { + "foreground": "#82071e" + } + }, + { + "scope": "string variable", + "settings": { + "foreground": "#0550ae" + } + }, + { + "scope": [ + "source.regexp", + "string.regexp" + ], + "settings": { + "foreground": "#0a3069" + } + }, + { + "scope": [ + "string.regexp.character-class", + "string.regexp constant.character.escape", + "string.regexp source.ruby.embedded", + "string.regexp string.regexp.arbitrary-repitition" + ], + "settings": { + "foreground": "#0a3069" + } + }, + { + "scope": "string.regexp constant.character.escape", + "settings": { + "fontStyle": "bold", + "foreground": "#116329" + } + }, + { + "scope": "support.constant", + "settings": { + "foreground": "#0550ae" + } + }, + { + "scope": "support.variable", + "settings": { + "foreground": "#0550ae" + } + }, + { + "scope": "support.type.property-name.json", + "settings": { + "foreground": "#116329" + } + }, + { + "scope": "meta.module-reference", + "settings": { + "foreground": "#0550ae" + } + }, + { + "scope": "punctuation.definition.list.begin.markdown", + "settings": { + "foreground": "#953800" + } + }, + { + "scope": [ + "markup.heading", + "markup.heading entity.name" + ], + "settings": { + "fontStyle": "bold", + "foreground": "#0550ae" + } + }, + { + "scope": "markup.quote", + "settings": { + "foreground": "#116329" + } + }, + { + "scope": "markup.italic", + "settings": { + "fontStyle": "italic", + "foreground": "#1f2328" + } + }, + { + "scope": "markup.bold", + "settings": { + "fontStyle": "bold", + "foreground": "#1f2328" + } + }, + { + "scope": [ + "markup.underline" + ], + "settings": { + "fontStyle": "underline" + } + }, + { + "scope": [ + "markup.strikethrough" + ], + "settings": { + "fontStyle": "strikethrough" + } + }, + { + "scope": "markup.inline.raw", + "settings": { + "foreground": "#0550ae" + } + }, + { + "scope": [ + "markup.deleted", + "meta.diff.header.from-file", + "punctuation.definition.deleted" + ], + "settings": { + "background": "#ffebe9", + "foreground": "#82071e" + } + }, + { + "scope": [ + "punctuation.section.embedded" + ], + "settings": { + "foreground": "#cf222e" + } + }, + { + "scope": [ + "markup.inserted", + "meta.diff.header.to-file", + "punctuation.definition.inserted" + ], + "settings": { + "background": "#dafbe1", + "foreground": "#116329" + } + }, + { + "scope": [ + "markup.changed", + "punctuation.definition.changed" + ], + "settings": { + "background": "#ffd8b5", + "foreground": "#953800" + } + }, + { + "scope": [ + "markup.ignored", + "markup.untracked" + ], + "settings": { + "background": "#0550ae", + "foreground": "#eaeef2" + } + }, + { + "scope": "meta.diff.range", + "settings": { + "fontStyle": "bold", + "foreground": "#8250df" + } + }, + { + "scope": "meta.diff.header", + "settings": { + "foreground": "#0550ae" + } + }, + { + "scope": "meta.separator", + "settings": { + "fontStyle": "bold", + "foreground": "#0550ae" + } + }, + { + "scope": "meta.output", + "settings": { + "foreground": "#0550ae" + } + }, + { + "scope": [ + "brackethighlighter.tag", + "brackethighlighter.curly", + "brackethighlighter.round", + "brackethighlighter.square", + "brackethighlighter.angle", + "brackethighlighter.quote" + ], + "settings": { + "foreground": "#57606a" + } + }, + { + "scope": "brackethighlighter.unmatched", + "settings": { + "foreground": "#82071e" + } + }, + { + "scope": [ + "constant.other.reference.link", + "string.other.link" + ], + "settings": { + "foreground": "#0a3069" + } + } + ], + "type": "light" + } \ No newline at end of file diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index 6bca7a4..5d77e14 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -209,6 +209,22 @@ "node": ">= 8" } }, + "node_modules/@shikijs/core": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.14.1.tgz", + "integrity": "sha512-KyHIIpKNaT20FtFPFjCQB5WVSTpLR/n+jQXhWHWVUMm9MaOaG9BGOG0MSyt7yA4+Lm+4c9rTc03tt3nYzeYSfw==", + "dependencies": { + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/transformers": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-1.14.1.tgz", + "integrity": "sha512-JJqL8QBVCJh3L61jqqEXgFq1cTycwjcGj7aSmqOEsbxnETM9hRlaB74QuXvY/fVJNjbNt8nvWo0VwAXKvMSLRg==", + "dependencies": { + "shiki": "1.14.1" + } + }, "node_modules/@sindresorhus/slugify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-1.1.2.tgz", @@ -250,6 +266,14 @@ "node": ">=8" } }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", @@ -278,6 +302,11 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "dev": true }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + }, "node_modules/a-sync-waterfall": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", @@ -2469,6 +2498,15 @@ "node": ">=8" } }, + "node_modules/shiki": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.14.1.tgz", + "integrity": "sha512-FujAN40NEejeXdzPt+3sZ3F2dx1U24BY2XTY01+MG8mbxCiA2XukXdcbyMyLAHJ/1AUUnQd1tZlvIjefWWEJeA==", + "dependencies": { + "@shikijs/core": "1.14.1", + "@types/hast": "^3.0.4" + } + }, "node_modules/shikiji": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/shikiji/-/shikiji-0.10.2.tgz", diff --git a/node_modules/@shikijs/core/LICENSE b/node_modules/@shikijs/core/LICENSE new file mode 100644 index 0000000..6a62718 --- /dev/null +++ b/node_modules/@shikijs/core/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2021 Pine Wu +Copyright (c) 2023 Anthony Fu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/node_modules/@shikijs/core/README.md b/node_modules/@shikijs/core/README.md new file mode 100644 index 0000000..4c90ca2 --- /dev/null +++ b/node_modules/@shikijs/core/README.md @@ -0,0 +1,5 @@ +# @shikijs/core + +The core functionality of [Shiki](https://github.com/shikijs/shiki), without any grammar of themes bundled. + +It's the same as importing `shiki/core`. diff --git a/node_modules/@shikijs/core/dist/chunk-index.d.mts b/node_modules/@shikijs/core/dist/chunk-index.d.mts new file mode 100644 index 0000000..f3d77b6 --- /dev/null +++ b/node_modules/@shikijs/core/dist/chunk-index.d.mts @@ -0,0 +1,17 @@ +interface WebAssemblyInstantiator { + (importObject: Record> | undefined): Promise; +} +type WebAssemblyInstance = WebAssembly.WebAssemblyInstantiatedSource | WebAssembly.Instance | WebAssembly.Instance['exports']; +type OnigurumaLoadOptions = { + instantiator: WebAssemblyInstantiator; +} | { + default: WebAssemblyInstantiator; +} | { + data: ArrayBufferView | ArrayBuffer | Response; +}; +type Awaitable = T | Promise; +type LoadWasmOptionsPlain = OnigurumaLoadOptions | WebAssemblyInstantiator | ArrayBufferView | ArrayBuffer | Response; +type LoadWasmOptions = Awaitable | (() => Awaitable); +declare function loadWasm(options: LoadWasmOptions): Promise; + +export { type LoadWasmOptions as L, type WebAssemblyInstantiator as W, loadWasm as l }; diff --git a/node_modules/@shikijs/core/dist/chunk-tokens.d.mts b/node_modules/@shikijs/core/dist/chunk-tokens.d.mts new file mode 100644 index 0000000..d27ffd0 --- /dev/null +++ b/node_modules/@shikijs/core/dist/chunk-tokens.d.mts @@ -0,0 +1,1022 @@ +import { L as LoadWasmOptions } from './chunk-index.mjs'; +import { Root, Element } from 'hast'; + +/** + * A union of given const enum values. +*/ +type OrMask = number; + +interface IOnigLib { + createOnigScanner(sources: string[]): OnigScanner; + createOnigString(str: string): OnigString; +} +interface IOnigCaptureIndex { + start: number; + end: number; + length: number; +} +interface IOnigMatch { + index: number; + captureIndices: IOnigCaptureIndex[]; +} +declare const enum FindOption { + None = 0, + /** + * equivalent of ONIG_OPTION_NOT_BEGIN_STRING: (str) isn't considered as begin of string (* fail \A) + */ + NotBeginString = 1, + /** + * equivalent of ONIG_OPTION_NOT_END_STRING: (end) isn't considered as end of string (* fail \z, \Z) + */ + NotEndString = 2, + /** + * equivalent of ONIG_OPTION_NOT_BEGIN_POSITION: (start) isn't considered as start position of search (* fail \G) + */ + NotBeginPosition = 4, + /** + * used for debugging purposes. + */ + DebugCall = 8 +} +interface OnigScanner { + findNextMatchSync(string: string | OnigString, startPosition: number, options: OrMask): IOnigMatch | null; + dispose?(): void; +} +interface OnigString { + readonly content: string; + dispose?(): void; +} + +declare const ruleIdSymbol: unique symbol; +type RuleId = { + __brand: typeof ruleIdSymbol; +}; + +declare class Theme { + private readonly _colorMap; + private readonly _defaults; + private readonly _root; + static createFromRawTheme(source: IRawTheme | undefined, colorMap?: string[]): Theme; + static createFromParsedTheme(source: ParsedThemeRule[], colorMap?: string[]): Theme; + private readonly _cachedMatchRoot; + constructor(_colorMap: ColorMap, _defaults: StyleAttributes, _root: ThemeTrieElement); + getColorMap(): string[]; + getDefaults(): StyleAttributes; + match(scopePath: ScopeStack | null): StyleAttributes | null; +} +/** + * Identifiers with a binary dot operator. + * Examples: `baz` or `foo.bar` +*/ +type ScopeName = string; +/** + * An expression language of ScopePathStr with a binary comma (to indicate alternatives) operator. + * Examples: `foo.bar boo.baz,quick quack` +*/ +type ScopePattern = string; +/** + * A TextMate theme. + */ +interface IRawTheme { + readonly name?: string; + readonly settings: IRawThemeSetting[]; +} +/** + * A single theme setting. + */ +interface IRawThemeSetting { + readonly name?: string; + readonly scope?: ScopePattern | ScopePattern[]; + readonly settings: { + readonly fontStyle?: string; + readonly foreground?: string; + readonly background?: string; + }; +} +declare class ScopeStack { + readonly parent: ScopeStack | null; + readonly scopeName: ScopeName; + static push(path: ScopeStack | null, scopeNames: ScopeName[]): ScopeStack | null; + static from(first: ScopeName, ...segments: ScopeName[]): ScopeStack; + static from(...segments: ScopeName[]): ScopeStack | null; + constructor(parent: ScopeStack | null, scopeName: ScopeName); + push(scopeName: ScopeName): ScopeStack; + getSegments(): ScopeName[]; + toString(): string; + extends(other: ScopeStack): boolean; + getExtensionIfDefined(base: ScopeStack | null): string[] | undefined; +} +declare class StyleAttributes { + readonly fontStyle: OrMask; + readonly foregroundId: number; + readonly backgroundId: number; + constructor(fontStyle: OrMask, foregroundId: number, backgroundId: number); +} +declare class ParsedThemeRule { + readonly scope: ScopeName; + readonly parentScopes: ScopeName[] | null; + readonly index: number; + readonly fontStyle: OrMask; + readonly foreground: string | null; + readonly background: string | null; + constructor(scope: ScopeName, parentScopes: ScopeName[] | null, index: number, fontStyle: OrMask, foreground: string | null, background: string | null); +} +declare const enum FontStyle$1 { + NotSet = -1, + None = 0, + Italic = 1, + Bold = 2, + Underline = 4, + Strikethrough = 8 +} +declare class ColorMap { + private readonly _isFrozen; + private _lastColorId; + private _id2color; + private _color2id; + constructor(_colorMap?: string[]); + getId(color: string | null): number; + getColorMap(): string[]; +} +declare class ThemeTrieElementRule { + scopeDepth: number; + parentScopes: ScopeName[] | null; + fontStyle: number; + foreground: number; + background: number; + constructor(scopeDepth: number, parentScopes: ScopeName[] | null, fontStyle: number, foreground: number, background: number); + clone(): ThemeTrieElementRule; + static cloneArr(arr: ThemeTrieElementRule[]): ThemeTrieElementRule[]; + acceptOverwrite(scopeDepth: number, fontStyle: number, foreground: number, background: number): void; +} +interface ITrieChildrenMap { + [segment: string]: ThemeTrieElement; +} +declare class ThemeTrieElement { + private readonly _mainRule; + private readonly _children; + private readonly _rulesWithParentScopes; + constructor(_mainRule: ThemeTrieElementRule, rulesWithParentScopes?: ThemeTrieElementRule[], _children?: ITrieChildrenMap); + private static _sortBySpecificity; + private static _cmpBySpecificity; + match(scope: ScopeName): ThemeTrieElementRule[]; + insert(scopeDepth: number, scope: ScopeName, parentScopes: ScopeName[] | null, fontStyle: number, foreground: number, background: number): void; + private _doInsertHere; +} + +interface IRawGrammar extends ILocatable { + repository: IRawRepository; + readonly scopeName: ScopeName; + readonly patterns: IRawRule[]; + readonly injections?: { + [expression: string]: IRawRule; + }; + readonly injectionSelector?: string; + readonly fileTypes?: string[]; + readonly name?: string; + readonly firstLineMatch?: string; +} +/** + * Allowed values: + * * Scope Name, e.g. `source.ts` + * * Top level scope reference, e.g. `source.ts#entity.name.class` + * * Relative scope reference, e.g. `#entity.name.class` + * * self, e.g. `$self` + * * base, e.g. `$base` + */ +type IncludeString = string; +type RegExpString = string; +interface IRawRepositoryMap { + [name: string]: IRawRule; + $self: IRawRule; + $base: IRawRule; +} +type IRawRepository = IRawRepositoryMap & ILocatable; +interface IRawRule extends ILocatable { + id?: RuleId; + readonly include?: IncludeString; + readonly name?: ScopeName; + readonly contentName?: ScopeName; + readonly match?: RegExpString; + readonly captures?: IRawCaptures; + readonly begin?: RegExpString; + readonly beginCaptures?: IRawCaptures; + readonly end?: RegExpString; + readonly endCaptures?: IRawCaptures; + readonly while?: RegExpString; + readonly whileCaptures?: IRawCaptures; + readonly patterns?: IRawRule[]; + readonly repository?: IRawRepository; + readonly applyEndPatternLast?: boolean; +} +type IRawCaptures = IRawCapturesMap & ILocatable; +interface IRawCapturesMap { + [captureId: string]: IRawRule; +} +interface ILocation { + readonly filename: string; + readonly line: number; + readonly char: number; +} +interface ILocatable { + readonly $vscodeTextmateLocation?: ILocation; +} + +declare const enum StandardTokenType { + Other = 0, + Comment = 1, + String = 2, + RegEx = 3 +} + +/** + * A registry helper that can locate grammar file paths given scope names. + */ +interface RegistryOptions { + onigLib: Promise; + theme?: IRawTheme; + colorMap?: string[]; + loadGrammar(scopeName: ScopeName): Promise; + getInjections?(scopeName: ScopeName): ScopeName[] | undefined; +} +/** + * A map from scope name to a language id. Please do not use language id 0. + */ +interface IEmbeddedLanguagesMap { + [scopeName: string]: number; +} +/** + * A map from selectors to token types. + */ +interface ITokenTypeMap { + [selector: string]: StandardTokenType; +} +interface IGrammarConfiguration { + embeddedLanguages?: IEmbeddedLanguagesMap; + tokenTypes?: ITokenTypeMap; + balancedBracketSelectors?: string[]; + unbalancedBracketSelectors?: string[]; +} +/** + * The registry that will hold all grammars. + */ +declare class Registry { + private readonly _options; + private readonly _syncRegistry; + private readonly _ensureGrammarCache; + constructor(options: RegistryOptions); + dispose(): void; + /** + * Change the theme. Once called, no previous `ruleStack` should be used anymore. + */ + setTheme(theme: IRawTheme, colorMap?: string[]): void; + /** + * Returns a lookup array for color ids. + */ + getColorMap(): string[]; + /** + * Load the grammar for `scopeName` and all referenced included grammars asynchronously. + * Please do not use language id 0. + */ + loadGrammarWithEmbeddedLanguages(initialScopeName: ScopeName, initialLanguage: number, embeddedLanguages: IEmbeddedLanguagesMap): Promise; + /** + * Load the grammar for `scopeName` and all referenced included grammars asynchronously. + * Please do not use language id 0. + */ + loadGrammarWithConfiguration(initialScopeName: ScopeName, initialLanguage: number, configuration: IGrammarConfiguration): Promise; + /** + * Load the grammar for `scopeName` and all referenced included grammars asynchronously. + */ + loadGrammar(initialScopeName: ScopeName): Promise; + private _loadGrammar; + private _loadSingleGrammar; + private _doLoadSingleGrammar; + /** + * Adds a rawGrammar. + */ + addGrammar(rawGrammar: IRawGrammar, injections?: string[], initialLanguage?: number, embeddedLanguages?: IEmbeddedLanguagesMap | null): Promise; + /** + * Get the grammar for `scopeName`. The grammar must first be created via `loadGrammar` or `addGrammar`. + */ + private _grammarForScopeName; +} +/** + * A grammar + */ +interface IGrammar { + /** + * Tokenize `lineText` using previous line state `prevState`. + */ + tokenizeLine(lineText: string, prevState: StateStack | null, timeLimit?: number): ITokenizeLineResult; + /** + * Tokenize `lineText` using previous line state `prevState`. + * The result contains the tokens in binary format, resolved with the following information: + * - language + * - token type (regex, string, comment, other) + * - font style + * - foreground color + * - background color + * e.g. for getting the languageId: `(metadata & MetadataConsts.LANGUAGEID_MASK) >>> MetadataConsts.LANGUAGEID_OFFSET` + */ + tokenizeLine2(lineText: string, prevState: StateStack | null, timeLimit?: number): ITokenizeLineResult2; +} +interface ITokenizeLineResult { + readonly tokens: IToken[]; + /** + * The `prevState` to be passed on to the next line tokenization. + */ + readonly ruleStack: StateStack; + /** + * Did tokenization stop early due to reaching the time limit. + */ + readonly stoppedEarly: boolean; +} +interface ITokenizeLineResult2 { + /** + * The tokens in binary format. Each token occupies two array indices. For token i: + * - at offset 2*i => startIndex + * - at offset 2*i + 1 => metadata + * + */ + readonly tokens: Uint32Array; + /** + * The `prevState` to be passed on to the next line tokenization. + */ + readonly ruleStack: StateStack; + /** + * Did tokenization stop early due to reaching the time limit. + */ + readonly stoppedEarly: boolean; +} +interface IToken { + startIndex: number; + readonly endIndex: number; + readonly scopes: string[]; +} +/** + * **IMPORTANT** - Immutable! + */ +interface StateStack { + _stackElementBrand: void; + readonly depth: number; + clone(): StateStack; + equals(other: StateStack): boolean; +} +declare const INITIAL: StateStack; + +type Awaitable = T | Promise; +type MaybeGetter = Awaitable> | (() => Awaitable>); +type MaybeModule = T | { + default: T; +}; +type MaybeArray = T | T[]; +type RequireKeys = Omit & Required>; +interface Nothing { +} +/** + * type StringLiteralUnion<'foo'> = 'foo' | string + * This has auto completion whereas `'foo' | string` doesn't + * Adapted from https://github.com/microsoft/TypeScript/issues/29729 + */ +type StringLiteralUnion = T | (U & Nothing); + +type PlainTextLanguage = 'text' | 'plaintext' | 'txt'; +type AnsiLanguage = 'ansi'; +type SpecialLanguage = PlainTextLanguage | AnsiLanguage; +type LanguageInput = MaybeGetter>; +type ResolveBundleKey = [T] extends [never] ? string : T; +interface LanguageRegistration extends IRawGrammar { + name: string; + scopeName: string; + displayName?: string; + aliases?: string[]; + /** + * A list of languages the current language embeds. + * If manually specifying languages to load, make sure to load the embedded + * languages for each parent language. + */ + embeddedLangs?: string[]; + /** + * A list of languages that embed the current language. + * Unlike `embeddedLangs`, the embedded languages will not be loaded automatically. + */ + embeddedLangsLazy?: string[]; + balancedBracketSelectors?: string[]; + unbalancedBracketSelectors?: string[]; + foldingStopMarker?: string; + foldingStartMarker?: string; + /** + * Inject this language to other scopes. + * Same as `injectTo` in VSCode's `contributes.grammars`. + * + * @see https://code.visualstudio.com/api/language-extensions/syntax-highlight-guide#injection-grammars + */ + injectTo?: string[]; +} +interface BundledLanguageInfo { + id: string; + name: string; + import: DynamicImportLanguageRegistration; + aliases?: string[]; +} +type DynamicImportLanguageRegistration = () => Promise<{ + default: LanguageRegistration[]; +}>; + +type SpecialTheme = 'none'; +type ThemeInput = MaybeGetter; +interface ThemeRegistrationRaw extends IRawTheme, Partial> { +} +interface ThemeRegistration extends Partial { +} +interface ThemeRegistrationResolved extends IRawTheme { + /** + * Theme name + */ + name: string; + /** + * Display name + * + * @field shiki custom property + */ + displayName?: string; + /** + * Light/dark theme + * + * @field shiki custom property + */ + type: 'light' | 'dark'; + /** + * Token rules + */ + settings: IRawThemeSetting[]; + /** + * Same as `settings`, will use as fallback if `settings` is not present. + */ + tokenColors?: IRawThemeSetting[]; + /** + * Default foreground color + * + * @field shiki custom property + */ + fg: string; + /** + * Background color + * + * @field shiki custom property + */ + bg: string; + /** + * A map of color names to new color values. + * + * The color key starts with '#' and should be lowercased. + * + * @field shiki custom property + */ + colorReplacements?: Record; + /** + * Color map of VS Code options + * + * Will be used by shiki on `lang: 'ansi'` to find ANSI colors, and to find the default foreground/background colors. + */ + colors?: Record; + /** + * JSON schema path + * + * @field not used by shiki + */ + $schema?: string; + /** + * Enable semantic highlighting + * + * @field not used by shiki + */ + semanticHighlighting?: boolean; + /** + * Tokens for semantic highlighting + * + * @field not used by shiki + */ + semanticTokenColors?: Record; +} +type ThemeRegistrationAny = ThemeRegistrationRaw | ThemeRegistration | ThemeRegistrationResolved; +type DynamicImportThemeRegistration = () => Promise<{ + default: ThemeRegistration; +}>; +interface BundledThemeInfo { + id: string; + displayName: string; + type: 'light' | 'dark'; + import: DynamicImportThemeRegistration; +} + +/** + * GrammarState is a special reference object that holds the state of a grammar. + * + * It's used to highlight code snippets that are part of the target language. + */ +declare class GrammarState { + private readonly _stack; + readonly lang: string; + readonly theme: string; + /** + * Static method to create a initial grammar state. + */ + static initial(lang: string, theme: string): GrammarState; + constructor(_stack: StateStack, lang: string, theme: string); + get scopes(): string[]; + toJSON(): { + lang: string; + theme: string; + scopes: string[]; + }; +} + +interface TransformerOptions { + /** + * Transformers for the Shiki pipeline. + */ + transformers?: ShikiTransformer[]; +} +interface ShikiTransformerContextMeta { +} +/** + * Common transformer context for all transformers hooks + */ +interface ShikiTransformerContextCommon { + meta: ShikiTransformerContextMeta; + options: CodeToHastOptions; + codeToHast: (code: string, options: CodeToHastOptions) => Root; + codeToTokens: (code: string, options: CodeToTokensOptions) => TokensResult; +} +interface ShikiTransformerContextSource extends ShikiTransformerContextCommon { + readonly source: string; +} +/** + * Transformer context for HAST related hooks + */ +interface ShikiTransformerContext extends ShikiTransformerContextSource { + readonly tokens: ThemedToken[][]; + readonly root: Root; + readonly pre: Element; + readonly code: Element; + readonly lines: Element[]; + readonly structure: CodeToHastOptions['structure']; + /** + * Utility to append class to a hast node + * + * If the `property.class` is a string, it will be splitted by space and converted to an array. + */ + addClassToHast: (hast: Element, className: string | string[]) => Element; +} +interface ShikiTransformer { + /** + * Name of the transformer + */ + name?: string; + /** + * Transform the raw input code before passing to the highlighter. + */ + preprocess?: (this: ShikiTransformerContextCommon, code: string, options: CodeToHastOptions) => string | void; + /** + * Transform the full tokens list before converting to HAST. + * Return a new tokens list will replace the original one. + */ + tokens?: (this: ShikiTransformerContextSource, tokens: ThemedToken[][]) => ThemedToken[][] | void; + /** + * Transform the entire generated HAST tree. Return a new Node will replace the original one. + */ + root?: (this: ShikiTransformerContext, hast: Root) => Root | void; + /** + * Transform the `
    ` element. Return a new Node will replace the original one.
    +     */
    +    pre?: (this: ShikiTransformerContext, hast: Element) => Element | void;
    +    /**
    +     * Transform the `` element. Return a new Node will replace the original one.
    +     */
    +    code?: (this: ShikiTransformerContext, hast: Element) => Element | void;
    +    /**
    +     * Transform each line `` element.
    +     *
    +     * @param hast
    +     * @param line 1-based line number
    +     */
    +    line?: (this: ShikiTransformerContext, hast: Element, line: number) => Element | void;
    +    /**
    +     * Transform each token `` element.
    +     */
    +    span?: (this: ShikiTransformerContext, hast: Element, line: number, col: number, lineElement: Element) => Element | void;
    +    /**
    +     * Transform the generated HTML string before returning.
    +     * This hook will only be called with `codeToHtml`.
    +     */
    +    postprocess?: (this: ShikiTransformerContextCommon, html: string, options: CodeToHastOptions) => string | void;
    +}
    +
    +interface DecorationOptions {
    +    /**
    +     * Custom decorations to wrap highlighted tokens with.
    +     */
    +    decorations?: DecorationItem[];
    +}
    +interface DecorationItem {
    +    /**
    +     * Start offset or position of the decoration.
    +     */
    +    start: OffsetOrPosition;
    +    /**
    +     * End offset or position of the decoration.
    +     */
    +    end: OffsetOrPosition;
    +    /**
    +     * Tag name of the element to create.
    +     * @default 'span'
    +     */
    +    tagName?: string;
    +    /**
    +     * Properties of the element to create.
    +     */
    +    properties?: Element['properties'];
    +    /**
    +     * A custom function to transform the element after it has been created.
    +     */
    +    transform?: (element: Element, type: DecorationTransformType) => Element | void;
    +    /**
    +     * By default when the decoration contains only one token, the decoration will be applied to the token.
    +     *
    +     * Set to `true` to always wrap the token with a new element
    +     *
    +     * @default false
    +     */
    +    alwaysWrap?: boolean;
    +}
    +interface ResolvedDecorationItem extends Omit {
    +    start: ResolvedPosition;
    +    end: ResolvedPosition;
    +}
    +type DecorationTransformType = 'wrapper' | 'line' | 'token';
    +interface Position {
    +    line: number;
    +    character: number;
    +}
    +type Offset = number;
    +type OffsetOrPosition = Position | Offset;
    +interface ResolvedPosition extends Position {
    +    offset: Offset;
    +}
    +
    +interface HighlighterCoreOptions {
    +    /**
    +     * Theme names, or theme registration objects to be loaded upfront.
    +     */
    +    themes?: ThemeInput[];
    +    /**
    +     * Language names, or language registration objects to be loaded upfront.
    +     */
    +    langs?: LanguageInput[];
    +    /**
    +     * Alias of languages
    +     * @example { 'my-lang': 'javascript' }
    +     */
    +    langAlias?: Record;
    +    /**
    +     * Load wasm file from a custom path or using a custom function.
    +     */
    +    loadWasm?: LoadWasmOptions;
    +    /**
    +     * Emit console warnings to alert users of potential issues.
    +     * @default true
    +     */
    +    warnings?: boolean;
    +}
    +interface BundledHighlighterOptions {
    +    /**
    +     * Theme registation
    +     *
    +     * @default []
    +     */
    +    themes: (ThemeInput | StringLiteralUnion | SpecialTheme)[];
    +    /**
    +     * Language registation
    +     *
    +     * @default []
    +     */
    +    langs: (LanguageInput | StringLiteralUnion | SpecialLanguage)[];
    +    /**
    +     * Alias of languages
    +     * @example { 'my-lang': 'javascript' }
    +     */
    +    langAlias?: Record>;
    +}
    +interface CodeOptionsSingleTheme {
    +    theme: ThemeRegistrationAny | StringLiteralUnion;
    +}
    +interface CodeOptionsMultipleThemes {
    +    /**
    +     * A map of color names to themes.
    +     * This allows you to specify multiple themes for the generated code.
    +     *
    +     * ```ts
    +     * highlighter.codeToHtml(code, {
    +     *   lang: 'js',
    +     *   themes: {
    +     *     light: 'vitesse-light',
    +     *     dark: 'vitesse-dark',
    +     *   }
    +     * })
    +     * ```
    +     *
    +     * Will generate:
    +     *
    +     * ```html
    +     * code
    +     * ```
    +     *
    +     * @see https://github.com/shikijs/shiki#lightdark-dual-themes
    +     */
    +    themes: Partial>>;
    +    /**
    +     * The default theme applied to the code (via inline `color` style).
    +     * The rest of the themes are applied via CSS variables, and toggled by CSS overrides.
    +     *
    +     * For example, if `defaultColor` is `light`, then `light` theme is applied to the code,
    +     * and the `dark` theme and other custom themes are applied via CSS variables:
    +     *
    +     * ```html
    +     * code
    +     * ```
    +     *
    +     * When set to `false`, no default styles will be applied, and totally up to users to apply the styles:
    +     *
    +     * ```html
    +     * code
    +     * ```
    +     *
    +     *
    +     * @default 'light'
    +     */
    +    defaultColor?: StringLiteralUnion<'light' | 'dark'> | false;
    +    /**
    +     * Prefix of CSS variables used to store the color of the other theme.
    +     *
    +     * @default '--shiki-'
    +     */
    +    cssVariablePrefix?: string;
    +}
    +type CodeOptionsThemes = CodeOptionsSingleTheme | CodeOptionsMultipleThemes;
    +type CodeToHastOptions = CodeToHastOptionsCommon & CodeOptionsThemes & CodeOptionsMeta;
    +interface CodeToHastOptionsCommon extends TransformerOptions, DecorationOptions, Pick {
    +    lang: StringLiteralUnion;
    +    /**
    +     * Merge whitespace tokens to saving extra ``.
    +     *
    +     * When set to true, it will merge whitespace tokens with the next token.
    +     * When set to false, it keep the output as-is.
    +     * When set to `never`, it will force to separate leading and trailing spaces from tokens.
    +     *
    +     * @default true
    +     */
    +    mergeWhitespaces?: boolean | 'never';
    +    /**
    +     * The structure of the generated HAST and HTML.
    +     *
    +     * - `classic`: The classic structure with `
    ` and `` elements, each line wrapped with a `` element.
    +     * - `inline`: All tokens are rendered as ``, line breaks are rendered as `
    `. No `
    ` or `` elements. Default forground and background colors are not applied.
    +     *
    +     * @default 'classic'
    +     */
    +    structure?: 'classic' | 'inline';
    +}
    +interface CodeOptionsMeta {
    +    /**
    +     * Meta data passed to Shiki, usually used by plugin integrations to pass the code block header.
    +     *
    +     * Key values in meta will be serialized to the attributes of the root `
    ` element.
    +     *
    +     * Keys starting with `_` will be ignored.
    +     *
    +     * A special key `__raw` key will be used to pass the raw code block header (if the integration supports it).
    +     */
    +    meta?: {
    +        /**
    +         * Raw string of the code block header.
    +         */
    +        __raw?: string;
    +        [key: string]: any;
    +    };
    +}
    +interface CodeToHastRenderOptionsCommon extends TransformerOptions, Omit {
    +    lang?: string;
    +    langId?: string;
    +}
    +type CodeToHastRenderOptions = CodeToHastRenderOptionsCommon & CodeToHastOptions;
    +
    +interface CodeToTokensBaseOptions extends TokenizeWithThemeOptions {
    +    lang?: Languages | SpecialLanguage;
    +    theme?: Themes | ThemeRegistrationAny | SpecialTheme;
    +}
    +type CodeToTokensOptions = Omit, 'theme'> & CodeOptionsThemes;
    +interface CodeToTokensWithThemesOptions {
    +    lang?: Languages | SpecialLanguage;
    +    /**
    +     * A map of color names to themes.
    +     *
    +     * `light` and `dark` are required, and arbitrary color names can be added.
    +     *
    +     * @example
    +     * ```ts
    +     * themes: {
    +     *   light: 'vitesse-light',
    +     *   dark: 'vitesse-dark',
    +     *   soft: 'nord',
    +     *   // custom colors
    +     * }
    +     * ```
    +     */
    +    themes: Partial>;
    +}
    +interface ThemedTokenScopeExplanation {
    +    scopeName: string;
    +    themeMatches?: IRawThemeSetting[];
    +}
    +interface ThemedTokenExplanation {
    +    content: string;
    +    scopes: ThemedTokenScopeExplanation[];
    +}
    +/**
    + * A single token with color, and optionally with explanation.
    + *
    + * For example:
    + *
    + * ```json
    + * {
    + *   "content": "shiki",
    + *   "color": "#D8DEE9",
    + *   "explanation": [
    + *     {
    + *       "content": "shiki",
    + *       "scopes": [
    + *         {
    + *           "scopeName": "source.js",
    + *           "themeMatches": []
    + *         },
    + *         {
    + *           "scopeName": "meta.objectliteral.js",
    + *           "themeMatches": []
    + *         },
    + *         {
    + *           "scopeName": "meta.object.member.js",
    + *           "themeMatches": []
    + *         },
    + *         {
    + *           "scopeName": "meta.array.literal.js",
    + *           "themeMatches": []
    + *         },
    + *         {
    + *           "scopeName": "variable.other.object.js",
    + *           "themeMatches": [
    + *             {
    + *               "name": "Variable",
    + *               "scope": "variable.other",
    + *               "settings": {
    + *                 "foreground": "#D8DEE9"
    + *               }
    + *             },
    + *             {
    + *               "name": "[JavaScript] Variable Other Object",
    + *               "scope": "source.js variable.other.object",
    + *               "settings": {
    + *                 "foreground": "#D8DEE9"
    + *               }
    + *             }
    + *           ]
    + *         }
    + *       ]
    + *     }
    + *   ]
    + * }
    + * ```
    + */
    +interface ThemedToken extends TokenStyles, TokenBase {
    +}
    +interface TokenBase {
    +    /**
    +     * The content of the token
    +     */
    +    content: string;
    +    /**
    +     * The start offset of the token, relative to the input code. 0-indexed.
    +     */
    +    offset: number;
    +    /**
    +     * Explanation of
    +     *
    +     * - token text's matching scopes
    +     * - reason that token text is given a color (one matching scope matches a rule (scope -> color) in the theme)
    +     */
    +    explanation?: ThemedTokenExplanation[];
    +}
    +interface TokenStyles {
    +    /**
    +     * 6 or 8 digit hex code representation of the token's color
    +     */
    +    color?: string;
    +    /**
    +     * 6 or 8 digit hex code representation of the token's background color
    +     */
    +    bgColor?: string;
    +    /**
    +     * Font style of token. Can be None/Italic/Bold/Underline
    +     */
    +    fontStyle?: FontStyle;
    +    /**
    +     * Override with custom inline style for HTML renderer.
    +     * When specified, `color` and `fontStyle` will be ignored.
    +     */
    +    htmlStyle?: string;
    +}
    +interface ThemedTokenWithVariants extends TokenBase {
    +    /**
    +     * An object of color name to token styles
    +     */
    +    variants: Record;
    +}
    +interface TokenizeWithThemeOptions {
    +    /**
    +     * Include explanation of why a token is given a color.
    +     *
    +     * You can optionally pass `scopeName` to only include explanation for scopes,
    +     * which is more performant than full explanation.
    +     *
    +     * @default false
    +     */
    +    includeExplanation?: boolean | 'scopeName';
    +    /**
    +     * A map of color names to new color values.
    +     *
    +     * The color key starts with '#' and should be lowercased.
    +     *
    +     * This will be merged with theme's `colorReplacements` if any.
    +     */
    +    colorReplacements?: Record>;
    +    /**
    +     * Lines above this length will not be tokenized for performance reasons.
    +     *
    +     * @default 0 (no limit)
    +     */
    +    tokenizeMaxLineLength?: number;
    +    /**
    +     * Time limit in milliseconds for tokenizing a single line.
    +     *
    +     * @default 500 (0.5s)
    +     */
    +    tokenizeTimeLimit?: number;
    +    /**
    +     * Represent the state of the grammar, allowing to continue tokenizing from a intermediate grammar state.
    +     *
    +     * You can get the grammar state from `getLastGrammarState`.
    +     */
    +    grammarState?: GrammarState;
    +    /**
    +     * The code context of the grammar.
    +     * Consider it a prepended code to the input code, that only participate the grammar inference but not presented in the final output.
    +     *
    +     * This will be ignored if `grammarState` is provided.
    +     */
    +    grammarContextCode?: string;
    +}
    +/**
    + * Result of `codeToTokens`, an object with 2D array of tokens and meta info like background and foreground color.
    + */
    +interface TokensResult {
    +    /**
    +     * 2D array of tokens, first dimension is lines, second dimension is tokens in a line.
    +     */
    +    tokens: ThemedToken[][];
    +    /**
    +     * Foreground color of the code.
    +     */
    +    fg?: string;
    +    /**
    +     * Background color of the code.
    +     */
    +    bg?: string;
    +    /**
    +     * A string representation of themes applied to the token.
    +     */
    +    themeName?: string;
    +    /**
    +     * Custom style string to be applied to the root `
    ` element.
    +     * When specified, `fg` and `bg` will be ignored.
    +     */
    +    rootStyle?: string;
    +}
    +declare enum FontStyle {
    +    NotSet = -1,
    +    None = 0,
    +    Italic = 1,
    +    Bold = 2,
    +    Underline = 4
    +}
    +
    +export { type ThemedTokenScopeExplanation as $, type AnsiLanguage as A, type BundledHighlighterOptions as B, type CodeToHastOptions as C, type ResolveBundleKey as D, type LanguageRegistration as E, FontStyle as F, GrammarState as G, type HighlighterCoreOptions as H, INITIAL as I, type BundledLanguageInfo as J, type DynamicImportLanguageRegistration as K, type LanguageInput as L, type MaybeArray as M, type CodeOptionsSingleTheme as N, type CodeOptionsMultipleThemes as O, type PlainTextLanguage as P, type CodeOptionsThemes as Q, Registry as R, type StateStack as S, Theme as T, type CodeToHastOptionsCommon as U, type CodeOptionsMeta as V, type CodeToHastRenderOptionsCommon as W, type ThemeRegistrationRaw as X, type ThemeRegistration as Y, type DynamicImportThemeRegistration as Z, type BundledThemeInfo as _, type IRawTheme as a, type ThemedTokenExplanation as a0, type TokenBase as a1, type TransformerOptions as a2, type ShikiTransformerContextMeta as a3, type ShikiTransformerContext as a4, type Awaitable as a5, type MaybeGetter as a6, type MaybeModule as a7, type StringLiteralUnion as a8, type DecorationOptions as a9, type DecorationItem as aa, type ResolvedDecorationItem as ab, type DecorationTransformType as ac, type Offset as ad, type OffsetOrPosition as ae, type ResolvedPosition as af, type IRawGrammar as b, type IGrammar as c, type IGrammarConfiguration as d, type IOnigLib as e, type RegistryOptions as f, type IRawThemeSetting as g, type ThemeInput as h, type CodeToTokensOptions as i, type TokensResult as j, type RequireKeys as k, type CodeToTokensBaseOptions as l, type ThemedToken as m, type CodeToTokensWithThemesOptions as n, type ThemedTokenWithVariants as o, type SpecialLanguage as p, type SpecialTheme as q, type ThemeRegistrationAny as r, type TokenizeWithThemeOptions as s, type TokenStyles as t, type Position as u, type ThemeRegistrationResolved as v, type ShikiTransformerContextCommon as w, type CodeToHastRenderOptions as x, type ShikiTransformerContextSource as y, type ShikiTransformer as z };
    diff --git a/node_modules/@shikijs/core/dist/index.d.mts b/node_modules/@shikijs/core/dist/index.d.mts
    new file mode 100644
    index 0000000..b98821f
    --- /dev/null
    +++ b/node_modules/@shikijs/core/dist/index.d.mts
    @@ -0,0 +1,423 @@
    +import { HighlighterCore, HighlighterGeneric, ShikiInternal } from './types.mjs';
    +export { Grammar } from './types.mjs';
    +import { H as HighlighterCoreOptions, B as BundledHighlighterOptions, L as LanguageInput, h as ThemeInput, C as CodeToHastOptions, i as CodeToTokensOptions, j as TokensResult, k as RequireKeys, l as CodeToTokensBaseOptions, m as ThemedToken, n as CodeToTokensWithThemesOptions, o as ThemedTokenWithVariants, G as GrammarState, M as MaybeArray, P as PlainTextLanguage, p as SpecialLanguage, q as SpecialTheme, r as ThemeRegistrationAny, s as TokenizeWithThemeOptions, t as TokenStyles, u as Position, c as IGrammar, v as ThemeRegistrationResolved, w as ShikiTransformerContextCommon, x as CodeToHastRenderOptions, y as ShikiTransformerContextSource, z as ShikiTransformer } from './chunk-tokens.mjs';
    +export { A as AnsiLanguage, a5 as Awaitable, J as BundledLanguageInfo, _ as BundledThemeInfo, V as CodeOptionsMeta, O as CodeOptionsMultipleThemes, N as CodeOptionsSingleTheme, Q as CodeOptionsThemes, U as CodeToHastOptionsCommon, W as CodeToHastRenderOptionsCommon, aa as DecorationItem, a9 as DecorationOptions, ac as DecorationTransformType, K as DynamicImportLanguageRegistration, Z as DynamicImportThemeRegistration, F as FontStyle, E as LanguageRegistration, a6 as MaybeGetter, a7 as MaybeModule, ad as Offset, ae as OffsetOrPosition, b as RawGrammar, a as RawTheme, g as RawThemeSetting, D as ResolveBundleKey, ab as ResolvedDecorationItem, af as ResolvedPosition, a4 as ShikiTransformerContext, a3 as ShikiTransformerContextMeta, a8 as StringLiteralUnion, Y as ThemeRegistration, X as ThemeRegistrationRaw, a0 as ThemedTokenExplanation, $ as ThemedTokenScopeExplanation, a1 as TokenBase, a2 as TransformerOptions } from './chunk-tokens.mjs';
    +import * as hast from 'hast';
    +import { Root, Element } from 'hast';
    +import { L as LoadWasmOptions } from './chunk-index.mjs';
    +export { W as WebAssemblyInstantiator, l as loadWasm } from './chunk-index.mjs';
    +
    +/**
    + * Create a Shiki core highlighter instance, with no languages or themes bundled.
    + * Wasm and each language and theme must be loaded manually.
    + *
    + * @see http://shiki.style/guide/install#fine-grained-bundle
    + */
    +declare function createHighlighterCore(options?: HighlighterCoreOptions): Promise;
    +declare function makeSingletonHighlighterCore(createHighlighter: typeof createHighlighterCore): (options?: Partial) => Promise;
    +declare const getSingletonHighlighterCore: (options?: Partial) => Promise;
    +/**
    + * @deprecated Use `createHighlighterCore` or `getSingletonHighlighterCore` instead.
    + */
    +declare function getHighlighterCore(options?: HighlighterCoreOptions): Promise;
    +
    +type CreateHighlighterFactory = (options: BundledHighlighterOptions) => Promise>;
    +/**
    + * Create a `createHighlighter` function with bundled themes and languages.
    + *
    + * @param bundledLanguages
    + * @param bundledThemes
    + * @param loadWasm
    + */
    +declare function createdBundledHighlighter(bundledLanguages: Record, bundledThemes: Record, loadWasm: HighlighterCoreOptions['loadWasm']): CreateHighlighterFactory;
    +interface ShorthandsBundle {
    +    /**
    +     * Shorthand for `codeToHtml` with auto-loaded theme and language.
    +     * A singleton highlighter it maintained internally.
    +     *
    +     * Differences from `highlighter.codeToHtml()`, this function is async.
    +     */
    +    codeToHtml: (code: string, options: CodeToHastOptions) => Promise;
    +    /**
    +     * Shorthand for `codeToHtml` with auto-loaded theme and language.
    +     * A singleton highlighter it maintained internally.
    +     *
    +     * Differences from `highlighter.codeToHtml()`, this function is async.
    +     */
    +    codeToHast: (code: string, options: CodeToHastOptions) => Promise;
    +    /**
    +     * Shorthand for `codeToTokens` with auto-loaded theme and language.
    +     * A singleton highlighter it maintained internally.
    +     *
    +     * Differences from `highlighter.codeToTokens()`, this function is async.
    +     */
    +    codeToTokens: (code: string, options: CodeToTokensOptions) => Promise;
    +    /**
    +     * Shorthand for `codeToTokensBase` with auto-loaded theme and language.
    +     * A singleton highlighter it maintained internally.
    +     *
    +     * Differences from `highlighter.codeToTokensBase()`, this function is async.
    +     */
    +    codeToTokensBase: (code: string, options: RequireKeys, 'theme' | 'lang'>) => Promise;
    +    /**
    +     * Shorthand for `codeToTokensWithThemes` with auto-loaded theme and language.
    +     * A singleton highlighter it maintained internally.
    +     *
    +     * Differences from `highlighter.codeToTokensWithThemes()`, this function is async.
    +     */
    +    codeToTokensWithThemes: (code: string, options: RequireKeys, 'themes' | 'lang'>) => Promise;
    +    /**
    +     * Get the singleton highlighter.
    +     */
    +    getSingletonHighlighter: (options?: Partial>) => Promise>;
    +    /**
    +     * Shorthand for `getLastGrammarState` with auto-loaded theme and language.
    +     * A singleton highlighter it maintained internally.
    +     */
    +    getLastGrammarState: (code: string, options: CodeToTokensBaseOptions) => Promise;
    +}
    +declare function makeSingletonHighlighter(createHighlighter: CreateHighlighterFactory): (options?: Partial>) => Promise>;
    +declare function createSingletonShorthands(createHighlighter: CreateHighlighterFactory): ShorthandsBundle;
    +
    +declare function toArray(x: MaybeArray): T[];
    +/**
    + * Split a string into lines, each line preserves the line ending.
    + */
    +declare function splitLines(code: string, preserveEnding?: boolean): [string, number][];
    +/**
    + * Check if the language is plaintext that is ignored by Shiki.
    + *
    + * Hard-coded plain text languages: `plaintext`, `txt`, `text`, `plain`.
    + */
    +declare function isPlainLang(lang: string | null | undefined): lang is PlainTextLanguage;
    +/**
    + * Check if the language is specially handled or bypassed by Shiki.
    + *
    + * Hard-coded languages: `ansi` and plaintexts like `plaintext`, `txt`, `text`, `plain`.
    + */
    +declare function isSpecialLang(lang: any): lang is SpecialLanguage;
    +/**
    + * Check if the theme is specially handled or bypassed by Shiki.
    + *
    + * Hard-coded themes: `none`.
    + */
    +declare function isNoneTheme(theme: string | ThemeInput | null | undefined): theme is 'none';
    +/**
    + * Check if the theme is specially handled or bypassed by Shiki.
    + *
    + * Hard-coded themes: `none`.
    + */
    +declare function isSpecialTheme(theme: string | ThemeInput | null | undefined): theme is SpecialTheme;
    +/**
    + * Utility to append class to a hast node
    + *
    + * If the `property.class` is a string, it will be splitted by space and converted to an array.
    + */
    +declare function addClassToHast(node: Element, className: string | string[]): Element;
    +/**
    + * Split a token into multiple tokens by given offsets.
    + *
    + * The offsets are relative to the token, and should be sorted.
    + */
    +declare function splitToken>(token: T, offsets: number[]): T[];
    +/**
    + * Split 2D tokens array by given breakpoints.
    + */
    +declare function splitTokens>(tokens: T[][], breakpoints: number[] | Set): T[][];
    +declare function resolveColorReplacements(theme: ThemeRegistrationAny | string, options?: TokenizeWithThemeOptions): {
    +    [x: string]: string;
    +};
    +declare function applyColorReplacements(color: string, replacements?: Record): string;
    +declare function applyColorReplacements(color?: string | undefined, replacements?: Record): string | undefined;
    +declare function getTokenStyleObject(token: TokenStyles): Record;
    +declare function stringifyTokenStyle(token: Record): string;
    +/**
    + * Creates a converter between index and position in a code block.
    + *
    + * Overflow/underflow are unchecked.
    + */
    +declare function createPositionConverter(code: string): {
    +    lines: string[];
    +    indexToPos: (index: number) => Position;
    +    posToIndex: (line: number, character: number) => number;
    +};
    +
    +/**
    + * Set the default wasm loader for `loadWasm`.
    + * @internal
    + */
    +declare function setDefaultWasmLoader(_loader: LoadWasmOptions): void;
    +/**
    + * Get the minimal shiki context for rendering.
    + */
    +declare function createShikiInternal(options?: HighlighterCoreOptions): Promise;
    +/**
    + * @deprecated Use `createShikiInternal` instead.
    + */
    +declare function getShikiInternal(options?: HighlighterCoreOptions): Promise;
    +
    +/**
    + * Code to tokens, with a simple theme.
    + */
    +declare function codeToTokensBase(internal: ShikiInternal, code: string, options?: CodeToTokensBaseOptions): ThemedToken[][];
    +declare function tokenizeWithTheme(code: string, grammar: IGrammar, theme: ThemeRegistrationResolved, colorMap: string[], options: TokenizeWithThemeOptions): ThemedToken[][];
    +
    +/**
    + * High-level code-to-tokens API.
    + *
    + * It will use `codeToTokensWithThemes` or `codeToTokensBase` based on the options.
    + */
    +declare function codeToTokens(internal: ShikiInternal, code: string, options: CodeToTokensOptions): TokensResult;
    +
    +declare function tokenizeAnsiWithTheme(theme: ThemeRegistrationResolved, fileContents: string, options?: TokenizeWithThemeOptions): ThemedToken[][];
    +
    +declare function codeToHast(internal: ShikiInternal, code: string, options: CodeToHastOptions, transformerContext?: ShikiTransformerContextCommon): Root;
    +declare function tokensToHast(tokens: ThemedToken[][], options: CodeToHastRenderOptions, transformerContext: ShikiTransformerContextSource): Root;
    +
    +type FormatSmartOptions = {
    +  /**
    +   * Prefer named character references (`&`) where possible.
    +   */
    +  useNamedReferences?: boolean | undefined
    +  /**
    +   * Prefer the shortest possible reference, if that results in less bytes.
    +   * **Note**: `useNamedReferences` can be omitted when using `useShortestReferences`.
    +   */
    +  useShortestReferences?: boolean | undefined
    +  /**
    +   * Whether to omit semicolons when possible.
    +   * **Note**: This creates what HTML calls “parse errors” but is otherwise still valid HTML — don’t use this except when building a minifier.
    +   * Omitting semicolons is possible for certain named and numeric references in some cases.
    +   */
    +  omitOptionalSemicolons?: boolean | undefined
    +  /**
    +   * Create character references which don’t fail in attributes.
    +   * **Note**: `attribute` only applies when operating dangerously with
    +   * `omitOptionalSemicolons: true`.
    +   */
    +  attribute?: boolean | undefined
    +}
    +
    +type CoreOptions = {
    +  /**
    +   * Whether to only escape the given subset of characters.
    +   */
    +  subset?: string[] | undefined
    +  /**
    +   * Whether to only escape possibly dangerous characters.
    +   * Those characters are `"`, `&`, `'`, `<`, `>`, and `` ` ``.
    +   */
    +  escapeOnly?: boolean | undefined
    +}
    +
    +type Options$2 = CoreOptions &
    +  FormatSmartOptions
    +
    +type Options$1 = Options$2
    +
    +/**
    + * Serialize hast as HTML.
    + *
    + * @param {Array | Nodes} tree
    + *   Tree to serialize.
    + * @param {Options | null | undefined} [options]
    + *   Configuration (optional).
    + * @returns {string}
    + *   Serialized HTML.
    + */
    +declare function toHtml(tree: Array | Nodes, options?: Options | null | undefined): string;
    +type Nodes = hast.Nodes;
    +type RootContent = hast.RootContent;
    +type StringifyEntitiesOptions = Options$1;
    +type CharacterReferences = Omit;
    +/**
    + * Configuration.
    + */
    +type Options = {
    +    /**
    +     * Do not encode some characters which cause XSS vulnerabilities in older
    +     * browsers (default: `false`).
    +     *
    +     * > ⚠️ **Danger**: only set this if you completely trust the content.
    +     */
    +    allowDangerousCharacters?: boolean | null | undefined;
    +    /**
    +     * Allow `raw` nodes and insert them as raw HTML (default: `false`).
    +     *
    +     * When `false`, `Raw` nodes are encoded.
    +     *
    +     * > ⚠️ **Danger**: only set this if you completely trust the content.
    +     */
    +    allowDangerousHtml?: boolean | null | undefined;
    +    /**
    +     * Do not encode characters which cause parse errors (even though they work),
    +     * to save bytes (default: `false`).
    +     *
    +     * Not used in the SVG space.
    +     *
    +     * > 👉 **Note**: intentionally creates parse errors in markup (how parse
    +     * > errors are handled is well defined, so this works but isn’t pretty).
    +     */
    +    allowParseErrors?: boolean | null | undefined;
    +    /**
    +     * Use “bogus comments” instead of comments to save byes: ``
    +     * instead of `` (default: `false`).
    +     *
    +     * > 👉 **Note**: intentionally creates parse errors in markup (how parse
    +     * > errors are handled is well defined, so this works but isn’t pretty).
    +     */
    +    bogusComments?: boolean | null | undefined;
    +    /**
    +     * Configure how to serialize character references (optional).
    +     */
    +    characterReferences?: CharacterReferences | null | undefined;
    +    /**
    +     * Close SVG elements without any content with slash (`/`) on the opening tag
    +     * instead of an end tag: `` instead of ``
    +     * (default: `false`).
    +     *
    +     * See `tightSelfClosing` to control whether a space is used before the
    +     * slash.
    +     *
    +     * Not used in the HTML space.
    +     */
    +    closeEmptyElements?: boolean | null | undefined;
    +    /**
    +     * Close self-closing nodes with an extra slash (`/`): `` instead of
    +     * `` (default: `false`).
    +     *
    +     * See `tightSelfClosing` to control whether a space is used before the
    +     * slash.
    +     *
    +     * Not used in the SVG space.
    +     */
    +    closeSelfClosing?: boolean | null | undefined;
    +    /**
    +     * Collapse empty attributes: get `class` instead of `class=""` (default:
    +     * `false`).
    +     *
    +     * Not used in the SVG space.
    +     *
    +     * > 👉 **Note**: boolean attributes (such as `hidden`) are always collapsed.
    +     */
    +    collapseEmptyAttributes?: boolean | null | undefined;
    +    /**
    +     * Omit optional opening and closing tags (default: `false`).
    +     *
    +     * For example, in `
    1. one
    2. two
    `, both `` closing + * tags can be omitted. + * The first because it’s followed by another `li`, the last because it’s + * followed by nothing. + * + * Not used in the SVG space. + */ + omitOptionalTags?: boolean | null | undefined; + /** + * Leave attributes unquoted if that results in less bytes (default: `false`). + * + * Not used in the SVG space. + */ + preferUnquoted?: boolean | null | undefined; + /** + * Preferred quote to use (default: `'"'`). + */ + quote?: Quote | null | undefined; + /** + * Use the other quote if that results in less bytes (default: `false`). + */ + quoteSmart?: boolean | null | undefined; + /** + * When an `` element is found in the HTML space, this package already + * automatically switches to and from the SVG space when entering and exiting + * it (default: `'html'`). + * + * > 👉 **Note**: hast is not XML. + * > It supports SVG as embedded in HTML. + * > It does not support the features available in XML. + * > Passing SVG might break but fragments of modern SVG should be fine. + * > Use [`xast`][xast] if you need to support SVG as XML. + */ + space?: Space | null | undefined; + /** + * Join attributes together, without whitespace, if possible: get + * `class="a b"title="c d"` instead of `class="a b" title="c d"` to save + * bytes (default: `false`). + * + * Not used in the SVG space. + * + * > 👉 **Note**: intentionally creates parse errors in markup (how parse + * > errors are handled is well defined, so this works but isn’t pretty). + */ + tightAttributes?: boolean | null | undefined; + /** + * Join known comma-separated attribute values with just a comma (`,`), + * instead of padding them on the right as well (`,␠`, where `␠` represents a + * space) (default: `false`). + */ + tightCommaSeparatedLists?: boolean | null | undefined; + /** + * Drop unneeded spaces in doctypes: `` instead of + * `` to save bytes (default: `false`). + * + * > 👉 **Note**: intentionally creates parse errors in markup (how parse + * > errors are handled is well defined, so this works but isn’t pretty). + */ + tightDoctype?: boolean | null | undefined; + /** + * Do not use an extra space when closing self-closing elements: `` + * instead of `` (default: `false`). + * + * > 👉 **Note**: only used if `closeSelfClosing: true` or + * > `closeEmptyElements: true`. + */ + tightSelfClosing?: boolean | null | undefined; + /** + * Use a ` 👉 **Note**: It’s highly unlikely that you want to pass this, because + * > hast is not for XML, and HTML will not add more void elements. + */ + voids?: ReadonlyArray | null | undefined; +}; +/** + * HTML quotes for attribute values. + */ +type Quote = '"' | "'"; +/** + * Namespace. + */ +type Space = 'html' | 'svg'; + +/** + * Get highlighted code in HTML. + */ +declare function codeToHtml(internal: ShikiInternal, code: string, options: CodeToHastOptions): string; + +/** + * Get tokens with multiple themes + */ +declare function codeToTokensWithThemes(internal: ShikiInternal, code: string, options: CodeToTokensWithThemesOptions): ThemedTokenWithVariants[][]; + +/** + * Normalize a textmate theme to shiki theme + */ +declare function normalizeTheme(rawTheme: ThemeRegistrationAny): ThemeRegistrationResolved; + +/** + * A built-in transformer to add decorations to the highlighted code. + */ +declare function transformerDecorations(): ShikiTransformer; + +declare class ShikiError extends Error { + constructor(message: string); +} + +export { BundledHighlighterOptions, CodeToHastOptions, CodeToHastRenderOptions, CodeToTokensBaseOptions, CodeToTokensOptions, CodeToTokensWithThemesOptions, type CreateHighlighterFactory, GrammarState, HighlighterCore, HighlighterCoreOptions, HighlighterGeneric, LanguageInput, MaybeArray, PlainTextLanguage, Position, RequireKeys, ShikiError, ShikiInternal, ShikiTransformer, ShikiTransformerContextCommon, ShikiTransformerContextSource, type ShorthandsBundle, SpecialLanguage, SpecialTheme, ThemeInput, ThemeRegistrationAny, ThemeRegistrationResolved, ThemedToken, ThemedTokenWithVariants, TokenStyles, TokenizeWithThemeOptions, TokensResult, addClassToHast, applyColorReplacements, codeToHast, codeToHtml, codeToTokens, codeToTokensBase, codeToTokensWithThemes, createHighlighterCore, createPositionConverter, createShikiInternal, createSingletonShorthands, createdBundledHighlighter, getHighlighterCore, getShikiInternal, getSingletonHighlighterCore, getTokenStyleObject, toHtml as hastToHtml, isNoneTheme, isPlainLang, isSpecialLang, isSpecialTheme, makeSingletonHighlighter, makeSingletonHighlighterCore, normalizeTheme, resolveColorReplacements, setDefaultWasmLoader, splitLines, splitToken, splitTokens, stringifyTokenStyle, toArray, tokenizeAnsiWithTheme, tokenizeWithTheme, tokensToHast, transformerDecorations }; diff --git a/node_modules/@shikijs/core/dist/index.mjs b/node_modules/@shikijs/core/dist/index.mjs new file mode 100644 index 0000000..08b0760 --- /dev/null +++ b/node_modules/@shikijs/core/dist/index.mjs @@ -0,0 +1,5795 @@ +import { INITIAL, StackElementMetadata, Registry as Registry$1, Theme } from './textmate.mjs'; +import { FontStyle } from './types.mjs'; + +function toArray(x) { + return Array.isArray(x) ? x : [x]; +} +/** + * Split a string into lines, each line preserves the line ending. + */ +function splitLines(code, preserveEnding = false) { + const parts = code.split(/(\r?\n)/g); + let index = 0; + const lines = []; + for (let i = 0; i < parts.length; i += 2) { + const line = preserveEnding + ? parts[i] + (parts[i + 1] || '') + : parts[i]; + lines.push([line, index]); + index += parts[i].length; + index += parts[i + 1]?.length || 0; + } + return lines; +} +/** + * Check if the language is plaintext that is ignored by Shiki. + * + * Hard-coded plain text languages: `plaintext`, `txt`, `text`, `plain`. + */ +function isPlainLang(lang) { + return !lang || ['plaintext', 'txt', 'text', 'plain'].includes(lang); +} +/** + * Check if the language is specially handled or bypassed by Shiki. + * + * Hard-coded languages: `ansi` and plaintexts like `plaintext`, `txt`, `text`, `plain`. + */ +function isSpecialLang(lang) { + return lang === 'ansi' || isPlainLang(lang); +} +/** + * Check if the theme is specially handled or bypassed by Shiki. + * + * Hard-coded themes: `none`. + */ +function isNoneTheme(theme) { + return theme === 'none'; +} +/** + * Check if the theme is specially handled or bypassed by Shiki. + * + * Hard-coded themes: `none`. + */ +function isSpecialTheme(theme) { + return isNoneTheme(theme); +} +/** + * Utility to append class to a hast node + * + * If the `property.class` is a string, it will be splitted by space and converted to an array. + */ +function addClassToHast(node, className) { + if (!className) + return node; + node.properties ||= {}; + node.properties.class ||= []; + if (typeof node.properties.class === 'string') + node.properties.class = node.properties.class.split(/\s+/g); + if (!Array.isArray(node.properties.class)) + node.properties.class = []; + const targets = Array.isArray(className) ? className : className.split(/\s+/g); + for (const c of targets) { + if (c && !node.properties.class.includes(c)) + node.properties.class.push(c); + } + return node; +} +/** + * Split a token into multiple tokens by given offsets. + * + * The offsets are relative to the token, and should be sorted. + */ +function splitToken(token, offsets) { + let lastOffset = 0; + const tokens = []; + for (const offset of offsets) { + if (offset > lastOffset) { + tokens.push({ + ...token, + content: token.content.slice(lastOffset, offset), + offset: token.offset + lastOffset, + }); + } + lastOffset = offset; + } + if (lastOffset < token.content.length) { + tokens.push({ + ...token, + content: token.content.slice(lastOffset), + offset: token.offset + lastOffset, + }); + } + return tokens; +} +/** + * Split 2D tokens array by given breakpoints. + */ +function splitTokens(tokens, breakpoints) { + const sorted = Array.from(breakpoints instanceof Set ? breakpoints : new Set(breakpoints)) + .sort((a, b) => a - b); + if (!sorted.length) + return tokens; + return tokens.map((line) => { + return line.flatMap((token) => { + const breakpointsInToken = sorted + .filter(i => token.offset < i && i < token.offset + token.content.length) + .map(i => i - token.offset) + .sort((a, b) => a - b); + if (!breakpointsInToken.length) + return token; + return splitToken(token, breakpointsInToken); + }); + }); +} +function resolveColorReplacements(theme, options) { + const replacements = typeof theme === 'string' ? {} : { ...theme.colorReplacements }; + const themeName = typeof theme === 'string' ? theme : theme.name; + for (const [key, value] of Object.entries(options?.colorReplacements || {})) { + if (typeof value === 'string') + replacements[key] = value; + else if (key === themeName) + Object.assign(replacements, value); + } + return replacements; +} +function applyColorReplacements(color, replacements) { + if (!color) + return color; + return replacements?.[color?.toLowerCase()] || color; +} +function getTokenStyleObject(token) { + const styles = {}; + if (token.color) + styles.color = token.color; + if (token.bgColor) + styles['background-color'] = token.bgColor; + if (token.fontStyle) { + if (token.fontStyle & FontStyle.Italic) + styles['font-style'] = 'italic'; + if (token.fontStyle & FontStyle.Bold) + styles['font-weight'] = 'bold'; + if (token.fontStyle & FontStyle.Underline) + styles['text-decoration'] = 'underline'; + } + return styles; +} +function stringifyTokenStyle(token) { + return Object.entries(token).map(([key, value]) => `${key}:${value}`).join(';'); +} +/** + * Creates a converter between index and position in a code block. + * + * Overflow/underflow are unchecked. + */ +function createPositionConverter(code) { + const lines = splitLines(code, true).map(([line]) => line); + function indexToPos(index) { + if (index === code.length) { + return { + line: lines.length - 1, + character: lines[lines.length - 1].length, + }; + } + let character = index; + let line = 0; + for (const lineText of lines) { + if (character < lineText.length) + break; + character -= lineText.length; + line++; + } + return { line, character }; + } + function posToIndex(line, character) { + let index = 0; + for (let i = 0; i < line; i++) + index += lines[i].length; + index += character; + return index; + } + return { + lines, + indexToPos, + posToIndex, + }; +} + +// src/colors.ts +var namedColors = [ + "black", + "red", + "green", + "yellow", + "blue", + "magenta", + "cyan", + "white", + "brightBlack", + "brightRed", + "brightGreen", + "brightYellow", + "brightBlue", + "brightMagenta", + "brightCyan", + "brightWhite" +]; + +// src/decorations.ts +var decorations = { + 1: "bold", + 2: "dim", + 3: "italic", + 4: "underline", + 7: "reverse", + 9: "strikethrough" +}; + +// src/parser.ts +function findSequence(value, position) { + const nextEscape = value.indexOf("\x1B[", position); + if (nextEscape !== -1) { + const nextClose = value.indexOf("m", nextEscape); + return { + sequence: value.substring(nextEscape + 2, nextClose).split(";"), + startPosition: nextEscape, + position: nextClose + 1 + }; + } + return { + position: value.length + }; +} +function parseColor(sequence, index) { + let offset = 1; + const colorMode = sequence[index + offset++]; + let color; + if (colorMode === "2") { + const rgb = [ + sequence[index + offset++], + sequence[index + offset++], + sequence[index + offset] + ].map((x) => Number.parseInt(x)); + if (rgb.length === 3 && !rgb.some((x) => Number.isNaN(x))) { + color = { + type: "rgb", + rgb + }; + } + } else if (colorMode === "5") { + const colorIndex = Number.parseInt(sequence[index + offset]); + if (!Number.isNaN(colorIndex)) { + color = { type: "table", index: Number(colorIndex) }; + } + } + return [offset, color]; +} +function parseSequence(sequence) { + const commands = []; + for (let i = 0; i < sequence.length; i++) { + const code = sequence[i]; + const codeInt = Number.parseInt(code); + if (Number.isNaN(codeInt)) + continue; + if (codeInt === 0) { + commands.push({ type: "resetAll" }); + } else if (codeInt <= 9) { + const decoration = decorations[codeInt]; + if (decoration) { + commands.push({ + type: "setDecoration", + value: decorations[codeInt] + }); + } + } else if (codeInt <= 29) { + const decoration = decorations[codeInt - 20]; + if (decoration) { + commands.push({ + type: "resetDecoration", + value: decoration + }); + } + } else if (codeInt <= 37) { + commands.push({ + type: "setForegroundColor", + value: { type: "named", name: namedColors[codeInt - 30] } + }); + } else if (codeInt === 38) { + const [offset, color] = parseColor(sequence, i); + if (color) { + commands.push({ + type: "setForegroundColor", + value: color + }); + } + i += offset; + } else if (codeInt === 39) { + commands.push({ + type: "resetForegroundColor" + }); + } else if (codeInt <= 47) { + commands.push({ + type: "setBackgroundColor", + value: { type: "named", name: namedColors[codeInt - 40] } + }); + } else if (codeInt === 48) { + const [offset, color] = parseColor(sequence, i); + if (color) { + commands.push({ + type: "setBackgroundColor", + value: color + }); + } + i += offset; + } else if (codeInt === 49) { + commands.push({ + type: "resetBackgroundColor" + }); + } else if (codeInt >= 90 && codeInt <= 97) { + commands.push({ + type: "setForegroundColor", + value: { type: "named", name: namedColors[codeInt - 90 + 8] } + }); + } else if (codeInt >= 100 && codeInt <= 107) { + commands.push({ + type: "setBackgroundColor", + value: { type: "named", name: namedColors[codeInt - 100 + 8] } + }); + } + } + return commands; +} +function createAnsiSequenceParser() { + let foreground = null; + let background = null; + let decorations2 = /* @__PURE__ */ new Set(); + return { + parse(value) { + const tokens = []; + let position = 0; + do { + const findResult = findSequence(value, position); + const text = findResult.sequence ? value.substring(position, findResult.startPosition) : value.substring(position); + if (text.length > 0) { + tokens.push({ + value: text, + foreground, + background, + decorations: new Set(decorations2) + }); + } + if (findResult.sequence) { + const commands = parseSequence(findResult.sequence); + for (const styleToken of commands) { + if (styleToken.type === "resetAll") { + foreground = null; + background = null; + decorations2.clear(); + } else if (styleToken.type === "resetForegroundColor") { + foreground = null; + } else if (styleToken.type === "resetBackgroundColor") { + background = null; + } else if (styleToken.type === "resetDecoration") { + decorations2.delete(styleToken.value); + } + } + for (const styleToken of commands) { + if (styleToken.type === "setForegroundColor") { + foreground = styleToken.value; + } else if (styleToken.type === "setBackgroundColor") { + background = styleToken.value; + } else if (styleToken.type === "setDecoration") { + decorations2.add(styleToken.value); + } + } + } + position = findResult.position; + } while (position < value.length); + return tokens; + } + }; +} + +// src/palette.ts +var defaultNamedColorsMap = { + black: "#000000", + red: "#bb0000", + green: "#00bb00", + yellow: "#bbbb00", + blue: "#0000bb", + magenta: "#ff00ff", + cyan: "#00bbbb", + white: "#eeeeee", + brightBlack: "#555555", + brightRed: "#ff5555", + brightGreen: "#00ff00", + brightYellow: "#ffff55", + brightBlue: "#5555ff", + brightMagenta: "#ff55ff", + brightCyan: "#55ffff", + brightWhite: "#ffffff" +}; +function createColorPalette(namedColorsMap = defaultNamedColorsMap) { + function namedColor(name) { + return namedColorsMap[name]; + } + function rgbColor(rgb) { + return `#${rgb.map((x) => Math.max(0, Math.min(x, 255)).toString(16).padStart(2, "0")).join("")}`; + } + let colorTable; + function getColorTable() { + if (colorTable) { + return colorTable; + } + colorTable = []; + for (let i = 0; i < namedColors.length; i++) { + colorTable.push(namedColor(namedColors[i])); + } + let levels = [0, 95, 135, 175, 215, 255]; + for (let r = 0; r < 6; r++) { + for (let g = 0; g < 6; g++) { + for (let b = 0; b < 6; b++) { + colorTable.push(rgbColor([levels[r], levels[g], levels[b]])); + } + } + } + let level = 8; + for (let i = 0; i < 24; i++, level += 10) { + colorTable.push(rgbColor([level, level, level])); + } + return colorTable; + } + function tableColor(index) { + return getColorTable()[index]; + } + function value(color) { + switch (color.type) { + case "named": + return namedColor(color.name); + case "rgb": + return rgbColor(color.rgb); + case "table": + return tableColor(color.index); + } + } + return { + value + }; +} + +function tokenizeAnsiWithTheme(theme, fileContents, options) { + const colorReplacements = resolveColorReplacements(theme, options); + const lines = splitLines(fileContents); + const colorPalette = createColorPalette(Object.fromEntries(namedColors.map(name => [ + name, + theme.colors?.[`terminal.ansi${name[0].toUpperCase()}${name.substring(1)}`], + ]))); + const parser = createAnsiSequenceParser(); + return lines.map(line => parser.parse(line[0]).map((token) => { + let color; + let bgColor; + if (token.decorations.has('reverse')) { + color = token.background ? colorPalette.value(token.background) : theme.bg; + bgColor = token.foreground ? colorPalette.value(token.foreground) : theme.fg; + } + else { + color = token.foreground ? colorPalette.value(token.foreground) : theme.fg; + bgColor = token.background ? colorPalette.value(token.background) : undefined; + } + color = applyColorReplacements(color, colorReplacements); + bgColor = applyColorReplacements(bgColor, colorReplacements); + if (token.decorations.has('dim')) + color = dimColor(color); + let fontStyle = FontStyle.None; + if (token.decorations.has('bold')) + fontStyle |= FontStyle.Bold; + if (token.decorations.has('italic')) + fontStyle |= FontStyle.Italic; + if (token.decorations.has('underline')) + fontStyle |= FontStyle.Underline; + return { + content: token.value, + offset: line[1], // TODO: more accurate offset? might need to fork ansi-sequence-parser + color, + bgColor, + fontStyle, + }; + })); +} +/** + * Adds 50% alpha to a hex color string or the "-dim" postfix to a CSS variable + */ +function dimColor(color) { + const hexMatch = color.match(/#([0-9a-f]{3})([0-9a-f]{3})?([0-9a-f]{2})?/); + if (hexMatch) { + if (hexMatch[3]) { + // convert from #rrggbbaa to #rrggbb(aa/2) + const alpha = Math.round(Number.parseInt(hexMatch[3], 16) / 2) + .toString(16) + .padStart(2, '0'); + return `#${hexMatch[1]}${hexMatch[2]}${alpha}`; + } + else if (hexMatch[2]) { + // convert from #rrggbb to #rrggbb80 + return `#${hexMatch[1]}${hexMatch[2]}80`; + } + else { + // convert from #rgb to #rrggbb80 + return `#${Array.from(hexMatch[1]) + .map(x => `${x}${x}`) + .join('')}80`; + } + } + const cssVarMatch = color.match(/var\((--[\w-]+-ansi-[\w-]+)\)/); + if (cssVarMatch) + return `var(${cssVarMatch[1]}-dim)`; + return color; +} + +class ShikiError extends Error { + constructor(message) { + super(message); + this.name = 'ShikiError'; + } +} + +/** + * GrammarState is a special reference object that holds the state of a grammar. + * + * It's used to highlight code snippets that are part of the target language. + */ +class GrammarState { + _stack; + lang; + theme; + /** + * Static method to create a initial grammar state. + */ + static initial(lang, theme) { + return new GrammarState(INITIAL, lang, theme); + } + constructor(_stack, lang, theme) { + this._stack = _stack; + this.lang = lang; + this.theme = theme; + } + get scopes() { + return getScopes(this._stack); + } + toJSON() { + return { + lang: this.lang, + theme: this.theme, + scopes: this.scopes, + }; + } +} +function getScopes(stack) { + const scopes = []; + const visited = new Set(); + function pushScope(stack) { + if (visited.has(stack)) + return; + visited.add(stack); + const name = stack?.nameScopesList?.scopeName; + if (name) + scopes.push(name); + if (stack.parent) + pushScope(stack.parent); + } + pushScope(stack); + return scopes; +} +function getGrammarStack(state) { + if (!(state instanceof GrammarState)) + throw new ShikiError('Invalid grammar state'); + // @ts-expect-error _stack is private + return state._stack; +} + +/** + * Code to tokens, with a simple theme. + */ +function codeToTokensBase(internal, code, options = {}) { + const { lang = 'text', theme: themeName = internal.getLoadedThemes()[0], } = options; + if (isPlainLang(lang) || isNoneTheme(themeName)) + return splitLines(code).map(line => [{ content: line[0], offset: line[1] }]); + const { theme, colorMap } = internal.setTheme(themeName); + if (lang === 'ansi') + return tokenizeAnsiWithTheme(theme, code, options); + const _grammar = internal.getLanguage(lang); + if (options.grammarState) { + if (options.grammarState.lang !== _grammar.name) { + throw new ShikiError(`Grammar state language "${options.grammarState.lang}" does not match highlight language "${_grammar.name}"`); + } + if (options.grammarState.theme !== themeName) { + throw new ShikiError(`Grammar state theme "${options.grammarState.theme}" does not match highlight theme "${themeName}"`); + } + } + return tokenizeWithTheme(code, _grammar, theme, colorMap, options); +} +function getLastGrammarState(internal, code, options = {}) { + const { lang = 'text', theme: themeName = internal.getLoadedThemes()[0], } = options; + if (isPlainLang(lang) || isNoneTheme(themeName)) + throw new ShikiError('Plain language does not have grammar state'); + if (lang === 'ansi') + throw new ShikiError('ANSI language does not have grammar state'); + const { theme, colorMap } = internal.setTheme(themeName); + const _grammar = internal.getLanguage(lang); + return new GrammarState(_tokenizeWithTheme(code, _grammar, theme, colorMap, options).stateStack, _grammar.name, theme.name); +} +function tokenizeWithTheme(code, grammar, theme, colorMap, options) { + return _tokenizeWithTheme(code, grammar, theme, colorMap, options).tokens; +} +function _tokenizeWithTheme(code, grammar, theme, colorMap, options) { + const colorReplacements = resolveColorReplacements(theme, options); + const { tokenizeMaxLineLength = 0, tokenizeTimeLimit = 500, } = options; + const lines = splitLines(code); + let stateStack = options.grammarState + ? getGrammarStack(options.grammarState) + : options.grammarContextCode != null + ? _tokenizeWithTheme(options.grammarContextCode, grammar, theme, colorMap, { + ...options, + grammarState: undefined, + grammarContextCode: undefined, + }).stateStack + : INITIAL; + let actual = []; + const final = []; + for (let i = 0, len = lines.length; i < len; i++) { + const [line, lineOffset] = lines[i]; + if (line === '') { + actual = []; + final.push([]); + continue; + } + // Do not attempt to tokenize if the line length is longer than the `tokenizationMaxLineLength` + if (tokenizeMaxLineLength > 0 && line.length >= tokenizeMaxLineLength) { + actual = []; + final.push([{ + content: line, + offset: lineOffset, + color: '', + fontStyle: 0, + }]); + continue; + } + let resultWithScopes; + let tokensWithScopes; + let tokensWithScopesIndex; + if (options.includeExplanation) { + resultWithScopes = grammar.tokenizeLine(line, stateStack); + tokensWithScopes = resultWithScopes.tokens; + tokensWithScopesIndex = 0; + } + const result = grammar.tokenizeLine2(line, stateStack, tokenizeTimeLimit); + const tokensLength = result.tokens.length / 2; + for (let j = 0; j < tokensLength; j++) { + const startIndex = result.tokens[2 * j]; + const nextStartIndex = j + 1 < tokensLength ? result.tokens[2 * j + 2] : line.length; + if (startIndex === nextStartIndex) + continue; + const metadata = result.tokens[2 * j + 1]; + const color = applyColorReplacements(colorMap[StackElementMetadata.getForeground(metadata)], colorReplacements); + const fontStyle = StackElementMetadata.getFontStyle(metadata); + const token = { + content: line.substring(startIndex, nextStartIndex), + offset: lineOffset + startIndex, + color, + fontStyle, + }; + if (options.includeExplanation) { + const themeSettingsSelectors = []; + if (options.includeExplanation !== 'scopeName') { + for (const setting of theme.settings) { + let selectors; + switch (typeof setting.scope) { + case 'string': + selectors = setting.scope.split(/,/).map(scope => scope.trim()); + break; + case 'object': + selectors = setting.scope; + break; + default: + continue; + } + themeSettingsSelectors.push({ + settings: setting, + selectors: selectors.map(selector => selector.split(/ /)), + }); + } + } + token.explanation = []; + let offset = 0; + while (startIndex + offset < nextStartIndex) { + const tokenWithScopes = tokensWithScopes[tokensWithScopesIndex]; + const tokenWithScopesText = line.substring(tokenWithScopes.startIndex, tokenWithScopes.endIndex); + offset += tokenWithScopesText.length; + token.explanation.push({ + content: tokenWithScopesText, + scopes: options.includeExplanation === 'scopeName' + ? explainThemeScopesNameOnly(tokenWithScopes.scopes) + : explainThemeScopesFull(themeSettingsSelectors, tokenWithScopes.scopes), + }); + tokensWithScopesIndex += 1; + } + } + actual.push(token); + } + final.push(actual); + actual = []; + stateStack = result.ruleStack; + } + return { + tokens: final, + stateStack, + }; +} +function explainThemeScopesNameOnly(scopes) { + return scopes.map(scope => ({ scopeName: scope })); +} +function explainThemeScopesFull(themeSelectors, scopes) { + const result = []; + for (let i = 0, len = scopes.length; i < len; i++) { + const scope = scopes[i]; + result[i] = { + scopeName: scope, + themeMatches: explainThemeScope(themeSelectors, scope, scopes.slice(0, i)), + }; + } + return result; +} +function matchesOne(selector, scope) { + return selector === scope + || (scope.substring(0, selector.length) === selector && scope[selector.length] === '.'); +} +function matches(selectors, scope, parentScopes) { + if (!matchesOne(selectors[selectors.length - 1], scope)) + return false; + let selectorParentIndex = selectors.length - 2; + let parentIndex = parentScopes.length - 1; + while (selectorParentIndex >= 0 && parentIndex >= 0) { + if (matchesOne(selectors[selectorParentIndex], parentScopes[parentIndex])) + selectorParentIndex -= 1; + parentIndex -= 1; + } + if (selectorParentIndex === -1) + return true; + return false; +} +function explainThemeScope(themeSettingsSelectors, scope, parentScopes) { + const result = []; + for (const { selectors, settings } of themeSettingsSelectors) { + for (const selectorPieces of selectors) { + if (matches(selectorPieces, scope, parentScopes)) { + result.push(settings); + break; // continue to the next theme settings + } + } + } + return result; +} + +/** + * Get tokens with multiple themes + */ +function codeToTokensWithThemes(internal, code, options) { + const themes = Object.entries(options.themes) + .filter(i => i[1]) + .map(i => ({ color: i[0], theme: i[1] })); + const tokens = syncThemesTokenization(...themes.map(t => codeToTokensBase(internal, code, { + ...options, + theme: t.theme, + }))); + const mergedTokens = tokens[0] + .map((line, lineIdx) => line + .map((_token, tokenIdx) => { + const mergedToken = { + content: _token.content, + variants: {}, + offset: _token.offset, + }; + if ('includeExplanation' in options && options.includeExplanation) { + mergedToken.explanation = _token.explanation; + } + tokens.forEach((t, themeIdx) => { + const { content: _, explanation: __, offset: ___, ...styles } = t[lineIdx][tokenIdx]; + mergedToken.variants[themes[themeIdx].color] = styles; + }); + return mergedToken; + })); + return mergedTokens; +} +/** + * Break tokens from multiple themes into same tokenization. + * + * For example, given two themes that tokenize `console.log("hello")` as: + * + * - `console . log (" hello ")` (6 tokens) + * - `console .log ( "hello" )` (5 tokens) + * + * This function will return: + * + * - `console . log ( " hello " )` (8 tokens) + * - `console . log ( " hello " )` (8 tokens) + */ +function syncThemesTokenization(...themes) { + const outThemes = themes.map(() => []); + const count = themes.length; + for (let i = 0; i < themes[0].length; i++) { + const lines = themes.map(t => t[i]); + const outLines = outThemes.map(() => []); + outThemes.forEach((t, i) => t.push(outLines[i])); + const indexes = lines.map(() => 0); + const current = lines.map(l => l[0]); + while (current.every(t => t)) { + const minLength = Math.min(...current.map(t => t.content.length)); + for (let n = 0; n < count; n++) { + const token = current[n]; + if (token.content.length === minLength) { + outLines[n].push(token); + indexes[n] += 1; + current[n] = lines[n][indexes[n]]; + } + else { + outLines[n].push({ + ...token, + content: token.content.slice(0, minLength), + }); + current[n] = { + ...token, + content: token.content.slice(minLength), + offset: token.offset + minLength, + }; + } + } + } + } + return outThemes; +} + +/** + * High-level code-to-tokens API. + * + * It will use `codeToTokensWithThemes` or `codeToTokensBase` based on the options. + */ +function codeToTokens(internal, code, options) { + let bg; + let fg; + let tokens; + let themeName; + let rootStyle; + if ('themes' in options) { + const { defaultColor = 'light', cssVariablePrefix = '--shiki-', } = options; + const themes = Object.entries(options.themes) + .filter(i => i[1]) + .map(i => ({ color: i[0], theme: i[1] })) + .sort((a, b) => a.color === defaultColor ? -1 : b.color === defaultColor ? 1 : 0); + if (themes.length === 0) + throw new ShikiError('`themes` option must not be empty'); + const themeTokens = codeToTokensWithThemes(internal, code, options); + if (defaultColor && !themes.find(t => t.color === defaultColor)) + throw new ShikiError(`\`themes\` option must contain the defaultColor key \`${defaultColor}\``); + const themeRegs = themes.map(t => internal.getTheme(t.theme)); + const themesOrder = themes.map(t => t.color); + tokens = themeTokens + .map(line => line.map(token => mergeToken(token, themesOrder, cssVariablePrefix, defaultColor))); + const themeColorReplacements = themes.map(t => resolveColorReplacements(t.theme, options)); + fg = themes.map((t, idx) => (idx === 0 && defaultColor + ? '' + : `${cssVariablePrefix + t.color}:`) + (applyColorReplacements(themeRegs[idx].fg, themeColorReplacements[idx]) || 'inherit')).join(';'); + bg = themes.map((t, idx) => (idx === 0 && defaultColor + ? '' + : `${cssVariablePrefix + t.color}-bg:`) + (applyColorReplacements(themeRegs[idx].bg, themeColorReplacements[idx]) || 'inherit')).join(';'); + themeName = `shiki-themes ${themeRegs.map(t => t.name).join(' ')}`; + rootStyle = defaultColor ? undefined : [fg, bg].join(';'); + } + else if ('theme' in options) { + const colorReplacements = resolveColorReplacements(options.theme, options); + tokens = codeToTokensBase(internal, code, options); + const _theme = internal.getTheme(options.theme); + bg = applyColorReplacements(_theme.bg, colorReplacements); + fg = applyColorReplacements(_theme.fg, colorReplacements); + themeName = _theme.name; + } + else { + throw new ShikiError('Invalid options, either `theme` or `themes` must be provided'); + } + return { + tokens, + fg, + bg, + themeName, + rootStyle, + }; +} +function mergeToken(merged, variantsOrder, cssVariablePrefix, defaultColor) { + const token = { + content: merged.content, + explanation: merged.explanation, + offset: merged.offset, + }; + const styles = variantsOrder.map(t => getTokenStyleObject(merged.variants[t])); + // Get all style keys, for themes that missing some style, we put `inherit` to override as needed + const styleKeys = new Set(styles.flatMap(t => Object.keys(t))); + const mergedStyles = styles.reduce((acc, cur, idx) => { + for (const key of styleKeys) { + const value = cur[key] || 'inherit'; + if (idx === 0 && defaultColor) { + acc[key] = value; + } + else { + const keyName = key === 'color' ? '' : key === 'background-color' ? '-bg' : `-${key}`; + const varKey = cssVariablePrefix + variantsOrder[idx] + (key === 'color' ? '' : keyName); + if (acc[key]) + acc[key] += `;${varKey}:${value}`; + else + acc[key] = `${varKey}:${value}`; + } + } + return acc; + }, {}); + token.htmlStyle = defaultColor + ? stringifyTokenStyle(mergedStyles) + : Object.values(mergedStyles).join(';'); + return token; +} + +/** + * A built-in transformer to add decorations to the highlighted code. + */ +function transformerDecorations() { + const map = new WeakMap(); + function getContext(shiki) { + if (!map.has(shiki.meta)) { + const converter = createPositionConverter(shiki.source); + function normalizePosition(p) { + if (typeof p === 'number') { + if (p < 0 || p > shiki.source.length) + throw new ShikiError(`Invalid decoration offset: ${p}. Code length: ${shiki.source.length}`); + return { + ...converter.indexToPos(p), + offset: p, + }; + } + else { + const line = converter.lines[p.line]; + if (line === undefined) + throw new ShikiError(`Invalid decoration position ${JSON.stringify(p)}. Lines length: ${converter.lines.length}`); + if (p.character < 0 || p.character > line.length) + throw new ShikiError(`Invalid decoration position ${JSON.stringify(p)}. Line ${p.line} length: ${line.length}`); + return { + ...p, + offset: converter.posToIndex(p.line, p.character), + }; + } + } + const decorations = (shiki.options.decorations || []) + .map((d) => ({ + ...d, + start: normalizePosition(d.start), + end: normalizePosition(d.end), + })); + verifyIntersections(decorations); + map.set(shiki.meta, { + decorations, + converter, + source: shiki.source, + }); + } + return map.get(shiki.meta); + } + function verifyIntersections(items) { + for (let i = 0; i < items.length; i++) { + const foo = items[i]; + if (foo.start.offset > foo.end.offset) + throw new ShikiError(`Invalid decoration range: ${JSON.stringify(foo.start)} - ${JSON.stringify(foo.end)}`); + for (let j = i + 1; j < items.length; j++) { + const bar = items[j]; + const isFooHasBarStart = foo.start.offset < bar.start.offset && bar.start.offset < foo.end.offset; + const isFooHasBarEnd = foo.start.offset < bar.end.offset && bar.end.offset < foo.end.offset; + const isBarHasFooStart = bar.start.offset < foo.start.offset && foo.start.offset < bar.end.offset; + const isBarHasFooEnd = bar.start.offset < foo.end.offset && foo.end.offset < bar.end.offset; + if (isFooHasBarStart || isFooHasBarEnd || isBarHasFooStart || isBarHasFooEnd) { + if (isFooHasBarEnd && isFooHasBarEnd) + continue; // nested + if (isBarHasFooStart && isBarHasFooEnd) + continue; // nested + throw new ShikiError(`Decorations ${JSON.stringify(foo.start)} and ${JSON.stringify(bar.start)} intersect.`); + } + } + } + } + return { + name: 'shiki:decorations', + tokens(tokens) { + if (!this.options.decorations?.length) + return; + const ctx = getContext(this); + const breakpoints = ctx.decorations.flatMap(d => [d.start.offset, d.end.offset]); + const splitted = splitTokens(tokens, breakpoints); + return splitted; + }, + code(codeEl) { + if (!this.options.decorations?.length) + return; + const ctx = getContext(this); + const lines = Array.from(codeEl.children).filter(i => i.type === 'element' && i.tagName === 'span'); + if (lines.length !== ctx.converter.lines.length) + throw new ShikiError(`Number of lines in code element (${lines.length}) does not match the number of lines in the source (${ctx.converter.lines.length}). Failed to apply decorations.`); + function applyLineSection(line, start, end, decoration) { + const lineEl = lines[line]; + let text = ''; + let startIndex = -1; + let endIndex = -1; + function stringify(el) { + if (el.type === 'text') + return el.value; + if (el.type === 'element') + return el.children.map(stringify).join(''); + return ''; + } + if (start === 0) + startIndex = 0; + if (end === 0) + endIndex = 0; + if (end === Number.POSITIVE_INFINITY) + endIndex = lineEl.children.length; + if (startIndex === -1 || endIndex === -1) { + for (let i = 0; i < lineEl.children.length; i++) { + text += stringify(lineEl.children[i]); + if (startIndex === -1 && text.length === start) + startIndex = i + 1; + if (endIndex === -1 && text.length === end) + endIndex = i + 1; + } + } + if (startIndex === -1) + throw new ShikiError(`Failed to find start index for decoration ${JSON.stringify(decoration.start)}`); + if (endIndex === -1) + throw new ShikiError(`Failed to find end index for decoration ${JSON.stringify(decoration.end)}`); + const children = lineEl.children.slice(startIndex, endIndex); + // Full line decoration + if (!decoration.alwaysWrap && children.length === lineEl.children.length) { + applyDecoration(lineEl, decoration, 'line'); + } + // Single token decoration + else if (!decoration.alwaysWrap && children.length === 1 && children[0].type === 'element') { + applyDecoration(children[0], decoration, 'token'); + } + // Create a wrapper for the decoration + else { + const wrapper = { + type: 'element', + tagName: 'span', + properties: {}, + children, + }; + applyDecoration(wrapper, decoration, 'wrapper'); + lineEl.children.splice(startIndex, children.length, wrapper); + } + } + function applyLine(line, decoration) { + lines[line] = applyDecoration(lines[line], decoration, 'line'); + } + function applyDecoration(el, decoration, type) { + const properties = decoration.properties || {}; + const transform = decoration.transform || (i => i); + el.tagName = decoration.tagName || 'span'; + el.properties = { + ...el.properties, + ...properties, + class: el.properties.class, + }; + if (decoration.properties?.class) + addClassToHast(el, decoration.properties.class); + el = transform(el, type) || el; + return el; + } + const lineApplies = []; + // Apply decorations in reverse order so the nested ones get applied first. + const sorted = ctx.decorations.sort((a, b) => b.start.offset - a.start.offset); + for (const decoration of sorted) { + const { start, end } = decoration; + if (start.line === end.line) { + applyLineSection(start.line, start.character, end.character, decoration); + } + else if (start.line < end.line) { + applyLineSection(start.line, start.character, Number.POSITIVE_INFINITY, decoration); + for (let i = start.line + 1; i < end.line; i++) + lineApplies.unshift(() => applyLine(i, decoration)); + applyLineSection(end.line, 0, end.character, decoration); + } + } + lineApplies.forEach(i => i()); + }, + }; +} + +const builtInTransformers = [ + /* @__PURE__ */ transformerDecorations(), +]; +function getTransformers(options) { + return [ + ...options.transformers || [], + ...builtInTransformers, + ]; +} + +function codeToHast(internal, code, options, transformerContext = { + meta: {}, + options, + codeToHast: (_code, _options) => codeToHast(internal, _code, _options), + codeToTokens: (_code, _options) => codeToTokens(internal, _code, _options), +}) { + let input = code; + for (const transformer of getTransformers(options)) + input = transformer.preprocess?.call(transformerContext, input, options) || input; + let { tokens, fg, bg, themeName, rootStyle, } = codeToTokens(internal, input, options); + const { mergeWhitespaces = true, } = options; + if (mergeWhitespaces === true) + tokens = mergeWhitespaceTokens(tokens); + else if (mergeWhitespaces === 'never') + tokens = splitWhitespaceTokens(tokens); + const contextSource = { + ...transformerContext, + get source() { + return input; + }, + }; + for (const transformer of getTransformers(options)) + tokens = transformer.tokens?.call(contextSource, tokens) || tokens; + return tokensToHast(tokens, { + ...options, + fg, + bg, + themeName, + rootStyle, + }, contextSource); +} +function tokensToHast(tokens, options, transformerContext) { + const transformers = getTransformers(options); + const lines = []; + const root = { + type: 'root', + children: [], + }; + const { structure = 'classic', } = options; + let preNode = { + type: 'element', + tagName: 'pre', + properties: { + class: `shiki ${options.themeName || ''}`, + style: options.rootStyle || `background-color:${options.bg};color:${options.fg}`, + tabindex: '0', + ...Object.fromEntries(Array.from(Object.entries(options.meta || {})) + .filter(([key]) => !key.startsWith('_'))), + }, + children: [], + }; + let codeNode = { + type: 'element', + tagName: 'code', + properties: {}, + children: lines, + }; + const lineNodes = []; + const context = { + ...transformerContext, + structure, + addClassToHast, + get source() { + return transformerContext.source; + }, + get tokens() { + return tokens; + }, + get options() { + return options; + }, + get root() { + return root; + }, + get pre() { + return preNode; + }, + get code() { + return codeNode; + }, + get lines() { + return lineNodes; + }, + }; + tokens.forEach((line, idx) => { + if (idx) { + if (structure === 'inline') + root.children.push({ type: 'element', tagName: 'br', properties: {}, children: [] }); + else if (structure === 'classic') + lines.push({ type: 'text', value: '\n' }); + } + let lineNode = { + type: 'element', + tagName: 'span', + properties: { class: 'line' }, + children: [], + }; + let col = 0; + for (const token of line) { + let tokenNode = { + type: 'element', + tagName: 'span', + properties: {}, + children: [{ type: 'text', value: token.content }], + }; + const style = token.htmlStyle || stringifyTokenStyle(getTokenStyleObject(token)); + if (style) + tokenNode.properties.style = style; + for (const transformer of transformers) + tokenNode = transformer?.span?.call(context, tokenNode, idx + 1, col, lineNode) || tokenNode; + if (structure === 'inline') + root.children.push(tokenNode); + else if (structure === 'classic') + lineNode.children.push(tokenNode); + col += token.content.length; + } + if (structure === 'classic') { + for (const transformer of transformers) + lineNode = transformer?.line?.call(context, lineNode, idx + 1) || lineNode; + lineNodes.push(lineNode); + lines.push(lineNode); + } + }); + if (structure === 'classic') { + for (const transformer of transformers) + codeNode = transformer?.code?.call(context, codeNode) || codeNode; + preNode.children.push(codeNode); + for (const transformer of transformers) + preNode = transformer?.pre?.call(context, preNode) || preNode; + root.children.push(preNode); + } + let result = root; + for (const transformer of transformers) + result = transformer?.root?.call(context, result) || result; + return result; +} +function mergeWhitespaceTokens(tokens) { + return tokens.map((line) => { + const newLine = []; + let carryOnContent = ''; + let firstOffset = 0; + line.forEach((token, idx) => { + const isUnderline = token.fontStyle && token.fontStyle & FontStyle.Underline; + const couldMerge = !isUnderline; + if (couldMerge && token.content.match(/^\s+$/) && line[idx + 1]) { + if (!firstOffset) + firstOffset = token.offset; + carryOnContent += token.content; + } + else { + if (carryOnContent) { + if (couldMerge) { + newLine.push({ + ...token, + offset: firstOffset, + content: carryOnContent + token.content, + }); + } + else { + newLine.push({ + content: carryOnContent, + offset: firstOffset, + }, token); + } + firstOffset = 0; + carryOnContent = ''; + } + else { + newLine.push(token); + } + } + }); + return newLine; + }); +} +function splitWhitespaceTokens(tokens) { + return tokens.map((line) => { + return line.flatMap((token) => { + if (token.content.match(/^\s+$/)) + return token; + // eslint-disable-next-line regexp/no-super-linear-backtracking + const match = token.content.match(/^(\s*)(.*?)(\s*)$/); + if (!match) + return token; + const [, leading, content, trailing] = match; + if (!leading && !trailing) + return token; + const expanded = [{ + ...token, + offset: token.offset + leading.length, + content, + }]; + if (leading) { + expanded.unshift({ + content: leading, + offset: token.offset, + }); + } + if (trailing) { + expanded.push({ + content: trailing, + offset: token.offset + leading.length + content.length, + }); + } + return expanded; + }); + }); +} + +/** + * List of HTML void tag names. + * + * @type {Array} + */ +const htmlVoidElements = [ + 'area', + 'base', + 'basefont', + 'bgsound', + 'br', + 'col', + 'command', + 'embed', + 'frame', + 'hr', + 'image', + 'img', + 'input', + 'keygen', + 'link', + 'meta', + 'param', + 'source', + 'track', + 'wbr' +]; + +/** + * @typedef {import('./info.js').Info} Info + * @typedef {Record} Properties + * @typedef {Record} Normal + */ + +class Schema { + /** + * @constructor + * @param {Properties} property + * @param {Normal} normal + * @param {string} [space] + */ + constructor(property, normal, space) { + this.property = property; + this.normal = normal; + if (space) { + this.space = space; + } + } +} + +/** @type {Properties} */ +Schema.prototype.property = {}; +/** @type {Normal} */ +Schema.prototype.normal = {}; +/** @type {string|null} */ +Schema.prototype.space = null; + +/** + * @typedef {import('./schema.js').Properties} Properties + * @typedef {import('./schema.js').Normal} Normal + */ + + +/** + * @param {Schema[]} definitions + * @param {string} [space] + * @returns {Schema} + */ +function merge(definitions, space) { + /** @type {Properties} */ + const property = {}; + /** @type {Normal} */ + const normal = {}; + let index = -1; + + while (++index < definitions.length) { + Object.assign(property, definitions[index].property); + Object.assign(normal, definitions[index].normal); + } + + return new Schema(property, normal, space) +} + +/** + * @param {string} value + * @returns {string} + */ +function normalize(value) { + return value.toLowerCase() +} + +class Info { + /** + * @constructor + * @param {string} property + * @param {string} attribute + */ + constructor(property, attribute) { + /** @type {string} */ + this.property = property; + /** @type {string} */ + this.attribute = attribute; + } +} + +/** @type {string|null} */ +Info.prototype.space = null; +Info.prototype.boolean = false; +Info.prototype.booleanish = false; +Info.prototype.overloadedBoolean = false; +Info.prototype.number = false; +Info.prototype.commaSeparated = false; +Info.prototype.spaceSeparated = false; +Info.prototype.commaOrSpaceSeparated = false; +Info.prototype.mustUseProperty = false; +Info.prototype.defined = false; + +let powers = 0; + +const boolean = increment(); +const booleanish = increment(); +const overloadedBoolean = increment(); +const number = increment(); +const spaceSeparated = increment(); +const commaSeparated = increment(); +const commaOrSpaceSeparated = increment(); + +function increment() { + return 2 ** ++powers +} + +var types = /*#__PURE__*/Object.freeze({ + __proto__: null, + boolean: boolean, + booleanish: booleanish, + commaOrSpaceSeparated: commaOrSpaceSeparated, + commaSeparated: commaSeparated, + number: number, + overloadedBoolean: overloadedBoolean, + spaceSeparated: spaceSeparated +}); + +/** @type {Array} */ +// @ts-expect-error: hush. +const checks = Object.keys(types); + +class DefinedInfo extends Info { + /** + * @constructor + * @param {string} property + * @param {string} attribute + * @param {number|null} [mask] + * @param {string} [space] + */ + constructor(property, attribute, mask, space) { + let index = -1; + + super(property, attribute); + + mark(this, 'space', space); + + if (typeof mask === 'number') { + while (++index < checks.length) { + const check = checks[index]; + mark(this, checks[index], (mask & types[check]) === types[check]); + } + } + } +} + +DefinedInfo.prototype.defined = true; + +/** + * @param {DefinedInfo} values + * @param {string} key + * @param {unknown} value + */ +function mark(values, key, value) { + if (value) { + // @ts-expect-error: assume `value` matches the expected value of `key`. + values[key] = value; + } +} + +/** + * @typedef {import('./schema.js').Properties} Properties + * @typedef {import('./schema.js').Normal} Normal + * + * @typedef {Record} Attributes + * + * @typedef {Object} Definition + * @property {Record} properties + * @property {(attributes: Attributes, property: string) => string} transform + * @property {string} [space] + * @property {Attributes} [attributes] + * @property {Array} [mustUseProperty] + */ + + +const own$3 = {}.hasOwnProperty; + +/** + * @param {Definition} definition + * @returns {Schema} + */ +function create(definition) { + /** @type {Properties} */ + const property = {}; + /** @type {Normal} */ + const normal = {}; + /** @type {string} */ + let prop; + + for (prop in definition.properties) { + if (own$3.call(definition.properties, prop)) { + const value = definition.properties[prop]; + const info = new DefinedInfo( + prop, + definition.transform(definition.attributes || {}, prop), + value, + definition.space + ); + + if ( + definition.mustUseProperty && + definition.mustUseProperty.includes(prop) + ) { + info.mustUseProperty = true; + } + + property[prop] = info; + + normal[normalize(prop)] = prop; + normal[normalize(info.attribute)] = prop; + } + } + + return new Schema(property, normal, definition.space) +} + +const xlink = create({ + space: 'xlink', + transform(_, prop) { + return 'xlink:' + prop.slice(5).toLowerCase() + }, + properties: { + xLinkActuate: null, + xLinkArcRole: null, + xLinkHref: null, + xLinkRole: null, + xLinkShow: null, + xLinkTitle: null, + xLinkType: null + } +}); + +const xml = create({ + space: 'xml', + transform(_, prop) { + return 'xml:' + prop.slice(3).toLowerCase() + }, + properties: {xmlLang: null, xmlBase: null, xmlSpace: null} +}); + +/** + * @param {Record} attributes + * @param {string} attribute + * @returns {string} + */ +function caseSensitiveTransform(attributes, attribute) { + return attribute in attributes ? attributes[attribute] : attribute +} + +/** + * @param {Record} attributes + * @param {string} property + * @returns {string} + */ +function caseInsensitiveTransform(attributes, property) { + return caseSensitiveTransform(attributes, property.toLowerCase()) +} + +const xmlns = create({ + space: 'xmlns', + attributes: {xmlnsxlink: 'xmlns:xlink'}, + transform: caseInsensitiveTransform, + properties: {xmlns: null, xmlnsXLink: null} +}); + +const aria = create({ + transform(_, prop) { + return prop === 'role' ? prop : 'aria-' + prop.slice(4).toLowerCase() + }, + properties: { + ariaActiveDescendant: null, + ariaAtomic: booleanish, + ariaAutoComplete: null, + ariaBusy: booleanish, + ariaChecked: booleanish, + ariaColCount: number, + ariaColIndex: number, + ariaColSpan: number, + ariaControls: spaceSeparated, + ariaCurrent: null, + ariaDescribedBy: spaceSeparated, + ariaDetails: null, + ariaDisabled: booleanish, + ariaDropEffect: spaceSeparated, + ariaErrorMessage: null, + ariaExpanded: booleanish, + ariaFlowTo: spaceSeparated, + ariaGrabbed: booleanish, + ariaHasPopup: null, + ariaHidden: booleanish, + ariaInvalid: null, + ariaKeyShortcuts: null, + ariaLabel: null, + ariaLabelledBy: spaceSeparated, + ariaLevel: number, + ariaLive: null, + ariaModal: booleanish, + ariaMultiLine: booleanish, + ariaMultiSelectable: booleanish, + ariaOrientation: null, + ariaOwns: spaceSeparated, + ariaPlaceholder: null, + ariaPosInSet: number, + ariaPressed: booleanish, + ariaReadOnly: booleanish, + ariaRelevant: null, + ariaRequired: booleanish, + ariaRoleDescription: spaceSeparated, + ariaRowCount: number, + ariaRowIndex: number, + ariaRowSpan: number, + ariaSelected: booleanish, + ariaSetSize: number, + ariaSort: null, + ariaValueMax: number, + ariaValueMin: number, + ariaValueNow: number, + ariaValueText: null, + role: null + } +}); + +const html$3 = create({ + space: 'html', + attributes: { + acceptcharset: 'accept-charset', + classname: 'class', + htmlfor: 'for', + httpequiv: 'http-equiv' + }, + transform: caseInsensitiveTransform, + mustUseProperty: ['checked', 'multiple', 'muted', 'selected'], + properties: { + // Standard Properties. + abbr: null, + accept: commaSeparated, + acceptCharset: spaceSeparated, + accessKey: spaceSeparated, + action: null, + allow: null, + allowFullScreen: boolean, + allowPaymentRequest: boolean, + allowUserMedia: boolean, + alt: null, + as: null, + async: boolean, + autoCapitalize: null, + autoComplete: spaceSeparated, + autoFocus: boolean, + autoPlay: boolean, + blocking: spaceSeparated, + capture: null, + charSet: null, + checked: boolean, + cite: null, + className: spaceSeparated, + cols: number, + colSpan: null, + content: null, + contentEditable: booleanish, + controls: boolean, + controlsList: spaceSeparated, + coords: number | commaSeparated, + crossOrigin: null, + data: null, + dateTime: null, + decoding: null, + default: boolean, + defer: boolean, + dir: null, + dirName: null, + disabled: boolean, + download: overloadedBoolean, + draggable: booleanish, + encType: null, + enterKeyHint: null, + fetchPriority: null, + form: null, + formAction: null, + formEncType: null, + formMethod: null, + formNoValidate: boolean, + formTarget: null, + headers: spaceSeparated, + height: number, + hidden: boolean, + high: number, + href: null, + hrefLang: null, + htmlFor: spaceSeparated, + httpEquiv: spaceSeparated, + id: null, + imageSizes: null, + imageSrcSet: null, + inert: boolean, + inputMode: null, + integrity: null, + is: null, + isMap: boolean, + itemId: null, + itemProp: spaceSeparated, + itemRef: spaceSeparated, + itemScope: boolean, + itemType: spaceSeparated, + kind: null, + label: null, + lang: null, + language: null, + list: null, + loading: null, + loop: boolean, + low: number, + manifest: null, + max: null, + maxLength: number, + media: null, + method: null, + min: null, + minLength: number, + multiple: boolean, + muted: boolean, + name: null, + nonce: null, + noModule: boolean, + noValidate: boolean, + onAbort: null, + onAfterPrint: null, + onAuxClick: null, + onBeforeMatch: null, + onBeforePrint: null, + onBeforeToggle: null, + onBeforeUnload: null, + onBlur: null, + onCancel: null, + onCanPlay: null, + onCanPlayThrough: null, + onChange: null, + onClick: null, + onClose: null, + onContextLost: null, + onContextMenu: null, + onContextRestored: null, + onCopy: null, + onCueChange: null, + onCut: null, + onDblClick: null, + onDrag: null, + onDragEnd: null, + onDragEnter: null, + onDragExit: null, + onDragLeave: null, + onDragOver: null, + onDragStart: null, + onDrop: null, + onDurationChange: null, + onEmptied: null, + onEnded: null, + onError: null, + onFocus: null, + onFormData: null, + onHashChange: null, + onInput: null, + onInvalid: null, + onKeyDown: null, + onKeyPress: null, + onKeyUp: null, + onLanguageChange: null, + onLoad: null, + onLoadedData: null, + onLoadedMetadata: null, + onLoadEnd: null, + onLoadStart: null, + onMessage: null, + onMessageError: null, + onMouseDown: null, + onMouseEnter: null, + onMouseLeave: null, + onMouseMove: null, + onMouseOut: null, + onMouseOver: null, + onMouseUp: null, + onOffline: null, + onOnline: null, + onPageHide: null, + onPageShow: null, + onPaste: null, + onPause: null, + onPlay: null, + onPlaying: null, + onPopState: null, + onProgress: null, + onRateChange: null, + onRejectionHandled: null, + onReset: null, + onResize: null, + onScroll: null, + onScrollEnd: null, + onSecurityPolicyViolation: null, + onSeeked: null, + onSeeking: null, + onSelect: null, + onSlotChange: null, + onStalled: null, + onStorage: null, + onSubmit: null, + onSuspend: null, + onTimeUpdate: null, + onToggle: null, + onUnhandledRejection: null, + onUnload: null, + onVolumeChange: null, + onWaiting: null, + onWheel: null, + open: boolean, + optimum: number, + pattern: null, + ping: spaceSeparated, + placeholder: null, + playsInline: boolean, + popover: null, + popoverTarget: null, + popoverTargetAction: null, + poster: null, + preload: null, + readOnly: boolean, + referrerPolicy: null, + rel: spaceSeparated, + required: boolean, + reversed: boolean, + rows: number, + rowSpan: number, + sandbox: spaceSeparated, + scope: null, + scoped: boolean, + seamless: boolean, + selected: boolean, + shadowRootDelegatesFocus: boolean, + shadowRootMode: null, + shape: null, + size: number, + sizes: null, + slot: null, + span: number, + spellCheck: booleanish, + src: null, + srcDoc: null, + srcLang: null, + srcSet: null, + start: number, + step: null, + style: null, + tabIndex: number, + target: null, + title: null, + translate: null, + type: null, + typeMustMatch: boolean, + useMap: null, + value: booleanish, + width: number, + wrap: null, + + // Legacy. + // See: https://html.spec.whatwg.org/#other-elements,-attributes-and-apis + align: null, // Several. Use CSS `text-align` instead, + aLink: null, // ``. Use CSS `a:active {color}` instead + archive: spaceSeparated, // ``. List of URIs to archives + axis: null, // `` and ``. Use `scope` on `` + background: null, // ``. Use CSS `background-image` instead + bgColor: null, // `` and table elements. Use CSS `background-color` instead + border: number, // ``. Use CSS `border-width` instead, + borderColor: null, // `
    `. Use CSS `border-color` instead, + bottomMargin: number, // `` + cellPadding: null, // `
    ` + cellSpacing: null, // `
    ` + char: null, // Several table elements. When `align=char`, sets the character to align on + charOff: null, // Several table elements. When `char`, offsets the alignment + classId: null, // `` + clear: null, // `
    `. Use CSS `clear` instead + code: null, // `` + codeBase: null, // `` + codeType: null, // `` + color: null, // `` and `
    `. Use CSS instead + compact: boolean, // Lists. Use CSS to reduce space between items instead + declare: boolean, // `` + event: null, // ` + + {% include 'footer.njk' %} + \ No newline at end of file diff --git a/src/_includes/handbookBase.njk b/src/_includes/handbookBase.njk index 8db34d0..613f273 100644 --- a/src/_includes/handbookBase.njk +++ b/src/_includes/handbookBase.njk @@ -19,17 +19,17 @@
    - +
    - +
    - +
    @@ -41,17 +41,17 @@
    - +
    - +
    - +
    @@ -63,17 +63,17 @@
    - +
    - +
    - +
    @@ -146,10 +146,16 @@ - + tablinks = document.getElementsByClassName("tablinks"); + for (i = 0; i < tablinks.length; i++) { + tablinks[i].className = tablinks[i] + .className + .replace(" active", ""); + } + document + .getElementById(tab) + .style + .display = "block"; + evt.currentTarget.className += " active"; + } + document + .getElementById("defaultOpen") + .click(); + + + + + + + +
    @@ -120,7 +166,7 @@
    - +
    @@ -133,7 +179,7 @@
    - +
    @@ -148,7 +194,8 @@

    Describe your data

    -

    Describe the shape of your objects and functions in your code.

    +

    + Describe the shape of your objects and functions in your code.

    Making it possible to see documentation and issues in your editor.

    @@ -174,319 +221,338 @@
    ts
    type Result = "pass" | "fail"
     
    function verify(result: Result) {
    if (result === "pass") {
    console.log("Passed")
    } else {
    console.log("Failed")
    }
    }
     
    -

    TypeScript file.

    - - -
    -
    ts
    type Result = "pass" | "fail"
     
    function verify(result: Result) {
    if (result === "pass") {
    console.log("Passed")
    } else {
    console.log("Failed")
    }
    }
     
    -

    Types are removed.

    -
    - - -
    -
    js
     
     
    function verify(result) {
    if (result === "pass") {
    console.log("Passed")
    } else {
    console.log("Failed")
    }
    }
     
    -

    JavaScript file.

    -
    - - - - - -
    -
    -

    TypeScript Testimonials

    -
    -
    -
    -
    -

    First, we were surprised by the number of small bugs we found when converting our code.

    -

    Second, we underestimated how powerful the editor integration is.

    -

    TypeScript was such a boon to our stability and sanity that we started using it for all new code within days of starting the conversion.

    -
    -
    - - - - - - - - - - -
    -
    -
    - - - - - - - - - - - - - - - -

    Felix Rieseberg at Slack covered the transition of their desktop app from JavaScript to TypeScript in their blog

    - Read -
    +

    + TypeScript file.

    + + +
    +
    ts
    type Result = "pass" | "fail"
     
    function verify(result: Result) {
    if (result === "pass") {
    console.log("Passed")
    } else {
    console.log("Failed")
    }
    }
     
    +

    + Types are removed. +

    +
    + + +
    +
    js
     
     
    function verify(result) {
    if (result === "pass") {
    console.log("Passed")
    } else {
    console.log("Failed")
    }
    }
     
    +

    + JavaScript file. +

    +
    + + +
    -
    -
    -
    -

    38% [...] bugs preventable with TypeScript according to postmortem analysis

    -

    With TypeScript, engineers can move faster more safely.

    -

    End-to-end type safety because the types used by the back-end and the front-end share a source of truth.

    +
    +
    +
    +

    TypeScript Testimonials

    +
    +
    +
    +
    +

    + First, we were surprised by the number of small bugs we found when converting our code.

    +

    + Second, we underestimated how powerful the editor integration is.

    +

    TypeScript was such a boon to our stability and sanity that we started using it for all new code within days of starting the conversion.

    +
    +
    + + + + + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + +

    Felix Rieseberg at Slack covered the transition of their desktop app from JavaScript to TypeScript in their blog

    + Read +
    -
    - - - - - - - - - - - - - -
    -
    -
    - - - - - - - - - - -

    Brie Bunge at Airbnb gave a talk at JSConf Hawaiʻi on how Airbnb adopted TypeScript at Scale

    - Watch -
    -
    -
    -
    -
    -

    Using TypeScript is simple and pleasant for all Google engineers.

    -

    Around eight or nine languages are officially supported and TypeScript is one of them.

    +
    +
    +
    +

    + 38% [...] bugs preventable with TypeScript according to postmortem analysis

    +

    With TypeScript, engineers can move faster more safely.

    +

    End-to-end type safety because the types used by the back-end and the front-end share a source of truth.

    +
    +
    + + + + + + + + + + + + + +
    +
    +
    + + + + + + + + + + +

    Brie Bunge at Airbnb gave a talk at JSConf Hawaiʻi on how Airbnb adopted TypeScript at Scale

    + Watch +
    -
    - - - - - - - - - +
    +
    +
    +

    Using TypeScript is simple and pleasant for all Google engineers.

    +

    Around eight or nine languages are officially supported and TypeScript is one of them.

    +
    +
    + + + + + + + + + +
    +
    +
    + + + + + + + + +

    Rodoslav Kirov and Bowen Ni covered how TypeScript became one of the five languages available at Google at TSConf 2018.

    + Watch +
    -
    -
    - - - - - - - - -

    Rodoslav Kirov and Bowen Ni covered how TypeScript became one of the five languages available at Google at TSConf 2018.

    - Watch + + + +
    - +
    +
    + + +

    Loved by Developers

    + +
    + + +
    + +
    +

    Voted 2nd most loved programming language in the Stack Overflow 2020 Developer survey +

    +
    +
    + + + + + +
    + + +
    +

    TypeScript was used by 78% of the 2020 State of JS respondents, with 93% saying they would use it again.

    +

    TypeScript was given the award for "Most Adopted Technology" based on year-on-year growth.

    +
    +
    +
    - - -
    -
    -
    -
    - - -

    Loved by Developers

    - -
    - - -
    - -
    -

    Voted 2nd most loved programming language in the Stack Overflow 2020 Developer survey

    -
    -
    - - - - - -
    - - -
    -

    TypeScript was used by 78% of the 2020 State of JS respondents, with 93% saying they would use it again.

    -

    TypeScript was given the award for "Most Adopted Technology" based on year-on-year growth.

    -
    -
    -
    -
    -
    -
    - - \ No newline at end of file + + \ No newline at end of file diff --git a/src/images/connect-blog.svg b/src/images/connect-blog.svg new file mode 100644 index 0000000..85a721f --- /dev/null +++ b/src/images/connect-blog.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/images/connect-definitely-typed.png b/src/images/connect-definitely-typed.png new file mode 100644 index 0000000..6127f06 Binary files /dev/null and b/src/images/connect-definitely-typed.png differ diff --git a/src/images/connect-discord.svg b/src/images/connect-discord.svg new file mode 100644 index 0000000..4613aa9 --- /dev/null +++ b/src/images/connect-discord.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/images/connect-dt.svg b/src/images/connect-dt.svg new file mode 100644 index 0000000..e69de29 diff --git a/src/images/connect-github-icon.png b/src/images/connect-github-icon.png new file mode 100644 index 0000000..73db1f6 Binary files /dev/null and b/src/images/connect-github-icon.png differ diff --git a/src/images/connect-twitter.svg b/src/images/connect-twitter.svg new file mode 100644 index 0000000..83fde92 --- /dev/null +++ b/src/images/connect-twitter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/images/meetupLogos/boston-ts-club.png b/src/images/meetupLogos/boston-ts-club.png new file mode 100644 index 0000000..1b5b793 Binary files /dev/null and b/src/images/meetupLogos/boston-ts-club.png differ diff --git a/src/images/meetupLogos/ktug.jpg b/src/images/meetupLogos/ktug.jpg new file mode 100644 index 0000000..19ff5c9 Binary files /dev/null and b/src/images/meetupLogos/ktug.jpg differ diff --git a/src/images/meetupLogos/phx-ts.jpg b/src/images/meetupLogos/phx-ts.jpg new file mode 100644 index 0000000..b166d38 Binary files /dev/null and b/src/images/meetupLogos/phx-ts.jpg differ diff --git a/src/images/meetupLogos/san-fran-ts.jpg b/src/images/meetupLogos/san-fran-ts.jpg new file mode 100644 index 0000000..dfb4ee4 Binary files /dev/null and b/src/images/meetupLogos/san-fran-ts.jpg differ diff --git a/src/images/meetupLogos/typescript-jp.jpg b/src/images/meetupLogos/typescript-jp.jpg new file mode 100644 index 0000000..8b2738c Binary files /dev/null and b/src/images/meetupLogos/typescript-jp.jpg differ diff --git a/src/images/stack-overflow-img.svg b/src/images/stack-overflow-img.svg new file mode 100644 index 0000000..7973d2f --- /dev/null +++ b/src/images/stack-overflow-img.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/pages/GetStarted/NewProgrammer.md b/src/pages/GetStarted/NewProgrammer.md index a5b2ec2..89636e9 100644 --- a/src/pages/GetStarted/NewProgrammer.md +++ b/src/pages/GetStarted/NewProgrammer.md @@ -58,9 +58,10 @@ For example, the last example above has an error because of the _type_ of `obj`. Here's the error TypeScript found: ```ts -// @errors: 2551 const obj = { width: 10, height: 15 }; const area = obj.width * obj.heigth; +Property 'heigth' does not exist on type '{ width: number; height: number; }'. Did you mean 'height'? // [!code error] + ``` ### A Typed Superset of JavaScript @@ -76,6 +77,8 @@ For example, this code has a _syntax_ error because it's missing a `)`: ```ts twoslash // @errors: 1005 let a = (4 +')' expected // [!code error] + ``` TypeScript doesn't consider any JavaScript code to be an error because of its syntax. diff --git a/src/pages/community.md b/src/pages/community.md index 7e8215a..85f6e2c 100644 --- a/src/pages/community.md +++ b/src/pages/community.md @@ -2,6 +2,4 @@ layout: "../_includes/community.njk" title: Start Handbook templateEngineOverride: njk,md ---- -First handbook page! -This iss the community page \ No newline at end of file +--- \ No newline at end of file diff --git a/src/pages/handbook.md b/src/pages/handbook.md index 704543d..1aee241 100644 --- a/src/pages/handbook.md +++ b/src/pages/handbook.md @@ -1,5 +1,5 @@ --- -layout: "../_includes/handbookBase.njk" +layout: "../_includes/handbook.njk" title: Start Handbook templateEngineOverride: njk,md --- diff --git a/src/style/community.css b/src/style/community.css new file mode 100644 index 0000000..cb45c7e --- /dev/null +++ b/src/style/community.css @@ -0,0 +1,129 @@ +.community.centered { + text-align: center; +} +.main-content-block { + margin: 1rem auto; + max-width: 960px; + + .community { + padding: 0; + } +} +main { + background-color: #faf9f8; +} +.raised { + background-color: #fff; + box-shadow: 0 1.6px 3.6px 0 rgba(0,0,0,.132), 0 0.3px 0.9px 0 rgba(0,0,0,.108); + color: #000; + p { + line-height: 1.4rem; + code { + font-size: 14px; + background-color: #f1f1fe; + font-family: "SF Mono", Menlo, Monaco, Consolas, monospace; + padding: 2px 4px; + } + } + h2, h3 { + line-height: normal; + margin-bottom: 1.5rem; + margin-top: 2rem; + } + h2, h3 { + font-weight: 400; + } + a { + color: #235a97; + } + ul { + padding-left: 10px; + li { + margin-bottom: 10px; + margin-left: 10px; + } + } + li { + line-height: 1.4rem; + code { + font-size: 14px; + background-color: #f1f1fe; + font-family: "SF Mono", Menlo, Monaco, Consolas, monospace; + padding: 2px 4px; + } + } +} +.row, .split-row { + display: flex; + flex-direction: row; + flex-wrap: wrap; +} +.community .sidebar { + background-color: rgba(204, 207, 233, .1); +} +.community .banner-text { + margin-top: 20px; +} +.community .callouts { + display: flex; + flex-wrap: wrap; + margin: 20px 0; + .icon { + background-position: 50%; + background-repeat: no-repeat; + background-size: auto 3.2rem; + display: block; + height: 5rem; + margin: 0 20px 20px; + min-width: 5rem; + transition: background-color .2s ease-out; + width: 5rem; + } + .icon.stackoverflow { + background-color: #5016d9; + background-image: url(../images/stack-overflow-img.svg); + } + .icon.discord { + background-color: #7289da; + background-image: url(../images/connect-discord.svg); + } + .icon.twitter { + background-color: #00a0d1;; + background-image: url(../images/connect-twitter.svg); + } + .icon.blog { + background-color: #d9a216; + background-image: url(../images/connect-blog.svg); + } + .icon.definitelytyped { + background-color: #0077d2; + background-image: url(../images/connect-definitely-typed.png); + } + .icon.bug { + background-color: #4d4d4d; + background-image: url(../images/connect-github-icon.png); + } + .icon.img-circle { + border-radius: 50%; + } +} +.community .callouts .callout { + display: flex; + line-height: 1.4rem; + margin-bottom: 10px; + margin-top: 20px; + width: 48%; +} +.community h3.centered-highlight { + background-color: rgba(204, 207, 233, .1); + padding: 20px; + text-align: center; +} +.community .community-callout-headline { + margin-top: 0; +} +.col1 { + flex: 1 1; + min-width: 250px; + padding: 1rem; +} \ No newline at end of file diff --git a/src/style/handbook.css b/src/style/handbook.css new file mode 100644 index 0000000..a90ba5f --- /dev/null +++ b/src/style/handbook.css @@ -0,0 +1,206 @@ +#doc-layout { + display: flex; + flex-direction: row; + background-color: #faf9f8; +} + +#sidebar { + background-color: #eeeeee; + color: #000; + min-width: 16rem; + ul { + max-height: calc(100vh - 10px); + overflow-x: hidden; + overflow-y: auto; + margin: 0; + padding: 0; + position: sticky; + top: 0; + li { + border-bottom: 1px solid #dfdfdf; + font-size: 1rem; + font-weight: 400; + list-style: none; + min-height: 2.5rem; + padding: 0; + a { + font-weight: 300; + margin-right: -.5rem; + } + button { + font-family: inherit; + background-color: transparent; + border: none; + color: #000; + cursor: pointer; + display: block; + font-size: 1rem; + font-weight: 500; + height: 2.5rem; + padding-left: 1rem; + position: relative; + text-align: left; + width: 100%; + span { + position: absolute; + right: 20px; + } + } + } + li.closed ul { + display: none; + } + li.open { + button span.closed { + display: none; + } + ul { + background-color: #e4e4e4; + } + } + li.highlighted { + background-color: #e3e8ec; + } + } +} + +.content-placeholder { + margin: auto; + max-width: 1200px; + min-width: 0; + padding: 0 2rem; + h1 { + font-size: 3.5rem; + font-weight: 400; + letter-spacing: 0; + line-height: 3.5rem; + } + article { + display: flex; + width: 100%; + #section1 { + margin: 0 auto 1rem; + overflow: hidden; + padding: 2rem; + background-color: #fff; + box-shadow: 0 1.6px 3.6px 0 rgba(0, 0, 0, .132), 0 0.3px 0.9px 0 rgba(0, 0, 0, .108); + color: #000; + scroll-behavior: smooth; + h2 { + font-size: 1.75rem; + margin-bottom: 12px; + margin-top: 32px; + white-space-collapse: preserve; + display: flex; + flex-wrap: wrap; + font-weight: 400; + line-height: 1.3; + } + h3 { + font-size: 1.1875rem; + margin-bottom: 18px; + margin-top: 30px; + white-space-collapse: preserve; + display: flex; + flex-wrap: wrap; + font-weight: 400; + line-height: 1.3; + } + h4 { + display: block; + margin-block-start: 1.33em; + margin-block-end: 1.33em; + margin-inline-start: 0px; + margin-inline-end: 0px; + font-weight: bold; + unicode-bidi: isolate; + } + p { + line-height: 1.4rem; + } + ul { + padding-left: 10px; + li { + margin-bottom: 10px; + margin-left: 10px; + line-height: 1.4rem; + } + } + pre { + clear: both; + top: 10px; + border-bottom: 1px solid #999; + border-left: 1px solid #999; + margin-bottom: 3rem; + padding: 12px; + position: relative; + border-color: #719af4; + } + pre.shiki { + overflow-x: visible; + } + pre .code-container { + overflow: auto; + } + pre code { + font-family: JetBrains Mono, Menlo, Monaco, Consolas, Courier New, monospace; + font-size: 15px; + white-space: pre; + } + pre .error { + align-items: center; + background-color: #fee; + border-left: 2px solid #bf1818; + color: #000; + display: flex; + margin-right: -2px; + position: absolute; + margin-bottom: 4px; + margin-left: -14px; + margin-top: 8px; + padding: 6px 6px 6px 14px; + white-space: pre-wrap; + width: calc(100% - 20px); + } + } + #section2 { + display: block; + margin-bottom: 1rem; + position: sticky; + top: 30px; + flex-shrink: 0; + margin-left: 20px; + width: 13rem; + nav { + margin-bottom: 1rem; + position: sticky; + top: 30px; + } + h5 { + font-size: 16px; + font-weight: 600; + margin: 0; + } + ul { + padding: 0; + max-height: 80vh; + overflow: auto; + li { + list-style: none; + } + a { + border-left: 2px solid transparent; + color: #000; + display: block; + font-size: 14px; + font-weight: 400; + overflow: hidden; + padding-left: 8px; + text-decoration: none; + text-overflow: ellipsis; + white-space: nowrap; + } + } + } + } +} \ No newline at end of file diff --git a/src/style/handbookBase.css b/src/style/handbookBase.css index d659afe..d060397 100644 --- a/src/style/handbookBase.css +++ b/src/style/handbookBase.css @@ -6,6 +6,11 @@ background-color: #eeeeee; color: #000; min-width: 16rem; + .side-content { + &.open { + background-color: aqua; + } + } table { max-height: calc(100vh - 10px); overflow-x: hidden; @@ -171,6 +176,14 @@ pre { clear: both; top: 10px; + background-color: #fff; + border-bottom: 1px solid #999; + border-left: 1px solid #999; + color: #000; + margin-bottom: 3rem; + overflow-x: auto; + padding: 12px; + position: relative; } article { display: flex; @@ -182,6 +195,14 @@ background-color: #fff;; box-shadow: 0 1.6px 3.6px 0 rgba(255, 255, 255, 0.132); color: #000; + ul { + padding-left: 10px; + li { + margin-bottom: 10px; + margin-left: 10px; + line-height: 1.4rem; + } + } } #section2 { display: block; diff --git a/src/style/home.css b/src/style/home.css index 6362eff..fe37425 100644 --- a/src/style/home.css +++ b/src/style/home.css @@ -9,6 +9,9 @@ line-height: 2.8rem; margin-top: 0; padding-right: 40px; + strong { + font-weight: 600; + } } h2 { @@ -140,6 +143,10 @@ code { font-size: 14px; line-height: 16px; + data-err { + background:url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") repeat-x 0 100%; + padding-bottom: 3px; + } .error { background-color: #ff000026; color: #ffc5c5; @@ -320,8 +327,8 @@ #migration-stories { min-height: 370px; position: relative; - .slides { - display: none; + .slides.slack { + display: block; } .illustration { .fg { diff --git a/src/style/style.css b/src/style/style.css index 08c11b9..f38501c 100644 --- a/src/style/style.css +++ b/src/style/style.css @@ -1,4 +1,4 @@ body { - font-family: sans-serif; + font-family: "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif; margin: 0; } \ No newline at end of file