From ad3bbc29935ba68f90f8a80856227b86702aff6e Mon Sep 17 00:00:00 2001 From: Markus Rudolph Date: Tue, 4 Jun 2024 17:24:05 +0200 Subject: [PATCH] Add links checker and add aliases (#237) --- .github/workflows/links.yml | 22 + hugo/content/docs/introduction/features.md | 6 +- .../{index.md => _index.md} | 2 + .../docs/learn/minilogo/customizing_cli.md | 2 + .../content/docs/learn/minilogo/generation.md | 2 + .../learn/minilogo/generation_in_the_web.md | 2 + .../docs/learn/minilogo/langium_and_monaco.md | 2 + .../content/docs/learn/minilogo/validation.md | 2 + .../docs/learn/minilogo/writing_a_grammar.md | 3 + hugo/content/docs/learn/workflow/_index.md | 4 +- hugo/content/docs/recipes/builtin-library.md | 2 +- hugo/content/docs/recipes/code-bundling.md | 4 +- .../docs/recipes/multiple-languages.md | 2 +- hugo/content/docs/recipes/scoping/_index.md | 4 +- .../docs/recipes/scoping/class-member.md | 2 + .../docs/recipes/scoping/qualified-name.md | 4 +- .../docs/reference/document-lifecycle.md | 2 + .../docs/reference/grammar-language.md | 7 +- hugo/content/docs/reference/semantic-model.md | 5 +- package-lock.json | 566 +++++++++++++++++- package.json | 10 +- scripts/check-links.ts | 140 +++++ 22 files changed, 770 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/links.yml rename hugo/content/docs/learn/minilogo/building_an_extension/{index.md => _index.md} (99%) create mode 100644 scripts/check-links.ts diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml new file mode 100644 index 00000000..0758cbdb --- /dev/null +++ b/.github/workflows/links.yml @@ -0,0 +1,22 @@ +name: Check if all links are reachable +on: + push: + branches: main + pull_request: + branches: main + workflow_dispatch: + +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + - name: Checkout + uses: actions/checkout@v3 + - name: Install + run: npm ci + - name: Check links + run: npm run check:links \ No newline at end of file diff --git a/hugo/content/docs/introduction/features.md b/hugo/content/docs/introduction/features.md index e6fa716e..0a00ac81 100644 --- a/hugo/content/docs/introduction/features.md +++ b/hugo/content/docs/introduction/features.md @@ -19,7 +19,7 @@ In this chapter, you'll get a closer look at the requirements developers usually - [Cross References and Linking](#cross-references-and-linking) - [Workspace Management](#workspace-management) - [Editing Support](#editing-support) -- [Try it out!](#try-it-out) +- [Try it out](#try-it-out) Langium provides out-of-the-box solutions for these problems, with the ability to fine-tune every part of it to fit your domain requirements. @@ -27,7 +27,7 @@ Langium provides out-of-the-box solutions for these problems, with the ability t ## Language Parsing -Programming languages and domain specific languages (DSLs) cannot be parsed using simple regular expressions (RegExp). Instead they require a more sophisticated parsing strategy. To define a custom language in Langium, you interact with a high level representation of your context-free grammar using the [Langium grammar language](/docs/grammar-language), in a similar fashion to EBNF. +Programming languages and domain specific languages (DSLs) cannot be parsed using simple regular expressions (RegExp). Instead they require a more sophisticated parsing strategy. To define a custom language in Langium, you interact with a high level representation of your context-free grammar using the [Langium grammar language](/docs/reference/grammar-language), in a similar fashion to EBNF. Based on the grammar, Langium is then able to construct a parser which transforms an input string into a semantic model representation. Just as the name suggests, this model captures the essential structure to describe your language. @@ -97,7 +97,7 @@ The Langium framework is deeply integrated with the [language server protocol](h The LSP includes commonly used language features, such as code completion, custom validations/diagnostics, finding references, formatting and many more. This allows for deep IDE integration without binding your language to a single IDE. Langium offers out-of-the-box support for most of these language features, with additional extension points for your domain specific requirements. -## Try it out! +## Try it out You can try out most of these features using our [showcase](/showcase/) and [playground](/playground/). The languages shown there are written using Langium and integrated in the monaco-editor. diff --git a/hugo/content/docs/learn/minilogo/building_an_extension/index.md b/hugo/content/docs/learn/minilogo/building_an_extension/_index.md similarity index 99% rename from hugo/content/docs/learn/minilogo/building_an_extension/index.md rename to hugo/content/docs/learn/minilogo/building_an_extension/_index.md index f8ace5a1..b50c7a1c 100644 --- a/hugo/content/docs/learn/minilogo/building_an_extension/index.md +++ b/hugo/content/docs/learn/minilogo/building_an_extension/_index.md @@ -1,6 +1,8 @@ --- title: "Building an Extension" weight: 5 +aliases: + - /tutorials/building_an_extension --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/minilogo/customizing_cli.md b/hugo/content/docs/learn/minilogo/customizing_cli.md index 836ac8ea..d2894308 100644 --- a/hugo/content/docs/learn/minilogo/customizing_cli.md +++ b/hugo/content/docs/learn/minilogo/customizing_cli.md @@ -1,6 +1,8 @@ --- title: "Customizing the CLI" weight: 2 +aliases: + - /tutorials/customizing_cli --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/minilogo/generation.md b/hugo/content/docs/learn/minilogo/generation.md index 5898cd0a..7b47d670 100644 --- a/hugo/content/docs/learn/minilogo/generation.md +++ b/hugo/content/docs/learn/minilogo/generation.md @@ -1,6 +1,8 @@ --- title: "Generation" weight: 3 +aliases: + - /tutorials/generation --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/minilogo/generation_in_the_web.md b/hugo/content/docs/learn/minilogo/generation_in_the_web.md index 4dc9bceb..c8db7cdb 100644 --- a/hugo/content/docs/learn/minilogo/generation_in_the_web.md +++ b/hugo/content/docs/learn/minilogo/generation_in_the_web.md @@ -1,6 +1,8 @@ --- title: "Generation in the Web" weight: 7 +aliases: + - /tutorials/generation_in_the_web --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/minilogo/langium_and_monaco.md b/hugo/content/docs/learn/minilogo/langium_and_monaco.md index 573ae304..4dcee7b3 100644 --- a/hugo/content/docs/learn/minilogo/langium_and_monaco.md +++ b/hugo/content/docs/learn/minilogo/langium_and_monaco.md @@ -1,6 +1,8 @@ --- title: "Langium + Monaco Editor" weight: 6 +aliases: + - /tutorials/langium_and_monaco --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/minilogo/validation.md b/hugo/content/docs/learn/minilogo/validation.md index 805f11ab..c37a5189 100644 --- a/hugo/content/docs/learn/minilogo/validation.md +++ b/hugo/content/docs/learn/minilogo/validation.md @@ -1,6 +1,8 @@ --- title: "Validation" weight: 1 +aliases: + - /tutorials/validation --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/minilogo/writing_a_grammar.md b/hugo/content/docs/learn/minilogo/writing_a_grammar.md index b9f02a6a..84b50b0b 100644 --- a/hugo/content/docs/learn/minilogo/writing_a_grammar.md +++ b/hugo/content/docs/learn/minilogo/writing_a_grammar.md @@ -1,6 +1,9 @@ --- title: "Writing a Grammar" weight: 0 +aliases: + - /tutorials/writing_a_grammar + - /writing_a_grammar --- {{< toc format=html >}} diff --git a/hugo/content/docs/learn/workflow/_index.md b/hugo/content/docs/learn/workflow/_index.md index b829400a..ddec04f2 100644 --- a/hugo/content/docs/learn/workflow/_index.md +++ b/hugo/content/docs/learn/workflow/_index.md @@ -1,7 +1,9 @@ --- title: "Langium's workflow" weight: 0 -url: /docs/learn/workflow/ +url: /docs/learn/workflow +aliases: + - /docs/getting-started --- Langium's workflow can be expressed as a flow chart diagram, which boils down to the following steps in the diagram. diff --git a/hugo/content/docs/recipes/builtin-library.md b/hugo/content/docs/recipes/builtin-library.md index 7e53a6c3..974047cd 100644 --- a/hugo/content/docs/recipes/builtin-library.md +++ b/hugo/content/docs/recipes/builtin-library.md @@ -8,7 +8,7 @@ For example, TypeScript provides users with typings for globally accessible vari They are part of the JavaScript runtime, and not defined by any user or a package they might import. Instead, these features are contributed through what we call builtin libraries. -Loading a builtin library in Langium is very simple. We first start off with defining the source code of the library using the *hello world* language from the [getting started guide](/docs/getting-started): +Loading a builtin library in Langium is very simple. We first start off with defining the source code of the library using the *hello world* language from the [getting started guide](/docs/learn/workflow): ```ts export const builtinHelloWorld = ` diff --git a/hugo/content/docs/recipes/code-bundling.md b/hugo/content/docs/recipes/code-bundling.md index f0fb6f78..1f2d0183 100644 --- a/hugo/content/docs/recipes/code-bundling.md +++ b/hugo/content/docs/recipes/code-bundling.md @@ -1,9 +1,11 @@ --- title: "Code Bundling" weight: 900 +aliases: + - /guides/code-bundling --- -When you first create a Langium project using the [Yeoman generator](/docs/learn/workflow/install), it will only contain a plain TypeScript configuration, without any additional build processes. +When you first create a Langium project using the [Yeoman generator](/docs/learn/workflow/scaffold#your-first-example-language), it will only contain a plain TypeScript configuration, without any additional build processes. However, if you want to make your language available for consumption in a non-development context, you'll want to create a bundle. It is not absolutely necessary in a Node.js context, since you can always resolve local `node_modules` but it's still recommended [for vscode extensions](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). It improves performance and decreases file size by minifying your code and only including what you actually need. diff --git a/hugo/content/docs/recipes/multiple-languages.md b/hugo/content/docs/recipes/multiple-languages.md index d76d7065..112a20e9 100644 --- a/hugo/content/docs/recipes/multiple-languages.md +++ b/hugo/content/docs/recipes/multiple-languages.md @@ -25,7 +25,7 @@ The entire change touches several files. Let's summarize what needs to be done: ## Our scenario -To keep this guide easy, I will use the `hello-world` project from the [learning section](/docs/learn/workflow). +To keep this guide easy, I will use the [`hello-world` project](/docs/learn/workflow) of the learning section. Let’s imagine that we have three languages: diff --git a/hugo/content/docs/recipes/scoping/_index.md b/hugo/content/docs/recipes/scoping/_index.md index 9d683f4f..b97b2708 100644 --- a/hugo/content/docs/recipes/scoping/_index.md +++ b/hugo/content/docs/recipes/scoping/_index.md @@ -25,8 +25,8 @@ In general, the way we resolve references is split into three phases of the docu In this guide, we'll look at different scoping kinds and styles and see how we can achieve them using Langium: -1. [Qualified Name Scoping](./qualified-name) -2. [Class Member Scoping](./class-member) +1. [Qualified Name Scoping](/docs/recipes/scoping/qualified-name) +2. [Class Member Scoping](/docs/recipes/scoping/class-member) Note that these are just example implementations for commonly used scoping methods. The scoping API of Langium is designed to be flexible and extensible for any kind of use case. diff --git a/hugo/content/docs/recipes/scoping/class-member.md b/hugo/content/docs/recipes/scoping/class-member.md index d6ef7ca1..2051ceb8 100644 --- a/hugo/content/docs/recipes/scoping/class-member.md +++ b/hugo/content/docs/recipes/scoping/class-member.md @@ -1,6 +1,8 @@ --- title: "Class Member Scoping" weight: 200 +aliases: + - /class-member --- In this guide we will take a look at member based scoping. It's a mechanism you are likely familiar with from object oriented languages such as Java, C# and JavaScript: diff --git a/hugo/content/docs/recipes/scoping/qualified-name.md b/hugo/content/docs/recipes/scoping/qualified-name.md index d79e968a..715bcabd 100644 --- a/hugo/content/docs/recipes/scoping/qualified-name.md +++ b/hugo/content/docs/recipes/scoping/qualified-name.md @@ -1,6 +1,8 @@ --- title: "Qualified Name Scoping" weight: 100 +aliases: + - /qualified-name --- Qualified name scoping refers to a style of referencing elements using a fully qualified name. @@ -21,7 +23,7 @@ void main() { As can be seen, using qualified name scoping is quite helpful in this case. It allows us to reference the `getDocumentation` function through the scope computed & made available by the `Langium` namespace, even though it's not directly accessible within the scope of `main` by itself. -Note that such behavior can also be accomplished using [class member scoping](./class-member). +Note that such behavior can also be accomplished using [class member scoping](/docs/recipes/scoping/class-member). However, there is one core advantage to using globally available elements: Compared to member scoping, this type of scoping requires few resources. The lookup required for qualified name scoping can be done in near constant time with just a bit of additional computation on a **per-document** basis, whereas member scoping needs to do a lot of computation on a **per-reference** basis. diff --git a/hugo/content/docs/reference/document-lifecycle.md b/hugo/content/docs/reference/document-lifecycle.md index 1a99770e..bc2a8247 100644 --- a/hugo/content/docs/reference/document-lifecycle.md +++ b/hugo/content/docs/reference/document-lifecycle.md @@ -1,6 +1,8 @@ --- title: 'Document Lifecycle' weight: 300 +aliases: + - /docs/document-lifecycle --- `LangiumDocument` is the central data structure in Langium that represents a text file of your DSL. Its main purpose is to hold the parsed Abstract Syntax Tree (AST) plus additional information derived from it. After its creation, a `LangiumDocument` must be "built" before it can be used in any way. The service responsible for building documents is called `DocumentBuilder`. diff --git a/hugo/content/docs/reference/grammar-language.md b/hugo/content/docs/reference/grammar-language.md index 2def1c3f..9bd6e7dd 100644 --- a/hugo/content/docs/reference/grammar-language.md +++ b/hugo/content/docs/reference/grammar-language.md @@ -1,6 +1,9 @@ --- title: "Grammar Language" weight: 100 +aliases: + - /grammar-language + - /docs/grammar-language --- {{< toc format=html >}} @@ -8,7 +11,9 @@ weight: 100 The grammar language describes the syntax and structure of your language. The [Langium grammar language](https://github.com/eclipse-langium/langium/blob/main/packages/langium/src/grammar/langium-grammar.langium) is implemented using Langium itself and therefore follows the same syntactic rules as any language created with Langium. The grammar language will define the structure of the *abstract syntax tree* (AST) which in Langium is a collection of *TypeScript types* describing the content of a parsed document and organized hierarchically. The individual nodes of the tree are then represented with JavaScript objects at runtime. In the following, we describe the Langium syntax and document structure. + ## Language Declaration + An *entry* Langium grammar file (i.e. a grammar which contains an [entry rule](#the-entry-rule)) always starts with a header which declares the name of the language. For example, a language named `MyLanguage` would be declared with: ```langium @@ -77,7 +82,7 @@ Person: ``` In this example, the parser will create an object of type `Person`. This object will have a property `name` which value and type must match the terminal rule `ID` (i.e. the property `name` is of type `string` and cannot start with a digit or special character). -By default, the parser will create an object with an inferred type corresponding to the parser rule name. It is possible to override this behavior by explicitly defining the type of the object to be created. This is done by adding the keyword `returns` followed by a separately declared type, or the keyword `infers` followed by the name of the type to be inferred for this rule (more about this [in the next chapter](../sematic-model)): +By default, the parser will create an object with an inferred type corresponding to the parser rule name. It is possible to override this behavior by explicitly defining the type of the object to be created. This is done by adding the keyword `returns` followed by a separately declared type, or the keyword `infers` followed by the name of the type to be inferred for this rule (more about this [in the next chapter](/docs/reference/semantic-model)): ```langium Person infers OtherType: 'person' name=ID; diff --git a/hugo/content/docs/reference/semantic-model.md b/hugo/content/docs/reference/semantic-model.md index 56df2bca..151bb111 100644 --- a/hugo/content/docs/reference/semantic-model.md +++ b/hugo/content/docs/reference/semantic-model.md @@ -1,6 +1,9 @@ --- title: "Semantic Model Inference" weight: 400 +aliases: + - /sematic-model + - /semantic-model --- When AST nodes are created during the parsing of a document, they are given a type. The language grammar dictates the shape of those types and how they might be related to each other. All types form the *semantic model* of your language. There are two ways by which Langium derives semantic model types from the grammar, by **[inference](#inferred-types)** and by **[declaration](#declared-types)**. @@ -89,7 +92,7 @@ interface X extends AstNode { ``` ### Assignments -There are three available kinds of [assignments](../grammar-language/#assignments) in a parser rule: +There are three available kinds of [assignments](/docs/reference/grammar-language/#assignments) in a parser rule: 1. `=` for assigning a **single value** to a property, resulting in the property's type to be derived from the right hand side of the assignment. 2. `+=` for assigning **multiple values** to a property, resulting in the property's type to be an array of the right hand side of the assignment. diff --git a/package-lock.json b/package-lock.json index 6abb9bfd..aeaa20cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,9 +12,14 @@ "tailwind" ], "devDependencies": { + "@types/chalk": "^2.2.0", + "chalk": "^4.0.0", "concurrently": "~8.2.1", "cross-env": "~7.0.3", - "shx": "~0.3.4" + "front-matter": "^4.0.2", + "glob": "^10.4.1", + "shx": "~0.3.4", + "ts-node": "^10.9.2" } }, "core": { @@ -315,6 +320,26 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/cli/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@babel/code-frame": { "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", @@ -1047,6 +1072,28 @@ "vscode": "npm:@codingame/monaco-vscode-api@1.83.2" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@esbuild/android-arm": { "version": "0.19.4", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.4.tgz", @@ -1399,6 +1446,102 @@ "node": ">=12" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -1498,6 +1641,16 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@rollup/plugin-inject": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.4.tgz", @@ -1573,6 +1726,30 @@ "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, "node_modules/@typefox/monaco-editor-react": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@typefox/monaco-editor-react/-/monaco-editor-react-2.3.0.tgz", @@ -1595,6 +1772,16 @@ "@types/responselike": "^1.0.0" } }, + "node_modules/@types/chalk": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/chalk/-/chalk-2.2.0.tgz", + "integrity": "sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw==", + "deprecated": "This is a stub types definition for chalk (https://github.com/chalk/chalk). chalk provides its own type definitions, so you don't need @types/chalk installed!", + "dev": true, + "dependencies": { + "chalk": "*" + } + }, "node_modules/@types/css-font-loading-module": { "version": "0.0.13", "resolved": "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.13.tgz", @@ -2010,6 +2197,15 @@ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "dev": true }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -2473,6 +2669,12 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -3187,6 +3389,15 @@ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", "dev": true }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -3204,6 +3415,12 @@ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "dev": true }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "node_modules/electron-to-chromium": { "version": "1.4.479", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.479.tgz", @@ -3604,6 +3821,19 @@ "node": ">=0.8.0" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -3675,6 +3905,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fraction.js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", @@ -3688,6 +3934,15 @@ "url": "https://www.patreon.com/infusion" } }, + "node_modules/front-matter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", + "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", + "dev": true, + "dependencies": { + "js-yaml": "^3.13.1" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -3768,19 +4023,22 @@ } }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -3797,6 +4055,30 @@ "node": ">= 6" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -3982,6 +4264,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -4127,11 +4410,42 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/jackspeak": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz", + "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -4765,6 +5079,12 @@ "semver": "bin/semver" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4813,6 +5133,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/monaco-editor": { "version": "0.44.0", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.44.0.tgz", @@ -5414,6 +5743,31 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5829,6 +6183,26 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/robust-predicates": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", @@ -5990,6 +6364,27 @@ "node": ">=4" } }, + "node_modules/shelljs/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/shx": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", @@ -6006,6 +6401,18 @@ "node": ">=6" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -6057,6 +6464,12 @@ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==" }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -6084,6 +6497,21 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -6096,6 +6524,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-dirs": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", @@ -6276,6 +6717,76 @@ "tree-kill": "cli.js" } }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/tslib": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", @@ -6371,6 +6882,12 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -6581,6 +7098,24 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -6653,6 +7188,15 @@ "fd-slicer": "~1.1.0" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", diff --git a/package.json b/package.json index cb45657c..51fdc8d5 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,18 @@ "watch": "npm run build --workspace core && concurrently -c gray,blue -k -n hugo,tailwind \"npm run watch --workspace hugo\" \"npm run watch --workspace tailwind\"", "watch:gitpod": "npm run build --workspace core && concurrently -c gray,blue -k -n hugo,tailwind \"npm run watch:gitpod --workspace hugo\" \"npm run watch --workspace tailwind\"", "build": "npm run clean && npm run build --workspace core --workspace=tailwind --workspace=hugo", - "clean": "shx rm -rf public && npm run clean --workspace core --workspace=tailwind" + "clean": "shx rm -rf public && npm run clean --workspace core --workspace=tailwind", + "check:links": "ts-node scripts/check-links.ts" }, "devDependencies": { + "@types/chalk": "^2.2.0", + "chalk": "^4.0.0", "concurrently": "~8.2.1", "cross-env": "~7.0.3", - "shx": "~0.3.4" + "front-matter": "^4.0.2", + "glob": "^10.4.1", + "shx": "~0.3.4", + "ts-node": "^10.9.2" }, "workspaces": [ "core", diff --git a/scripts/check-links.ts b/scripts/check-links.ts new file mode 100644 index 00000000..35bf3184 --- /dev/null +++ b/scripts/check-links.ts @@ -0,0 +1,140 @@ +import { glob } from "glob"; +import { readFile } from "node:fs/promises"; +import { basename, dirname, resolve, relative } from 'node:path'; +import chalk from 'chalk'; +import fm from "front-matter"; + +type Attributes = { + aliases?: string[]; + url?: string; + slug?: string; +} + +type MarkdownFile = { + localPath: string; + documentLink: string; + aliases: string[]; + links: string[]; +} + +type LinkType = 'alias'|'document'; + +const projectDir = dirname(__dirname); +const contentDir = resolve(projectDir, "hugo", "content"); + +async function main() { + const markdownFiles = await readMarkdownFiles(); + const setOfUrls = classifyAsDocumentLinksOrAliases(markdownFiles); + //await writeFile("existingLinks.txt", JSON.stringify([...setOfUrls.entries()], null, 2)); + const success = printMissingLinks(markdownFiles, setOfUrls); + if(success) { + console.log(chalk.greenBright('Success!')); + process.exit(0); + } else { + console.log(chalk.redBright('Failed!')); + process.exit(1); + } +} + +function classifyAsDocumentLinksOrAliases(markdownFiles: MarkdownFile[]) { + const documentLinks = [ + ...markdownFiles.map(m => m.documentLink), + 'http://langium.org/', + "/showcase", + "/playground" + ].map(urlToString).map(s => [s, 'document'] as const); + const aliases = markdownFiles.flatMap(m => m.aliases).map(urlToString).map(s => [s, 'alias'] as const); + return new Map([...documentLinks, ...aliases]); +} + +function printMissingLinks(markdownFiles: MarkdownFile[], setOfUrls: Map) { + let success: boolean = true; + for (const file of markdownFiles) { + let out = false; + for (const link of file.links) { + if (link.startsWith("http") || link.endsWith(".png") || link.endsWith(".jpg")) { + continue; + } + const url = urlToString(link); + if (!setOfUrls.has(url)) { + if (!out) { + console.log(`${relative(contentDir, file.localPath)}:`); + out = true; + } + console.log(`- ${chalk.red("MISSING LINK")}: ${url.toString()}`); + success = false; + } else if(setOfUrls.get(url) === 'alias') { + if (!out) { + console.log(`${relative(contentDir, file.localPath)}:`); + out = true; + } + console.log(`- ${chalk.yellow("LINK TO ALIAS")}: ${url.toString()}`); + success = false; + } + } + } + return success; +} + +async function readMarkdownFiles() { + const markdownFiles: MarkdownFile[] = []; + const mdfiles = await glob(`${contentDir}/**/*.md`); + for (const mdFile of mdfiles) { + const content = await readFile(mdFile, 'utf-8'); + + //urls + const { attributes: { url, aliases, slug }, body } = fm(content); + let urls: string[] = []; + if (aliases) { + urls = [...urls, ...aliases]; + } + let documentLink: string = ''; + if (url) { + documentLink = url; + } else if (slug) { + documentLink = relative(contentDir, resolve(mdFile, '..', slug)); + } else { + const base = basename(mdFile, '.md'); + if (['index', '_index'].includes(base)) { + documentLink = relative(contentDir, resolve(mdFile, '..')); + } else { + documentLink = relative(contentDir, resolve(mdFile, '..', base)); + } + } + + //links + const links = getAllLinks(content); + + //new file + markdownFiles.push({ + localPath: mdFile, + documentLink, + aliases: urls, + links + }); + } + return markdownFiles; +} + +function getAllLinks(content: string) { + const regexMdLinks = /\[([^\[]+)\](\(.*?\))/gm + const matches = content.match(regexMdLinks) + const singleMatch = /\[([^\[]+)\]\((.*?)\)/; + const result: string[] = []; + for (var i = 0; i < matches?.length ?? 0; i++) { + var text = singleMatch.exec(matches[i]) + result.push(text[2]); + } + return result; +} + +function urlToString(link: string): string { + const url = new URL(link, 'http://langium.org'); + url.hash = ""; + if(url.pathname.endsWith("/")) { + url.pathname = url.pathname.substring(0, url.pathname.length-1) + } + return url.toString(); +} + +main(); \ No newline at end of file