Compare commits

..

1 Commits

Author SHA1 Message Date
Colum Ferry de6f89189b feat(repo): add nx-graph-diff app 2025-08-06 16:17:20 +01:00
2184 changed files with 44166 additions and 126363 deletions
+7
View File
@@ -0,0 +1,7 @@
{
"mcpServers": {
"nx-mcp": {
"url": "http://localhost:9470/mcp"
}
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
"env": {
"node": true
},
"ignorePatterns": ["**/*.ts", "**/test-output"],
"ignorePatterns": ["**/*.ts"],
"plugins": ["@typescript-eslint", "@nx"],
"extends": ["plugin:storybook/recommended"],
"rules": {
+1 -1
View File
@@ -7,4 +7,4 @@
*.bat text eol=crlf
# Exclude files from Graphite reviews
docs/generated/* linguist-generated=true
*.pdf,*.gif,*.mp4,*.webp,*.avif,*.png,*.jpeg,*.jpg,*.tiff filter=lfs diff=lfs merge=lfs -text
*.gif,*.mp4,*.webp,*.avif,*.png,*.jpeg,*.jpg,*.tiff filter=lfs diff=lfs merge=lfs -text
+41 -22
View File
@@ -31,7 +31,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@v4
with:
fetch-depth: 0
filter: tree:0
@@ -41,7 +41,7 @@ jobs:
if: ${{ github.event_name == 'pull_request' }}
- name: Set SHAs
uses: nrwl/nx-set-shas@1859e66a83ac9be0dceecbd9a023702e27ac47f4 # v4.3.3
uses: nrwl/nx-set-shas@v4
with:
main-branch-name: 'master'
@@ -54,32 +54,43 @@ jobs:
sudo apt-get install -y ca-certificates lsof libvips-dev libglib2.0-dev libgirepository1.0-dev
- name: Install Chrome
uses: browser-actions/setup-chrome@2dbff04819ebbfd5c974947148805a825b8a07fd # v2.1.0
uses: browser-actions/setup-chrome@v1
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10.11.1
run_install: false
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1
- name: Cache Rust toolchain and cargo registry
uses: actions/cache@v4
with:
rustflags: ''
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Setup Java
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Setup Gradle
uses: gradle/actions/setup-gradle@48b5f213c81028ace310571dc5ec0fbbca0b2947 # v4.4.3
uses: gradle/actions/setup-gradle@v4
- name: Install project dependencies
run: |
@@ -113,9 +124,6 @@ jobs:
wait "$pid"
done
timeout-minutes: 100
- name: Fix CI
run: pnpm nx-cloud fix-ci
if: failure()
main-macos:
runs-on: macos-latest
@@ -139,7 +147,7 @@ jobs:
if: always()
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@v4
with:
fetch-depth: 0
filter: tree:0
@@ -149,7 +157,7 @@ jobs:
if: ${{ github.event_name == 'pull_request' }}
- name: Restore Homebrew packages
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
uses: actions/cache@v4
with:
path: |
/opt/homebrew
@@ -254,28 +262,39 @@ jobs:
ls -la ~/Library/Logs/CoreSimulator/ || echo "No simulator logs found"
- name: Save Homebrew Cache
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
uses: actions/cache@v4
with:
path: |
/opt/homebrew
~/Library/Caches/Homebrew
key: nrwl-nx-homebrew-packages
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10.11.1
run_install: false
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1
- name: Cache Rust toolchain and cargo registry
uses: actions/cache@v4
with:
rustflags: ''
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install project dependencies
run: |
@@ -283,7 +302,7 @@ jobs:
pnpm playwright install --with-deps
- name: Set SHAs
uses: nrwl/nx-set-shas@1859e66a83ac9be0dceecbd9a023702e27ac47f4 # v4.3.3
uses: nrwl/nx-set-shas@v4
with:
main-branch-name: 'master'
+93
View File
@@ -0,0 +1,93 @@
name: Claude Code
env:
PNPM_HOME: ~/.pnpm
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
jobs:
claude:
if: |
contains(fromJson('["AgentEnder", "barbados-clemens", "Cammisuli", "Coly010", "FrozenPandaz", "isaacplmann", "JamesHenry", "jaysoo", "leosvelperez", "mandarini", "MaxKless", "meeroslav", "nartc", "ndcunningham", "philipjfulcher", "vsavkin", "xiongemi"]'), github.actor) &&
((github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))))
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
actions: read
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 250
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y ca-certificates lsof libvips-dev libglib2.0-dev libgirepository1.0-dev
- name: Install Chrome
uses: browser-actions/setup-chrome@v1
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10.11.1
run_install: false
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
.cargo-cache
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- name: Install project dependencies
run: |
pnpm install --frozen-lockfile
pnpm playwright install --with-deps
- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@beta
timeout-minutes: 90
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
allowed_tools: "Bash,Edit,Read,Write,Glob,Grep,LS,MultiEdit,NotebookRead,NotebookEdit"
-104
View File
@@ -1,104 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ "master" ]
schedule:
- cron: '20 14 * * 6'
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: actions
build-mode: none
# We would like to test our Java / Kotlin... but its currently failing. We can follow up.
# - language: java-kotlin
# build-mode: autobuild
- language: javascript-typescript
build-mode: none
- language: rust
build-mode: none
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
# Add any setup steps before running the `github/codeql-action/init` action.
# This includes steps like installing compilers or runtimes (`actions/setup-node`
# or others). This is typically only required for manual builds.
# - name: Setup runtime (example)
# uses: actions/setup-example@v1
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@15403aac29bd91419968e066cded66bde56b0283 # v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@15403aac29bd91419968e066cded66bde56b0283 # v3
with:
category: "/language:${{matrix.language}}"
-101
View File
@@ -1,101 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
pull_request:
branches: [ "**" ]
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: actions
build-mode: none
# See comment in @./codeql-master.yml about Java / Kotlin
# - language: java-kotlin
# build-mode: autobuild
- language: javascript-typescript
build-mode: none
- language: rust
build-mode: none
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
# Add any setup steps before running the `github/codeql-action/init` action.
# This includes steps like installing compilers or runtimes (`actions/setup-node`
# or others). This is typically only required for manual builds.
# - name: Setup runtime (example)
# uses: actions/setup-example@v1
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@15403aac29bd91419968e066cded66bde56b0283 # v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@15403aac29bd91419968e066cded66bde56b0283 # v3
with:
category: "/language:${{matrix.language}}"
upload: 'never'
upload-database: false
+23 -27
View File
@@ -45,19 +45,19 @@ jobs:
name: Cache install (${{ matrix.os }}, node v${{ matrix.node_version }})
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@v4
with:
fetch-depth: 0
filter: tree:0
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10.11.1
run_install: false
- name: Set node
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node_version }}
cache: 'pnpm'
@@ -67,7 +67,7 @@ jobs:
run: echo "path=$(pnpm store path)" >> $GITHUB_OUTPUT
- name: Cache pnpm store
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache.outputs.path }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('pnpm-lock.yaml') }}
@@ -80,9 +80,7 @@ jobs:
run: brew install python-setuptools
- name: Install packages
run: |
pnpm install --frozen-lockfile
pnpm playwright install --with-deps
run: pnpm install --frozen-lockfile
- name: Homebrew cache directory path
if: ${{ matrix.os == 'macos-latest' }}
@@ -91,7 +89,7 @@ jobs:
- name: Cache Homebrew
if: ${{ matrix.os == 'macos-latest' }}
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
uses: actions/cache@v4
with:
lookup-only: true
path: ${{ steps.homebrew-cache-dir-path.outputs.dir }}
@@ -101,7 +99,7 @@ jobs:
- name: Cache Cypress
id: cache-cypress
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
uses: actions/cache@v4
with:
lookup-only: true
path: '${{ github.workspace }}/.cypress'
@@ -120,7 +118,7 @@ jobs:
matrix: ${{ steps.process-json.outputs.MATRIX }}
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@v4
with:
fetch-depth: 0
filter: tree:0
@@ -146,7 +144,7 @@ jobs:
name: ${{ matrix.os_name }}/${{ matrix.package_manager }}/${{ matrix.node_version }} ${{ join(matrix.project) }}
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@v4
with:
fetch-depth: 0
filter: tree:0
@@ -154,14 +152,14 @@ jobs:
- name: Prepare dir for output
run: mkdir -p outputs
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
version: 10.11.1
run_install: false
- name: Use Node.js ${{ matrix.node_version }}
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node_version }}
cache: 'pnpm'
@@ -179,14 +177,12 @@ jobs:
- name: Install bun
if: ${{ matrix.os != 'windows-latest' }}
uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2
uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- name: Install packages
run: |
pnpm install --frozen-lockfile
pnpm playwright install --with-deps
run: pnpm install --frozen-lockfile
- name: Cleanup
if: ${{ matrix.os == 'ubuntu-latest' }}
@@ -207,7 +203,7 @@ jobs:
- name: Cache Homebrew
if: ${{ matrix.os == 'macos-latest' }}
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
uses: actions/cache@v4
with:
path: ${{ steps.homebrew-cache-dir-path.outputs.dir }}
key: brew-${{ matrix.node_version }}
@@ -216,7 +212,7 @@ jobs:
- name: Cache Cypress
id: cache-cypress
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
uses: actions/cache@v4
with:
path: '${{ github.workspace }}/.cypress'
key: ${{ runner.os }}-cypress
@@ -397,7 +393,7 @@ jobs:
echo "$matrix" > 'outputs/matrix.json'
- name: Upload matrix config
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@v4
if: ${{ always() }}
with:
name: ${{ matrix.os_name}}-${{ matrix.node_version}}-${{ matrix.package_manager}}-${{ matrix.project }}
@@ -407,7 +403,7 @@ jobs:
- name: Setup tmate session
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled && failure() }}
uses: mxschmitt/action-tmate@1fb8b1023602bf1fd0e2994d7f1e93015cb5bbec # v3.22
uses: mxschmitt/action-tmate@v3.8
timeout-minutes: 15
with:
sudo: ${{ matrix.os != 'windows-latest' }} # disable sudo for windows debugging
@@ -425,7 +421,7 @@ jobs:
has_golden_failures: ${{ steps.process-json.outputs.has_golden_failures }}
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@v4
with:
fetch-depth: 0
filter: tree:0
@@ -434,7 +430,7 @@ jobs:
run: mkdir -p outputs
- name: Load outputs
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
uses: actions/download-artifact@v4
with:
path: outputs
@@ -457,7 +453,7 @@ jobs:
timeout-minutes: 10
steps:
- name: Send notification
uses: ravsamhq/notify-slack-action@be814b201e233b2dc673608aa46e5447c8ab13f2 # v11
uses: ravsamhq/notify-slack-action@v2
with:
status: 'failure'
message_format: '${{ needs.process-result.outputs.message }}'
@@ -475,7 +471,7 @@ jobs:
timeout-minutes: 10
steps:
- name: Send notification
uses: ravsamhq/notify-slack-action@be814b201e233b2dc673608aa46e5447c8ab13f2 # v11
uses: ravsamhq/notify-slack-action@v2
with:
status: 'success'
message_format: '${{ needs.process-result.outputs.message }}'
@@ -492,7 +488,7 @@ jobs:
name: Report duration per package manager
steps:
- name: Send notification
uses: ravsamhq/notify-slack-action@be814b201e233b2dc673608aa46e5447c8ab13f2 # v11
uses: ravsamhq/notify-slack-action@v2
with:
status: 'skipped'
message_format: '${{ needs.process-result.outputs.pm_duration }}'
@@ -508,7 +504,7 @@ jobs:
name: Report duration per project
steps:
- name: Send notification
uses: ravsamhq/notify-slack-action@be814b201e233b2dc673608aa46e5447c8ab13f2 # v11
uses: ravsamhq/notify-slack-action@v2
with:
status: 'skipped'
message_format: '${{ needs.process-result.outputs.proj_duration }}'
+4 -4
View File
@@ -14,15 +14,15 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@v3
- name: Install Node.js
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@v3
with:
node-version: '20.19.0'
- name: Install pnpm
uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
uses: pnpm/action-setup@v4
id: pnpm-install
with:
version: 10.11.1
@@ -35,7 +35,7 @@ jobs:
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- name: Setup pnpm cache
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
uses: actions/cache@v3
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
+7 -8
View File
@@ -16,21 +16,21 @@ jobs:
name: Report status
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@v3
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
- uses: pnpm/action-setup@v4
with:
version: 10.11.1
- name: Use Node.js ${{ matrix.node_version }}
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@v3
with:
node-version: '20.19.0'
cache: 'pnpm'
- name: Cache node_modules
id: cache-modules
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
uses: actions/cache@v3
with:
lookup-only: true
path: '**/node_modules'
@@ -41,12 +41,11 @@ jobs:
- name: Download artifact
id: download-artifact
uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e # v2 # Needed since we are downloading artifact from a different workflow run, official actions/download-artifact doesn't support this.
uses: dawidd6/action-download-artifact@v2 # Needed since we are downloading artifact from a different workflow run, official actions/download-artifact doesn't support this.
with:
name: cached-issue-data
path: ${{ github.workspace }}/scripts/issues-scraper/cached
search_artifacts: true
allow_forks: false
continue-on-error: true
- name: Collect Issue Data
@@ -55,14 +54,14 @@ jobs:
env:
GITHUB_TOKEN: ${{ github.token }}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
- uses: actions/upload-artifact@v4
with:
name: cached-issue-data
path: ./scripts/issues-scraper/cached/data.json
- name: Send GitHub Action trigger data to Slack workflow
id: slack
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
uses: slackapi/slack-github-action@v1.23.0
with:
payload: ${{ steps.collect.outputs.SLACK_MESSAGE }}
env:
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
if: ${{ github.repository_owner == 'nrwl' }}
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@7de207be1d3ce97a9abe6ff1306222982d1ca9f9 # v5.0.1
- uses: dessant/lock-threads@v4
id: lockthreads
with:
github-token: ${{ github.token }}
+13 -21
View File
@@ -38,46 +38,38 @@ const matrixData: MatrixData = {
{ name: 'e2e-js', codeowners: 'S04SJ6HHP0X', is_golden: true },
{ name: 'e2e-nx-init', codeowners: 'S04SYHYKGNP', is_golden: true },
{ name: 'e2e-nx', codeowners: 'S04SYHYKGNP' },
{ name: 'e2e-release', codeowners: 'S04SYHYKGNP' },
{ name: 'e2e-workspace-create', codeowners: 'S04SYHYKGNP' }
{ name: 'e2e-release', codeowners: 'S04SYHYKGNP'},
{ name: 'e2e-workspace-create', codeowners: 'S04SYHYKGNP' },
],
projects: [
{ name: 'e2e-cypress', codeowners: 'S04T16BTJJY', is_golden: true },
{ name: 'e2e-docker', codeowners: 'S04SJ6HHP0X', is_golden: true },
{ name: 'e2e-detox', codeowners: 'S04TNCNJG5N', is_golden: true },
{ name: 'e2e-esbuild', codeowners: 'S04SJ6HHP0X', is_golden: true },
{ name: 'e2e-gradle', codeowners: 'S04TNCNJG5N', is_golden: true },
{ name: 'e2e-detox', codeowners: 'S04TNCNJG5N' , is_golden: true},
{ name: 'e2e-esbuild', codeowners: 'S04SJ6HHP0X' , is_golden: true},
{ name: 'e2e-gradle', codeowners: 'S04TNCNJG5N' , is_golden: true},
{ name: 'e2e-eslint', codeowners: 'S04SYJGKSCT', is_golden: true },
{ name: 'e2e-node', codeowners: 'S04SJ6HHP0X', is_golden: true },
{ name: 'e2e-playwright', codeowners: 'S04SVQ8H0G5', is_golden: true },
{ name: 'e2e-remix', codeowners: 'S04SVQ8H0G5', is_golden: true },
{ name: 'e2e-remix', codeowners: 'S04SVQ8H0G5' , is_golden: true},
{ name: 'e2e-rspack', codeowners: 'S04SJ6HHP0X', is_golden: true },
{ name: 'e2e-vite', codeowners: 'S04SJ6PL98X', is_golden: true },
{ name: 'e2e-vue', codeowners: 'S04SJ6PL98X', is_golden: true },
{ name: 'e2e-vite', codeowners: 'S04SJ6PL98X' , is_golden: true},
{ name: 'e2e-vue', codeowners: 'S04SJ6PL98X' , is_golden: true},
{ name: 'e2e-web', codeowners: 'S04SJ6PL98X', is_golden: true },
{ name: 'e2e-webpack', codeowners: 'S04SJ6PL98X', is_golden: true },
{ name: 'e2e-jest', codeowners: 'S04T16BTJJY', is_golden: true },
{ name: 'e2e-expo', codeowners: 'S04TNCNJG5N', is_golden: true },
{ name: 'e2e-react-native', codeowners: 'S04TNCNJG5N', is_golden: true },
{ name: 'e2e-angular', codeowners: 'S04SS457V38' },
{ name: 'e2e-expo', codeowners: 'S04TNCNJG5N' },
{ name: 'e2e-next', codeowners: 'S04TNCNJG5N' },
{ name: 'e2e-plugin', codeowners: 'S04SYHYKGNP' },
{ name: 'e2e-react', codeowners: 'S04TNCNJG5N' },
{ name: 'e2e-react-native', codeowners: 'S04TNCNJG5N' },
{ name: 'e2e-rollup', codeowners: 'S04SJ6PL98X' },
{ name: 'e2e-storybook', codeowners: 'S04SVQ8H0G5' },
{ name: 'e2e-nuxt', codeowners: 'S04SJ6PL98X' }
],
nodeTLS: 20,
setup: [
{
os: 'ubuntu-latest',
os_name: 'Linux',
os_timeout: 60,
package_managers: ['npm', 'pnpm', 'yarn'],
node_versions: ['20.19.0', '22.12.0'],
excluded: ['e2e-detox', 'e2e-react-native', 'e2e-expo']
},
{ os: 'macos-latest', os_name: 'MacOS', os_timeout: 90, package_managers: ['npm'], node_versions: ['20.19.0'] }
{ os: 'ubuntu-latest', os_name: 'Linux', os_timeout: 60, package_managers: ['npm', 'pnpm', 'yarn'], node_versions: ['20.19.0', "22.12.0"], excluded: ['e2e-detox', 'e2e-react-native', 'e2e-expo'] },
{ os: 'macos-latest', os_name: 'MacOS', os_timeout: 90, package_managers: ['npm'], node_versions: ['20.19.0'] },
// TODO (emily): Fix Windows support as gradle fails when running nx build https://staging.nx.app/runs/LgD4vxGn8w?utm_source=pull-request&utm_medium=comment
// { os: 'windows-latest', os_name: 'WinOS', os_timeout: 180, package_managers: ['npm'], node_versions: ['20.19.0'], excluded: ['e2e-detox', 'e2e-react-native', 'e2e-expo'] }
]
@@ -94,7 +86,7 @@ function addMatrixCombo(project: MatrixDataProject, nodeVersion: number | string
os: matrixData.setup[os].os,
os_name: matrixData.setup[os].os_name,
os_timeout: matrixData.setup[os].os_timeout,
is_golden: !!project.is_golden // Mark golden projects as true, others as false
is_golden: !!project.is_golden, // Mark golden projects as true, others as false
});
}
+3 -3
View File
@@ -14,9 +14,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@v3
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
- uses: pnpm/action-setup@v4
with:
version: 10.11.1 # Aligned with root package.json (pnpm/action-setup will helpfully error if out of sync)
@@ -30,7 +30,7 @@ jobs:
name: Report status
steps:
- name: Send notification
uses: ravsamhq/notify-slack-action@be814b201e233b2dc673608aa46e5447c8ab13f2 # v11
uses: ravsamhq/notify-slack-action@v2
with:
status: ${{ needs.audit.result }}
message_format: '{emoji} Audit has {status_message}'
-30
View File
@@ -1,30 +0,0 @@
name: PR Title Validation
on:
pull_request:
types: [opened, edited, synchronize, reopened]
permissions: read-all
jobs:
validate-pr-title:
name: Validate PR Title
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# Ensure's validate-pr-title.js is the copy from master
ref: master
- name: Setup Node.js
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: 20
package-manager-cache: false
- name: Validate PR title
env:
PR_TITLE: ${{ github.event.pull_request.title }}
PR_BODY: ${{ github.event.pull_request.body }}
run: node ./scripts/validate-pr-title.js
+100 -48
View File
@@ -3,7 +3,14 @@ name: publish
on:
# Automated schedule - canary releases from master
schedule:
- cron: "0 20 * * 1-5" # Monday - Friday, at 20:00 UTC (8pm UTC)
- cron: "0 3 * * 2-6" # Tuesdays - Saturdays, at 3am UTC
# Manual trigger - PR releases or dry-runs (based on workflow inputs)
workflow_dispatch:
inputs:
pr:
description: "PR Number - If set, a real release will be created for the branch associated with the given PR number. If blank, a dry-run of the currently selected branch will be performed."
required: false
type: number
release:
types: [ published ]
@@ -28,6 +35,11 @@ jobs:
# - release:
# - We are running a full release which is based on the tag that triggered the release event, we can use default
# ref resolution in actions/checkout. The exact version will be generated within scripts/nx-release.ts.
#
# - workflow_dispatch:
# - We are either running a dry-run on the current branch, in which case the version will be statica and we can use
# default ref resolution in actions/checkout, or we are creating a PR release for the given PR number, in which case
# we should generate an applicable version number within publish-resolve-data.js and use a custom ref of the PR branch name.
resolve-required-data:
name: Resolve Required Data
if: ${{ github.repository_owner == 'nrwl' }}
@@ -35,25 +47,35 @@ jobs:
outputs:
version: ${{ steps.script.outputs.version }}
dry_run_flag: ${{ steps.script.outputs.dry_run_flag }}
success_comment: ${{ steps.script.outputs.success_comment }}
publish_branch: ${{ steps.script.outputs.publish_branch }}
ref: ${{ steps.script.outputs.ref }}
repo: ${{ steps.script.outputs.repo }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
steps:
# Default checkout on the triggering branch so that the latest publish-resolve-data.js script is available
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@v4
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
# Set up pnpm and node so that we can verify our setup and that the NPM_TOKEN secret will work later
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup node
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
registry-url: 'https://registry.npmjs.org'
check-latest: true
# Ensure that the NPM_TOKEN secret is still valid before wasting any time deriving data or building projects
- name: Check NPM Credentials
run: npm whoami && echo "NPM credentials are valid" || (echo "NPM credentials are invalid or have expired." && exit 1)
- name: Resolve and set checkout and version data to use for release
id: script
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ github.event.inputs.pr }}
with:
@@ -62,6 +84,36 @@ jobs:
const script = require('${{ github.workspace }}/scripts/publish-resolve-data.js');
await script({ github, context, core });
- name: (PR Release Only) Check out latest master
if: ${{ steps.script.outputs.ref != '' }}
uses: actions/checkout@v4
with:
# Check out the latest master branch to get its copy of nx-release.ts
repository: nrwl/nx
ref: master
path: latest-master-checkout
- name: (PR Release Only) Check out PR branch
if: ${{ steps.script.outputs.ref != '' }}
uses: actions/checkout@v4
with:
# Check out the PR branch to get its copy of nx-release.ts
repository: ${{ steps.script.outputs.repo }}
ref: ${{ steps.script.outputs.ref }}
path: pr-branch-checkout
- name: (PR Release Only) Ensure that nx-release.ts has not changed in the PR being released
if: ${{ steps.script.outputs.ref != '' }}
env:
FILE_TO_COMPARE: "scripts/nx-release.ts"
run: |
if ! cmp -s "latest-master-checkout/${{ env.FILE_TO_COMPARE }}" "pr-branch-checkout/${{ env.FILE_TO_COMPARE }}"; then
echo "🛑 Error: The file ${{ env.FILE_TO_COMPARE }} is different on the ${{ steps.script.outputs.ref }} branch on ${{ steps.script.outputs.repo }} vs latest master on nrwl/nx, cancelling workflow. If you did not modify the file, then you likely just need to rebase/merge latest master."
exit 1
else
echo "✅ The file ${{ env.FILE_TO_COMPARE }} is identical between the ${{ steps.script.outputs.ref }} branch on ${{ steps.script.outputs.repo }} and latest master on nrwl/nx."
fi
build:
needs: [ resolve-required-data ]
if: ${{ github.repository_owner == 'nrwl' }}
@@ -215,14 +267,17 @@ jobs:
name: stable - ${{ matrix.settings.target }} - node@22.16.0
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@v4
with:
repository: ${{ needs.resolve-required-data.outputs.repo }}
ref: ${{ needs.resolve-required-data.outputs.ref }}
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup node
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@v4
if: ${{ !matrix.settings.docker }}
with:
node-version: ${{ env.NODE_VERSION }}
@@ -230,14 +285,13 @@ jobs:
cache: 'pnpm'
- name: Install
uses: actions-rust-lang/setup-rust-toolchain@ac90e63697ac2784f4ecfe2964e1a285c304003a # v1
uses: dtolnay/rust-toolchain@stable
if: ${{ !matrix.settings.docker }}
with:
target: ${{ matrix.settings.target }}
rustflags: ''
targets: ${{ matrix.settings.target }}
- name: Cache cargo
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
@@ -247,7 +301,7 @@ jobs:
target/
key: ${{ matrix.settings.target }}-cargo-registry
- uses: goto-bus-stop/setup-zig@abea47f85e598557f500fa1fd2ab7464fcb39406 # v2.2.1
- uses: goto-bus-stop/setup-zig@v2
if: ${{ matrix.settings.target == 'armv7-unknown-linux-gnueabihf' }}
with:
version: 0.10.0
@@ -268,7 +322,7 @@ jobs:
timeout-minutes: 30
- name: Setup node x86
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@v4
if: matrix.settings.target == 'i686-pc-windows-msvc'
with:
node-version: ${{ env.NODE_VERSION }}
@@ -277,7 +331,7 @@ jobs:
architecture: x86
- name: Build in docker
uses: addnab/docker-run-action@4f65fabd2431ebc8d299f8e5a018d79a769ae185 # v3
uses: addnab/docker-run-action@v3
if: ${{ matrix.settings.docker }}
with:
image: ${{ matrix.settings.docker }}
@@ -290,7 +344,7 @@ jobs:
shell: bash
- name: Upload artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@v4
with:
name: bindings-${{ matrix.settings.target }}
path: |
@@ -305,11 +359,14 @@ jobs:
name: Build FreeBSD
timeout-minutes: 45
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@v4
with:
repository: ${{ needs.resolve-required-data.outputs.repo }}
ref: ${{ needs.resolve-required-data.outputs.ref }}
- name: Build
id: build
uses: cross-platform-actions/action@462ed697694d2ac9aa49e1225f395f7bb6dd49fe # v0.29.0
uses: cross-platform-actions/action@v0.25.0
env:
DEBUG: napi:*
RUSTUP_IO_THREADS: 1
@@ -354,7 +411,7 @@ jobs:
echo "COMPLETE"
- name: Upload artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@v4
with:
name: bindings-freebsd
path: |
@@ -365,7 +422,6 @@ jobs:
if: ${{ github.repository_owner == 'nrwl' }}
name: Publish
runs-on: ubuntu-latest
environment: npm-registry
permissions:
id-token: write
contents: write
@@ -376,29 +432,31 @@ jobs:
- build
env:
GH_TOKEN: ${{ github.token }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_CONFIG_PROVENANCE: true
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@v4
with:
repository: ${{ needs.resolve-required-data.outputs.repo }}
ref: ${{ needs.resolve-required-data.outputs.ref }}
- uses: pnpm/action-setup@7088e561eb65bb68695d245aa206f005ef30921d # v4.1.0
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup node
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
registry-url: 'https://registry.npmjs.org'
check-latest: true
cache: 'pnpm'
- name: Use npm 11.5.2
run: npm install -g npm@11.5.2
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Download all artifacts
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
uses: actions/download-artifact@v4
with:
path: artifacts
@@ -432,27 +490,21 @@ jobs:
if: ${{ !github.event.release.prerelease && github.event_name == 'release' }}
run: npx ts-node -P ./scripts/tsconfig.scripts.json ./scripts/release-docs.ts
report-pending-publish:
name: Report Pending Publish to Slack
if: ${{ github.repository_owner == 'nrwl' }}
needs:
- resolve-required-data
- build-freebsd
- build
runs-on: ubuntu-latest
timeout-minutes: 10
continue-on-error: true # Don't fail the workflow if notification fails
steps:
- name: Send Slack notification
uses: ravsamhq/notify-slack-action@be814b201e233b2dc673608aa46e5447c8ab13f2 # v11
with:
status: ${{ job.status }}
notification_title: '📦 Publish Pending Review'
message_format: ${{ format('Version `{0}` is being published to NPM - manual review is required', needs.resolve-required-data.outputs.version) }}
footer: '<{run_url}|View Workflow Run>'
mention_groups: 'U9NPA6C90' # Jason
- name: (PR Release Only) Create comment for successful PR release
if: success() && github.event.inputs.pr
uses: actions/github-script@v7
env:
SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }}
SUCCESS_COMMENT: ${{ needs.resolve-required-data.outputs.success_comment }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const successComment = JSON.parse(process.env.SUCCESS_COMMENT);
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ${{ github.event.inputs.pr }},
body: successComment
});
pr_failure_comment:
# Run this job if it is a PR release, running on the nrwl origin, and any of the required jobs failed
@@ -462,7 +514,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Create comment for failed PR release
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
# This script is intentionally kept inline (and e.g. not generated in publish-resolve-data.js)
+5 -5
View File
@@ -19,7 +19,7 @@ jobs:
# This handles issues that need more info
- name: stale-more-info-needed
id: stale-more-info-needed
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
uses: actions/stale@v9.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 7
@@ -37,7 +37,7 @@ jobs:
# This handles PRs that need to be rebased
- name: stale-needs-rebase
id: stale-needs-rebase
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
uses: actions/stale@v9.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 7
@@ -56,7 +56,7 @@ jobs:
# This handles issues that do not have a repro
- name: stale-repro-needed
id: stale-repro-needed
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
uses: actions/stale@v9.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 7
@@ -75,7 +75,7 @@ jobs:
- name: stale-retry-with-latest
id: stale-retry-with-latest
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
uses: actions/stale@v9.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 7
@@ -95,7 +95,7 @@ jobs:
# This handles issues are really old and were made with a previous major
- name: stale-bug
id: stale-bug
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
uses: actions/stale@v9.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 180
+6 -14
View File
@@ -3,7 +3,6 @@ node_modules
/.fleet
/.vscode
dist
out-tsc
/build
/coverage
./test
@@ -13,8 +12,7 @@ tmp
jest.debug.config.js
.tool-versions
/.nx-cache
/.nx/cache
/.nx/workspace-data
/.nx
/.verdaccio/build/local-registry
/graph/client/src/assets/environment.js
/graph/client/src/assets/dev/environment.js
@@ -52,6 +50,8 @@ out
# Fix for issue when working on the repo in a dev container
.pnpm-store
.nx
!.nx/workflows
.cargo/.package-cache
.cargo/bin/
@@ -102,20 +102,12 @@ node_modules/
.cursorindexingignore
# OS specific
# Task files
/tasks.json
/tasks
tasks.json
tasks/
# Upstream docs local configuration (machine-specific)
.upstreamdocs.local.json
astro-docs/.netlify
# Angular Rspack Specific Options
packages/angular-rspack/coverage
packages/angular-rspack-compiler/coverage
# Angular Rspack Packages use a template to generate the correct README
packages/angular-rspack/README.md
packages/angular-rspack-compiler/README.md
test-output
vitest.config.*.timestamp*
-1
View File
@@ -1 +0,0 @@
node ./scripts/commit-lint.js "$1"
+5 -18
View File
@@ -1,6 +1,6 @@
launch-templates:
linux-large:
resource-class: 'docker_linux_amd64/large'
linux-medium:
resource-class: 'docker_linux_amd64/medium+'
image: 'us-east1-docker.pkg.dev/nxcloudoperations/nx-cloud/nx-agents-base-images:ubuntu22.04-node20.19-v1'
env:
GIT_AUTHOR_EMAIL: test@test.com
@@ -65,15 +65,11 @@ launch-templates:
- name: Load Cargo Env
script: echo "PATH=$HOME/.cargo/bin:$PATH" >> $NX_CLOUD_ENV
- name: Install Rust Dependencies
script: |
cargo fetch
- name: Setup Java 21
- name: Setup Java 17
script: |
sudo apt update
sudo apt install -y openjdk-21-jdk
sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-amd64/bin/java
sudo apt install -y openjdk-17-jdk
sudo update-alternatives --set java /usr/lib/jvm/java-17-openjdk-amd64/bin/java
java -version
- name: Setup Gradle
@@ -146,18 +142,9 @@ launch-templates:
- name: Load Cargo Env
script: echo "PATH=$HOME/.cargo/bin:$PATH" >> $NX_CLOUD_ENV
- name: Install Rust Dependencies
script: |
cargo fetch
- name: Setup Java 21
script: |
sudo apt update
sudo apt install -y openjdk-21-jdk
sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-amd64/bin/java
java -version
- name: Setup Gradle
script: |
./gradlew wrapper
./gradlew --version
+6 -26
View File
@@ -1,33 +1,13 @@
distribute-on:
default: auto linux-large, 1 linux-extra-large
default: auto linux-medium, 1 linux-extra-large
assignment-rules:
# e2e-release tests must run sequentially due to shared git state and publishing operations
- projects:
- e2e-release
targets:
- e2e-ci**
run-on:
- agent: linux-large
parallelism: 1
- projects:
- e2e-gradle
targets:
- e2e-ci**
run-on:
- agent: linux-large
parallelism: 1
- agent: linux-extra-large
parallelism: 1
# All other e2e tests can run in parallel
- targets:
- e2e-ci**
run-on:
- agent: linux-large
parallelism: 2
- agent: linux-medium
parallelism: 1
- agent: linux-extra-large
parallelism: 3
parallelism: 1
# These projects should not need to be isolated.
- projects:
@@ -49,13 +29,13 @@ assignment-rules:
- targets:
- lint
run-on:
- agent: linux-large
- agent: linux-medium
parallelism: 6
- targets:
- '*'
run-on:
- agent: linux-large
- agent: linux-medium
parallelism: 3
- agent: linux-extra-large
parallelism: 3
+3 -6
View File
@@ -12,7 +12,7 @@ rust-toolchain.toml @nrwl/nx-native-reviewers
/astro-docs @nrwl/nx-docs-reviewers
/docs @nrwl/nx-docs-reviewers
/docs/nx-cloud @StalkAltan @rarmatei @nixallover @nrwl/nx-docs-reviewers
/graph/** @philipjfulcher @FrozenPandaz @bcabanes @MaxKless @Coly010 @jaysoo @nartc
/graph/** @philipjfulcher @FrozenPandaz @bcabanes @MaxKless @Coly010 @jaysoo
/images @nrwl/nx-docs-reviewers
/nx-dev/** @nrwl/nx-docs-reviewers
/typedoc-theme @nrwl/nx-docs-reviewers
@@ -23,9 +23,6 @@ rust-toolchain.toml @nrwl/nx-native-reviewers
/docs/generated/packages/angular/** @nrwl/nx-angular-reviewers @nrwl/nx-docs-reviewers
/docs/shared/packages/angular/** @nrwl/nx-angular-reviewers @nrwl/nx-docs-reviewers
/packages/angular/** @nrwl/nx-angular-reviewers
/packages/angular-rspack/** @nrwl/nx-angular-reviewers
/packages/angular-rspack-compiler/** @nrwl/nx-angular-reviewers
/examples/angular-rspack/** @nrwl/nx-angular-reviewers
/e2e/angular/** @nrwl/nx-angular-reviewers
/packages/angular/plugins/component-testing.ts @nrwl/nx-angular-reviewers @nrwl/nx-testing-tools-reviewers
/packages/angular/src/generators/cypress-component-configuration/** @nrwl/nx-angular-reviewers @nrwl/nx-testing-tools-reviewers
@@ -152,8 +149,8 @@ rust-toolchain.toml @nrwl/nx-native-reviewers
/packages/devkit/public-api.ts @FrozenPandaz @vsavkin
# Gradle
/packages/gradle/** @FrozenPandaz @MaxKless @lourw
/e2e/gradle/** @FrozenPandaz @MaxKless @lourw
/packages/gradle/** @FrozenPandaz @MaxKless
/e2e/gradle/** @FrozenPandaz @MaxKless
# Nx-Plugin
/docs/generated/packages/plugin/** @nrwl/nx-devkit-reviewers @nrwl/nx-docs-reviewers
Generated
+134 -43
View File
@@ -1527,30 +1527,26 @@ dependencies = [
"hyper-util",
"log",
"rustls",
"rustls-native-certs",
"rustls-pki-types",
"tokio",
"tokio-rustls",
"tower-service",
"webpki-roots",
]
[[package]]
name = "hyper-util"
version = "0.1.15"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f66d5bd4c6f02bf0542fad85d626775bab9258cf795a4256dcaf3161114d1df"
checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
dependencies = [
"base64",
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"http",
"http-body",
"hyper",
"ipnet",
"libc",
"percent-encoding",
"pin-project-lite",
"socket2",
"tokio",
@@ -1760,16 +1756,6 @@ version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
[[package]]
name = "iri-string"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
dependencies = [
"memchr",
"serde",
]
[[package]]
name = "is-macro"
version = "0.3.5"
@@ -2100,6 +2086,12 @@ dependencies = [
"syn 2.0.100",
]
[[package]]
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@@ -2317,10 +2309,11 @@ dependencies = [
[[package]]
name = "num-bigint"
version = "0.4.6"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
"serde",
@@ -3025,26 +3018,30 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.12.22"
version = "0.12.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531"
checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb"
dependencies = [
"base64",
"bytes",
"futures-core",
"futures-util",
"http",
"http-body",
"http-body-util",
"hyper",
"hyper-rustls",
"hyper-util",
"ipnet",
"js-sys",
"log",
"mime",
"once_cell",
"percent-encoding",
"pin-project-lite",
"quinn",
"rustls",
"rustls-native-certs",
"rustls-pemfile",
"rustls-pki-types",
"serde",
"serde_json",
@@ -3053,12 +3050,13 @@ dependencies = [
"tokio",
"tokio-rustls",
"tower",
"tower-http",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"webpki-roots",
"windows-registry",
]
[[package]]
@@ -3189,6 +3187,15 @@ dependencies = [
"security-framework",
]
[[package]]
name = "rustls-pemfile"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "rustls-pki-types"
version = "1.11.0"
@@ -4086,24 +4093,6 @@ dependencies = [
"tower-service",
]
[[package]]
name = "tower-http"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
dependencies = [
"bitflags 2.9.0",
"bytes",
"futures-util",
"http",
"http-body",
"iri-string",
"pin-project-lite",
"tower",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
@@ -4616,6 +4605,15 @@ dependencies = [
"rustls-pki-types",
]
[[package]]
name = "webpki-roots"
version = "0.26.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "weezl"
version = "0.1.8"
@@ -4689,7 +4687,7 @@ checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
dependencies = [
"windows-implement",
"windows-interface",
"windows-result",
"windows-result 0.1.2",
"windows-targets 0.52.6",
]
@@ -4721,6 +4719,17 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
[[package]]
name = "windows-registry"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
dependencies = [
"windows-result 0.3.2",
"windows-strings",
"windows-targets 0.53.0",
]
[[package]]
name = "windows-result"
version = "0.1.2"
@@ -4730,6 +4739,24 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-result"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
@@ -4805,13 +4832,29 @@ dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
dependencies = [
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",
"windows_i686_gnullvm 0.53.0",
"windows_i686_msvc 0.53.0",
"windows_x86_64_gnu 0.53.0",
"windows_x86_64_gnullvm 0.53.0",
"windows_x86_64_msvc 0.53.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
@@ -4830,6 +4873,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@@ -4848,6 +4897,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@@ -4866,12 +4921,24 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@@ -4890,6 +4957,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@@ -4908,6 +4981,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@@ -4926,6 +5005,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@@ -4944,6 +5029,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]]
name = "winnow"
version = "0.5.40"
+17 -22
View File
@@ -1,8 +1,8 @@
<p style="text-align: center;">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-dark.svg">
<img alt="Nx - Smart Repos · Fast Builds" src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-light.svg" width="100%">
</picture>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-dark.svg">
<img alt="Nx - Smart Repos · Fast Builds" src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-light.svg" width="100%">
</picture>
</p>
<div style="text-align: center;">
@@ -10,7 +10,7 @@
[![CircleCI](https://circleci.com/gh/nrwl/nx.svg?style=svg)](https://circleci.com/gh/nrwl/nx)
[![License](https://img.shields.io/npm/l/nx.svg?style=flat-square)]()
[![NPM Version](https://badge.fury.io/js/nx.svg)](https://www.npmjs.com/package/nx)
[![Semantic Release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic-release-e10079.svg?style=flat-square)]()
[![Semantic Release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)]()
[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
[![Join the chat at https://gitter.im/nrwl-nx/community](https://badges.gitter.im/nrwl-nx/community.svg)](https://gitter.im/nrwl-nx/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Join the Official Nx Discord Server](https://img.shields.io/discord/1143497901675401286?label=discord)](https://go.nx.dev/community)
@@ -21,7 +21,7 @@
# Smart Repos · Fast Builds
Get to green PRs in half the time. Nx optimizes your builds, scales your CI, and fixes failed PRs. Built for developers and AI agents.
An AI-first build platform that connects everything from your editor to CI. Helping you deliver fast, without breaking things.
Create a new Nx workspace with
@@ -47,7 +47,7 @@ Connect your existing Nx workspace with
npx nx connect
```
Learn more in the [Nx CI docs &raquo;](https://nx.dev/ci/getting-started/intro?utm_source=nxrepo&utm_medium=readme&utm_campaign=nxrepo)
Learn more in the [Nx CI docs &raquo;](https://nx.dev/ci/intro?utm_source=nxrepo&utm_medium=readme&utm_campaign=nxrepo)
## Useful links
@@ -77,27 +77,22 @@ help you get started.
| ![Victor Savkin](https://avatars1.githubusercontent.com/u/35996?s=160) | ![Jason Jean](https://avatars2.githubusercontent.com/u/8104246?s=160) | ![Benjamin Cabanes](https://avatars2.githubusercontent.com/u/3447705?s=160) | ![Jack Hsu](https://avatars0.githubusercontent.com/u/53559?s=160) |
| [vsavkin](https://github.com/vsavkin) | [FrozenPandaz](https://github.com/FrozenPandaz) | [bcabanes](https://github.com/bcabanes) | [jaysoo](https://github.com/jaysoo) |
| James Henry | Jon Cammisuli | Max Kless | Juri Strumpflohner |
| James Henry | Jon Cammisuli | Isaac Mann | Juri Strumpflohner |
| ------------------------------------------------------------------------ | ------------------------------------------------------------------------ | -------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| ![James Henry](https://avatars.githubusercontent.com/u/900523?s=160&v=4) | ![Jon Cammisuli](https://avatars2.githubusercontent.com/u/4332460?s=160) | ![Max Kless](https://avatars.githubusercontent.com/u/34165455?s=160) | ![Juri Strumpflohner](https://avatars1.githubusercontent.com/u/542458?s=160) |
| [JamesHenry](https://github.com/JamesHenry) | [cammisuli](https://github.com/cammisuli) | [MaxKless](https://github.com/MaxKless) | [juristr](https://github.com/juristr) |
| ![James Henry](https://avatars.githubusercontent.com/u/900523?s=160&v=4) | ![Jon Cammisuli](https://avatars2.githubusercontent.com/u/4332460?s=160) | ![Isaac Mann](https://avatars1.githubusercontent.com/u/861504?s=160) | ![Juri Strumpflohner](https://avatars1.githubusercontent.com/u/542458?s=160) |
| [JamesHenry](https://github.com/JamesHenry) | [cammisuli](https://github.com/cammisuli) | [isaacplmann](https://github.com/isaacplmann) | [juristr](https://github.com/juristr) |
| Philip Fulcher | Caleb Ukle | Colum Ferry | Steven Nance |
| Philip Fulcher | Caleb Ukle | Colum Ferry | Emily Xiong |
| ------------------------------------------------------------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| ![Philip Fulcher](https://avatars1.githubusercontent.com/u/1536471?s=160) | ![Caleb Ukle](https://avatars.githubusercontent.com/u/23272162?s=160) | ![Colum Ferry](https://avatars.githubusercontent.com/u/12140467?s=160) | ![Steven Nance](https://avatars.githubusercontent.com/u/1036428?s=160) |
| [philipjfulcher](https://github.com/philipjfulcher) | [barbados-clemens](https://github.com/barbados-clemens) | [Coly010](https://github.com/Coly010) | [llwt](https://github.com/llwt) |
| ![Philip Fulcher](https://avatars1.githubusercontent.com/u/1536471?s=160) | ![Caleb Ukle](https://avatars.githubusercontent.com/u/23272162?s=160) | ![Colum Ferry](https://avatars.githubusercontent.com/u/12140467?s=160) | ![Emily Xiong](https://avatars.githubusercontent.com/u/16211801?s=160) |
| [philipjfulcher](https://github.com/philipjfulcher) | [barbados-clemens](https://github.com/barbados-clemens) | [Coly010](https://github.com/Coly010) | [xiongemi](https://github.com/xiongemi) |
| Miroslav Jonaš | Leosvel Pérez Espinosa | Zachary DeRose | Craigory Coppola |
| ----------------------------------------------------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
| ![Miroslav Jonaš](https://avatars.githubusercontent.com/u/881612?s=160) | ![Leosvel Pérez Espinosa](https://avatars.githubusercontent.com/u/12051310?s=160) | ![Zachary DeRose](https://avatars.githubusercontent.com/u/3788405?s=160) | ![Craigory Coppola](https://avatars.githubusercontent.com/u/6933928?s=160) |
| [meeroslav](https://github.com/meeroslav) | [leosvelperez](https://github.com/leosvelperez) | [ZackDeRose](https://github.com/ZackDeRose) | [AgentEnder](https://github.com/AgentEnder) |
| Chau Tran | Nicole Oliver | Rares Matei | Altan Stalker |
| -------------------------------------------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| ![Chau Tran](https://avatars.githubusercontent.com/u/25516557?s=160) | ![Nicole Oliver](https://avatars.githubusercontent.com/u/4440385?s=160) | ![Rares Matei](https://avatars.githubusercontent.com/u/5975076?s=160) | ![Altan Stalker](https://avatars.githubusercontent.com/u/6324206?s=160) |
| [nartc](https://github.com/nartc) | [nixallover](https://github.com/nixallover) | [rarmatei](https://github.com/rarmatei) | [StalkAltan](https://github.com/StalkAltan) |
| Josh VanAllen | Austin Fahsl | Louie Weng |
| ----------------------------------------------------------------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------- |
| ![Josh VanAllen](https://avatars.githubusercontent.com/u/5290334?s=160) | ![Austin Fahsl](https://avatars.githubusercontent.com/u/6913035?s=160) | ![Louie Weng](https://avatars.githubusercontent.com/u/56288712?s=160) |
| [joshvanallen](https://github.com/joshvanallen) | [fahslaj](https://github.com/fahslaj) | [lourw](https://github.com/lourw) |
| Chau Tran | Nicholas Cunningham | Max Kless |
| -------------------------------------------------------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| ![Chau Tran](https://avatars.githubusercontent.com/u/25516557?s=160) | ![Nicholas Cunningham](https://avatars.githubusercontent.com/u/338948?s=160) | ![Max Kless](https://avatars.githubusercontent.com/u/34165455?s=160) |
| [nartc](https://github.com/nartc) | [ndcunningham](https://github.com/ndcunningham) | [MaxKless](https://github.com/MaxKless) |
-15
View File
@@ -1,15 +0,0 @@
# Security Policy
Nx/Nrwl takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations.
If you believe you have found a security vulnerability in any Nx-owned repository that meets Nx's definition of a security vulnerability, please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Security Team at security@nrwl.io.
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message.
Nx follows the principle of Coordinated Vulnerability Disclosure.
+16
View File
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>NxGraphDiff</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" href="/src/styles.css" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+11
View File
@@ -0,0 +1,11 @@
{
"name": "@nx/nx-graph-diff",
"version": "0.0.1",
"private": true,
"dependencies": {
"@monaco-editor/react": "^4.7.0",
"deep-equal": "^2.2.3",
"diff": "^8.0.2",
"monaco-editor": "^0.52.2"
}
}

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

+97
View File
@@ -0,0 +1,97 @@
.app {
min-height: 100vh;
background-color: #f5f5f5;
}
header {
background-color: #002147;
color: white;
padding: 1.5rem 2rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
header h1 {
margin: 0;
font-size: 2rem;
}
header p {
margin: 0.5rem 0 0 0;
opacity: 0.9;
}
header .warning {
background-color: rgba(255, 193, 7, 0.2);
color: #856404;
padding: 0.5rem;
border-radius: 4px;
margin-top: 1rem;
font-size: 0.9rem;
}
.main-content {
display: flex;
gap: 2rem;
padding: 2rem;
height: calc(100vh - 120px);
}
.editor-section {
flex: 1;
background: white;
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
}
.editor-section h2 {
margin-top: 0;
color: #333;
}
.graph-section {
flex: 1;
background: white;
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
overflow: hidden;
}
.graph-controls {
margin-bottom: 1rem;
display: flex;
gap: 1rem;
}
.graph-controls button {
background-color: #002147;
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.2s;
}
.graph-controls button:hover {
background-color: #003366;
}
.graph-controls button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.restore-button {
background-color: #6c757d !important;
}
.restore-button:hover:not(:disabled) {
background-color: #5a6268 !important;
}
+137
View File
@@ -0,0 +1,137 @@
import { useState, useEffect } from 'react';
import ProjectGraph from './components/ProjectGraph';
import NxJsonEditor from './components/NxJsonEditor';
import DiffViewer from './components/DiffViewer';
import './app.module.css';
export function App() {
const [originalGraph, setOriginalGraph] = useState<any>(null);
const [currentGraph, setCurrentGraph] = useState<any>(null);
const [nxJson, setNxJson] = useState<any>(null);
const [showDiff, setShowDiff] = useState(false);
useEffect(() => {
// Load the current project graph
fetch('/.nx/workspace-data/project-graph.json')
.then((res) => res.json())
.then((data) => {
setOriginalGraph(data);
setCurrentGraph(data);
})
.catch((err) => console.error('Failed to load project graph:', err));
// Load nx.json
fetch('/nx.json')
.then((res) => res.json())
.then((data) => setNxJson(data))
.catch((err) => console.error('Failed to load nx.json:', err));
}, []);
const handleNxJsonUpdate = async (updatedNxJson: any) => {
try {
const response = await fetch('/api/update-nx-json', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ nxJson: updatedNxJson }),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
if (result.success) {
setCurrentGraph(result.graph);
setNxJson(updatedNxJson);
setShowDiff(true);
} else {
console.error('Failed to update graph:', result.error);
alert('Failed to update graph: ' + result.error);
}
} catch (error) {
console.error('Error updating nx.json:', error);
alert('Error updating nx.json: ' + (error as Error).message);
}
};
const handleRestoreOriginal = async () => {
try {
const response = await fetch('/api/restore-nx-json', {
method: 'POST',
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
if (result.success) {
// Reload the original data
window.location.reload();
} else {
console.error('Failed to restore original:', result.error);
alert('Failed to restore original: ' + result.error);
}
} catch (error) {
console.error('Error restoring original:', error);
alert('Error restoring original: ' + (error as Error).message);
}
};
return (
<div className="app">
<header>
<h1>Nx Graph Diff Viewer</h1>
<p>Visualize how changes to nx.json affect your project graph</p>
<p className="warning">
This tool modifies your actual nx.json file and regenerates the
project graph. Use with caution!
</p>
</header>
<div className="main-content">
<div className="editor-section">
<h2>nx.json Editor</h2>
{nxJson && (
<NxJsonEditor nxJson={nxJson} onUpdate={handleNxJsonUpdate} />
)}
</div>
<div className="graph-section">
<div className="graph-controls">
<button
onClick={() => setShowDiff(!showDiff)}
disabled={!currentGraph || currentGraph === originalGraph}
>
{showDiff ? 'Hide Diff' : 'Show Diff'}
</button>
<button
onClick={handleRestoreOriginal}
className="restore-button"
disabled={currentGraph === originalGraph}
>
Restore Original
</button>
</div>
{originalGraph &&
currentGraph &&
(showDiff ? (
<DiffViewer
originalGraph={originalGraph}
currentGraph={currentGraph}
/>
) : (
<ProjectGraph graph={currentGraph} />
))}
</div>
</div>
</div>
);
}
export default App;
@@ -0,0 +1,177 @@
.diff-viewer {
height: 100%;
overflow-y: auto;
}
.diff-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.diff-header h3 {
margin: 0;
color: #333;
}
.toggle-detailed {
background-color: #6c757d;
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.2s;
}
.toggle-detailed:hover {
background-color: #5a6268;
}
.no-changes {
color: #666;
font-style: italic;
text-align: center;
padding: 2rem;
}
.changes-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.project-changes {
border: 1px solid #e0e0e0;
border-radius: 6px;
padding: 1rem;
background: #fafafa;
}
.project-changes h4 {
margin: 0 0 0.75rem 0;
color: #002147;
font-size: 1.1rem;
}
.change-items {
list-style: none;
margin: 0;
padding: 0;
}
.change-item {
padding: 0.5rem;
margin: 0.25rem 0;
border-radius: 4px;
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 14px;
display: flex;
align-items: center;
gap: 0.5rem;
}
.change-item.added {
background-color: #d4edda;
border-left: 4px solid #28a745;
}
.change-item.removed {
background-color: #f8d7da;
border-left: 4px solid #dc3545;
}
.change-item.modified {
background-color: #fff3cd;
border-left: 4px solid #ffc107;
}
.change-type {
font-weight: bold;
width: 20px;
}
.change-item.added .change-type {
color: #28a745;
}
.change-item.removed .change-type {
color: #dc3545;
}
.change-item.modified .change-type {
color: #856404;
}
.change-details {
flex: 1;
color: #333;
}
.change-item.detailed {
flex-direction: column;
align-items: flex-start;
}
.change-summary {
display: flex;
align-items: center;
gap: 0.5rem;
width: 100%;
}
.change-diff {
margin-top: 1rem;
width: 100%;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.diff-section h6 {
margin: 0 0 0.5rem 0;
font-size: 0.85rem;
color: #666;
font-weight: 600;
}
.value-display {
background-color: #f8f9fa;
padding: 0.75rem;
border-radius: 4px;
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 0.8rem;
overflow-x: auto;
white-space: pre-wrap;
border: 1px solid #dee2e6;
}
.value-display.original {
border-left: 4px solid #dc3545;
background-color: #f8d7da;
}
.value-display.current {
border-left: 4px solid #28a745;
background-color: #d4edda;
}
.array-value {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.array-item {
background-color: rgba(255, 255, 255, 0.8);
padding: 0.25rem 0.5rem;
border-radius: 3px;
border: 1px solid #dee2e6;
}
.value-display em {
color: #6c757d;
font-style: italic;
}
@@ -0,0 +1,261 @@
import React, { useMemo, useState } from 'react';
import deepEqual from 'deep-equal';
import './DiffViewer.css';
interface DiffViewerProps {
originalGraph: any;
currentGraph: any;
}
interface Change {
type: 'added' | 'removed' | 'modified';
projectName: string;
targetName?: string;
details: string;
originalValue?: any;
currentValue?: any;
property?: string;
}
const DiffViewer: React.FC<DiffViewerProps> = ({
originalGraph,
currentGraph,
}) => {
const [showDetailedDiff, setShowDetailedDiff] = useState(true);
const changes = useMemo(() => {
const changesList: Change[] = [];
// Compare projects
const originalProjects =
originalGraph?.graph?.nodes || originalGraph?.nodes || {};
const currentProjects =
currentGraph?.graph?.nodes || currentGraph?.nodes || {};
// Check for removed projects
Object.keys(originalProjects).forEach((projectName) => {
if (!currentProjects[projectName]) {
changesList.push({
type: 'removed',
projectName,
details: 'Project removed',
});
}
});
// Check for added projects and modified projects
Object.keys(currentProjects).forEach((projectName) => {
if (!originalProjects[projectName]) {
changesList.push({
type: 'added',
projectName,
details: 'Project added',
});
} else {
// Check for modified targets
const originalTargets =
originalProjects[projectName].data.targets || {};
const currentTargets = currentProjects[projectName].data.targets || {};
// Check for removed targets
Object.keys(originalTargets).forEach((targetName) => {
if (!currentTargets[targetName]) {
changesList.push({
type: 'removed',
projectName,
targetName,
details: `Target "${targetName}" removed`,
});
}
});
// Check for added or modified targets
Object.keys(currentTargets).forEach((targetName) => {
if (!originalTargets[targetName]) {
changesList.push({
type: 'added',
projectName,
targetName,
details: `Target "${targetName}" added`,
});
} else if (
!deepEqual(originalTargets[targetName], currentTargets[targetName])
) {
const changes = [];
// Check specific changes and create detailed change entries
const propertiesToCheck = [
{ key: 'dependsOn', label: 'dependencies' },
{ key: 'inputs', label: 'inputs' },
{ key: 'outputs', label: 'outputs' },
{ key: 'cache', label: 'cache settings' },
{ key: 'options', label: 'options' },
{ key: 'executor', label: 'executor' },
];
const changedProperties: string[] = [];
propertiesToCheck.forEach(({ key, label }) => {
const originalValue = originalTargets[targetName][key];
const currentValue = currentTargets[targetName][key];
if (!deepEqual(originalValue, currentValue)) {
changedProperties.push(label);
// Create detailed change entry
changesList.push({
type: 'modified',
projectName,
targetName,
property: key,
details: `Target "${targetName}" ${label} changed`,
originalValue,
currentValue,
});
}
});
// Create summary entry if there are changes
if (changedProperties.length > 0) {
changesList.push({
type: 'modified',
projectName,
targetName,
details: `Target "${targetName}" modified: ${changedProperties.join(
', '
)}`,
});
}
}
});
}
});
return changesList;
}, [originalGraph, currentGraph]);
const groupedChanges = useMemo(() => {
const grouped: { [key: string]: Change[] } = {};
changes.forEach((change) => {
if (!grouped[change.projectName]) {
grouped[change.projectName] = [];
}
grouped[change.projectName].push(change);
});
return grouped;
}, [changes]);
// Filter changes based on detailed view setting
const displayChanges = useMemo(() => {
if (showDetailedDiff) {
return changes.filter((change) => change.property); // Only detailed changes
} else {
return changes.filter((change) => !change.property); // Only summary changes
}
}, [changes, showDetailedDiff]);
const groupedDisplayChanges = useMemo(() => {
const grouped: { [key: string]: Change[] } = {};
displayChanges.forEach((change) => {
if (!grouped[change.projectName]) {
grouped[change.projectName] = [];
}
grouped[change.projectName].push(change);
});
return grouped;
}, [displayChanges]);
const renderValue = (value: any) => {
if (Array.isArray(value)) {
return (
<div className="array-value">
{value.map((item, index) => (
<div key={index} className="array-item">
{typeof item === 'string' ? item : JSON.stringify(item, null, 2)}
</div>
))}
</div>
);
}
return typeof value === 'object'
? JSON.stringify(value, null, 2)
: String(value);
};
return (
<div className="diff-viewer">
<div className="diff-header">
<h3>Changes ({changes.filter((c) => !c.property).length})</h3>
<button
className="toggle-detailed"
onClick={() => setShowDetailedDiff(!showDetailedDiff)}
>
{showDetailedDiff ? 'Show Summary' : 'Show Detailed'}
</button>
</div>
{changes.length === 0 ? (
<p className="no-changes">No changes detected</p>
) : (
<div className="changes-list">
{Object.entries(groupedDisplayChanges).map(
([projectName, projectChanges]) => (
<div key={projectName} className="project-changes">
<h4>{projectName}</h4>
<ul className="change-items">
{projectChanges.map((change, index) => (
<li
key={index}
className={`change-item ${change.type} ${
showDetailedDiff ? 'detailed' : ''
}`}
>
<div className="change-summary">
<span className="change-type">
{change.type === 'added' && '+ '}
{change.type === 'removed' && '- '}
{change.type === 'modified' && '~ '}
</span>
<span className="change-details">{change.details}</span>
</div>
{showDetailedDiff && change.property && (
<div className="change-diff">
<div className="diff-section">
<h6>Before:</h6>
<div className="value-display original">
{change.originalValue ? (
renderValue(change.originalValue)
) : (
<em>undefined</em>
)}
</div>
</div>
<div className="diff-section">
<h6>After:</h6>
<div className="value-display current">
{change.currentValue ? (
renderValue(change.currentValue)
) : (
<em>undefined</em>
)}
</div>
</div>
</div>
)}
</li>
))}
</ul>
</div>
)
)}
</div>
)}
</div>
);
};
export default DiffViewer;
@@ -0,0 +1,64 @@
.nx-json-editor {
display: flex;
flex-direction: column;
height: 100%;
}
.editor-controls {
margin-bottom: 1rem;
display: flex;
align-items: center;
gap: 1rem;
}
.apply-button {
background-color: #28a745;
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: background-color 0.2s;
}
.apply-button:hover {
background-color: #218838;
}
.error-message {
color: #dc3545;
font-size: 14px;
}
.updating-message {
color: #007bff;
font-size: 14px;
font-style: italic;
}
.editor-hints {
margin-top: 1rem;
padding: 1rem;
background-color: #f8f9fa;
border-radius: 4px;
border: 1px solid #e9ecef;
}
.editor-hints h4 {
margin: 0 0 0.5rem 0;
color: #495057;
font-size: 14px;
}
.editor-hints ul {
margin: 0;
padding-left: 1.5rem;
}
.editor-hints li {
margin: 0.25rem 0;
font-size: 13px;
color: #6c757d;
}
@@ -0,0 +1,85 @@
import React, { useState, useCallback } from 'react';
import Editor from '@monaco-editor/react';
import './NxJsonEditor.css';
interface NxJsonEditorProps {
nxJson: any;
onUpdate: (updatedNxJson: any) => void;
}
const NxJsonEditor: React.FC<NxJsonEditorProps> = ({ nxJson, onUpdate }) => {
const [editorValue, setEditorValue] = useState(
JSON.stringify(nxJson, null, 2)
);
const [error, setError] = useState<string | null>(null);
const [isUpdating, setIsUpdating] = useState(false);
const handleEditorChange = useCallback((value: string | undefined) => {
if (value) {
setEditorValue(value);
setError(null);
}
}, []);
const handleApplyChanges = useCallback(async () => {
try {
setIsUpdating(true);
setError(null);
const parsed = JSON.parse(editorValue);
await onUpdate(parsed);
} catch (e) {
setError('Invalid JSON: ' + (e as Error).message);
} finally {
setIsUpdating(false);
}
}, [editorValue, onUpdate]);
return (
<div className="nx-json-editor">
<div className="editor-controls">
<button
onClick={handleApplyChanges}
className="apply-button"
disabled={isUpdating}
>
{isUpdating ? 'Updating Graph...' : 'Apply Changes'}
</button>
{error && <span className="error-message">{error}</span>}
{isUpdating && (
<span className="updating-message">
Regenerating project graph...
</span>
)}
</div>
<Editor
height="600px"
defaultLanguage="json"
value={editorValue}
onChange={handleEditorChange}
theme="vs-dark"
options={{
minimap: { enabled: false },
fontSize: 14,
formatOnPaste: true,
formatOnType: true,
automaticLayout: true,
}}
/>
<div className="editor-hints">
<h4>Quick Examples:</h4>
<ul>
<li>Add a new target default: Add an entry to "targetDefaults"</li>
<li>
Modify build dependencies: Update "targetDefaults.build.dependsOn"
</li>
<li>Change cache settings: Update "targetDefaults.[target].cache"</li>
<li>Add inputs: Modify "targetDefaults.[target].inputs"</li>
</ul>
</div>
</div>
);
};
export default NxJsonEditor;
@@ -0,0 +1,149 @@
.project-graph {
height: 100%;
overflow-y: auto;
}
.project-graph h3 {
margin-top: 0;
color: #333;
}
.projects-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));
gap: 1rem;
}
.project-card {
border: 1px solid #e0e0e0;
border-radius: 6px;
padding: 1rem;
background: #fafafa;
transition: box-shadow 0.2s;
}
.project-card:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.project-card h4 {
margin: 0 0 0.5rem 0;
color: #002147;
font-size: 1.1rem;
}
.project-info {
margin-bottom: 1rem;
}
.project-info p {
margin: 0.25rem 0;
font-size: 0.9rem;
color: #666;
}
.project-info strong {
color: #333;
}
.targets {
margin-top: 0.5rem;
}
.targets h5 {
margin: 0 0 0.5rem 0;
font-size: 1rem;
color: #444;
}
.targets ul {
margin: 0;
padding-left: 1.5rem;
}
.target-item {
margin: 0.5rem 0;
padding: 0.75rem;
border: 1px solid #e9ecef;
border-radius: 4px;
background-color: #fff;
}
.target-header {
display: flex;
align-items: center;
margin-bottom: 0.5rem;
font-size: 0.9rem;
}
.target-header strong {
color: #495057;
}
.executor {
color: #666;
font-size: 0.85rem;
}
.target-details {
margin-left: 0.5rem;
}
.target-property {
margin: 0.4rem 0;
font-size: 0.85rem;
}
.property-label {
color: #6c757d;
font-weight: 500;
margin-right: 0.5rem;
display: inline-block;
min-width: 80px;
}
.property-value {
color: #495057;
}
.property-list {
margin-top: 0.25rem;
margin-left: 80px;
}
.input-item,
.output-item {
background-color: #f8f9fa;
padding: 0.25rem 0.5rem;
margin: 0.2rem 0;
border-radius: 3px;
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 0.8rem;
border-left: 3px solid #dee2e6;
word-break: break-all;
}
.input-item {
border-left-color: #007bff;
}
.output-item {
border-left-color: #28a745;
}
.cache-value {
font-weight: 500;
padding: 0.2rem 0.5rem;
border-radius: 3px;
font-size: 0.8rem;
}
.cache-value.enabled {
background-color: #d4edda;
color: #155724;
}
.cache-value.disabled {
background-color: #f8d7da;
color: #721c24;
}
@@ -0,0 +1,121 @@
import React from 'react';
import './ProjectGraph.css';
interface ProjectGraphProps {
graph: any;
}
const ProjectGraph: React.FC<ProjectGraphProps> = ({ graph }) => {
const projects = Object.entries(graph?.graph?.nodes || graph?.nodes || {});
return (
<div className="project-graph">
<h3>Projects ({projects.length})</h3>
<div className="projects-list">
{projects.map(([name, project]: [string, any]) => (
<div key={name} className="project-card">
<h4>{name}</h4>
<div className="project-info">
<p>
<strong>Type:</strong> {project.type}
</p>
<p>
<strong>Root:</strong> {project.data.root}
</p>
{project.data.tags && project.data.tags.length > 0 && (
<p>
<strong>Tags:</strong> {project.data.tags.join(', ')}
</p>
)}
</div>
{project.data.targets &&
Object.keys(project.data.targets).length > 0 && (
<div className="targets">
<h5>Targets:</h5>
<ul>
{Object.entries(project.data.targets).map(
([targetName, target]: [string, any]) => (
<li key={targetName} className="target-item">
<div className="target-header">
<strong>{targetName}</strong>
{target.executor && (
<span className="executor">
{' '}
({target.executor})
</span>
)}
</div>
<div className="target-details">
{target.dependsOn &&
target.dependsOn.length > 0 && (
<div className="target-property">
<span className="property-label">
Depends on:
</span>
<span className="property-value">
{target.dependsOn.join(', ')}
</span>
</div>
)}
{target.inputs && target.inputs.length > 0 && (
<div className="target-property">
<span className="property-label">Inputs:</span>
<div className="property-list">
{target.inputs.map(
(input: any, index: number) => (
<div key={index} className="input-item">
{typeof input === 'string'
? input
: JSON.stringify(input, null, 2)}
</div>
)
)}
</div>
</div>
)}
{target.outputs && target.outputs.length > 0 && (
<div className="target-property">
<span className="property-label">Outputs:</span>
<div className="property-list">
{target.outputs.map(
(output: string, index: number) => (
<div key={index} className="output-item">
{output}
</div>
)
)}
</div>
</div>
)}
{target.cache !== undefined && (
<div className="target-property">
<span className="property-label">Cache:</span>
<span
className={`cache-value ${
target.cache ? 'enabled' : 'disabled'
}`}
>
{target.cache ? 'enabled' : 'disabled'}
</span>
</div>
)}
</div>
</li>
)
)}
</ul>
</div>
)}
</div>
))}
</div>
</div>
);
};
export default ProjectGraph;
+13
View File
@@ -0,0 +1,13 @@
import { StrictMode } from 'react';
import * as ReactDOM from 'react-dom/client';
import App from './app/app';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<StrictMode>
<App />
</StrictMode>
);
+51
View File
@@ -0,0 +1,51 @@
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
padding: 0;
}
button {
font-family: inherit;
}
/* Scrollbar styles */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
background: #888;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
+31
View File
@@ -0,0 +1,31 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo",
"jsx": "react-jsx",
"lib": ["dom"],
"types": [
"node",
"@nx/react/typings/cssmodule.d.ts",
"@nx/react/typings/image.d.ts",
"vite/client"
],
"rootDir": "src",
"module": "esnext",
"moduleResolution": "bundler"
},
"exclude": [
"out-tsc",
"dist",
"src/**/*.spec.ts",
"src/**/*.test.ts",
"src/**/*.spec.tsx",
"src/**/*.test.tsx",
"src/**/*.spec.js",
"src/**/*.test.js",
"src/**/*.spec.jsx",
"src/**/*.test.jsx"
],
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
}
+10
View File
@@ -0,0 +1,10 @@
{
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
}
],
"extends": "../../tsconfig.base.json"
}
+244
View File
@@ -0,0 +1,244 @@
/// <reference types='vitest' />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { readFileSync, writeFileSync } from 'fs';
import { join } from 'path';
import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
export default defineConfig(() => ({
root: __dirname,
cacheDir: '../../node_modules/.vite/apps/nx-graph-diff',
server: {
port: 4200,
host: 'localhost',
middlewareMode: false,
},
plugins: [
react(),
{
name: 'nx-json-middleware',
configureServer(server) {
server.middlewares.use('/nx.json', (req, res, next) => {
if (req.method === 'GET') {
const nxJsonPath = join(__dirname, '../../nx.json');
try {
// Clear the require cache to ensure fresh content
delete require.cache[nxJsonPath];
// Read fresh content from disk
const content = readFileSync(nxJsonPath, 'utf-8');
// Set headers to prevent caching
res.setHeader('Content-Type', 'application/json');
res.setHeader(
'Cache-Control',
'no-cache, no-store, must-revalidate'
);
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
console.log('Serving fresh nx.json, length:', content.length);
res.end(content);
} catch (err) {
console.error('Error reading nx.json:', err);
res.statusCode = 404;
res.end(JSON.stringify({ error: 'nx.json not found' }));
}
} else {
next();
}
});
server.middlewares.use(
'/.nx/workspace-data/project-graph.json',
(req, res, next) => {
if (req.method === 'GET') {
const graphPath = join(
__dirname,
'../../.nx/workspace-data/project-graph.json'
);
try {
// Read fresh content from disk
const content = readFileSync(graphPath, 'utf-8');
// Set headers to prevent caching
res.setHeader('Content-Type', 'application/json');
res.setHeader(
'Cache-Control',
'no-cache, no-store, must-revalidate'
);
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
console.log(
'Serving fresh project-graph.json, length:',
content.length
);
res.end(content);
} catch (err) {
console.error('Error reading project-graph.json:', err);
res.statusCode = 404;
res.end(
JSON.stringify({ error: 'project-graph.json not found' })
);
}
} else {
next();
}
}
);
server.middlewares.use(
'/api/update-nx-json',
async (req, res, next) => {
if (req.method === 'POST') {
let body = '';
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', async () => {
try {
const { nxJson } = JSON.parse(body);
// Save the original nx.json as backup
const nxJsonPath = join(__dirname, '../../nx.json');
const backupPath = join(__dirname, '../../nx.json.backup');
const originalContent = readFileSync(nxJsonPath, 'utf-8');
writeFileSync(backupPath, originalContent);
// Write the new nx.json
writeFileSync(nxJsonPath, JSON.stringify(nxJson, null, 2));
// Regenerate project graph
console.log('Regenerating project graph...');
const { stdout, stderr } = await execAsync(
'pnpm nx graph --file=.nx/workspace-data/project-graph.json',
{
cwd: join(__dirname, '../..'),
}
);
console.log('Graph generation stdout:', stdout);
if (stderr) {
console.log('Graph generation stderr:', stderr);
}
// Wait a moment for file system to settle
await new Promise((resolve) => setTimeout(resolve, 1000));
// Read the new project graph
const graphPath = join(
__dirname,
'../../.nx/workspace-data/project-graph.json'
);
console.log('Reading graph from:', graphPath);
if (!require('fs').existsSync(graphPath)) {
throw new Error(
`Project graph file does not exist at ${graphPath}`
);
}
const graphContent = readFileSync(graphPath, 'utf-8');
console.log('Graph content length:', graphContent.length);
const newGraph = JSON.parse(graphContent);
console.log(
'New graph nodes count:',
Object.keys(newGraph.nodes || {}).length
);
res.setHeader('Content-Type', 'application/json');
res.end(
JSON.stringify({
success: true,
graph: newGraph,
})
);
} catch (err) {
console.error('Error updating nx.json:', err);
res.statusCode = 500;
res.end(
JSON.stringify({
error: 'Failed to update nx.json and regenerate graph',
details: err.message,
})
);
}
});
} else {
res.statusCode = 405;
res.end(JSON.stringify({ error: 'Method not allowed' }));
}
}
);
server.middlewares.use(
'/api/restore-nx-json',
async (req, res, next) => {
if (req.method === 'POST') {
try {
const nxJsonPath = join(__dirname, '../../nx.json');
const backupPath = join(__dirname, '../../nx.json.backup');
// Restore original nx.json
const originalContent = readFileSync(backupPath, 'utf-8');
writeFileSync(nxJsonPath, originalContent);
// Regenerate project graph
console.log('Restoring project graph...');
const { stdout, stderr } = await execAsync(
'pnpm nx graph --file=.nx/workspace-data/project-graph.json',
{
cwd: join(__dirname, '../..'),
}
);
console.log('Restore stdout:', stdout);
if (stderr) {
console.log('Restore stderr:', stderr);
}
// Wait a moment for file system to settle
await new Promise((resolve) => setTimeout(resolve, 1000));
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ success: true }));
} catch (err) {
console.error('Error restoring nx.json:', err);
res.statusCode = 500;
res.end(
JSON.stringify({
error: 'Failed to restore nx.json',
details: err.message,
})
);
}
} else {
res.statusCode = 405;
res.end(JSON.stringify({ error: 'Method not allowed' }));
}
}
);
},
},
],
preview: {
port: 4200,
host: 'localhost',
},
// Uncomment this if you are using workers.
// worker: {
// plugins: [ nxViteTsPaths() ],
// },
build: {
outDir: './dist',
emptyOutDir: true,
reportCompressedSize: true,
commonjsOptions: {
transformMixedEsModules: true,
},
},
}));
-6
View File
@@ -1,6 +0,0 @@
node_modules/
dist/
.astro/
.netlify/
test-output/
playwright-report/
-22
View File
@@ -1,22 +0,0 @@
{
"extends": ["plugin:playwright/recommended", "../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
},
{
"files": ["e2e/**/*.{ts,js,tsx,jsx}"],
"rules": {}
}
]
}
+35 -216
View File
@@ -1,235 +1,54 @@
# Nx Documentation Site
# Starlight Starter Kit: Basics
[![Built with Starlight](https://astro.badg.es/v2/built-with-starlight/tiny.svg)](https://starlight.astro.build)
The Nx documentation site built with Astro and Starlight, featuring advanced content management through Markdoc and dynamic plugin documentation generation.
```
pnpm create astro@latest -- --template starlight
```
## Architecture Overview
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/starlight/tree/main/examples/basics)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/starlight/tree/main/examples/basics)
[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/withastro/starlight&create_from_path=examples/basics)
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fwithastro%2Fstarlight%2Ftree%2Fmain%2Fexamples%2Fbasics&project-name=my-starlight-docs&repository-name=my-starlight-docs)
This documentation site leverages Astro's static site generation capabilities with Starlight for documentation-specific features. The architecture consists of:
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
### Core Technologies
## 🚀 Project Structure
- [**Astro**](https://docs.astro.build) - Static site generator with island architecture
- [**Starlight**](https://starlight.astro.build) - Documentation theme with built-in navigation, search, and i18n
- **React** - For implementing UI components
- **Netlify** - Deployment and hosting
### Key Features
- [Markdoc](https://markdoc.dev) with custom tags for rich content such as videos, graphs, etc.
- TailwindCSS for styling in Astro and React components
- Dynamic API documentation generation from Nx packages and CLI commands
- Community plugin registry
## Project Structure
Inside of your Astro + Starlight project, you'll see the following folders and files:
```
astro-docs/
.
├── public/
├── src/
│ ├── assets/ # Images and static assets to be optimized by Astro
│ ├── nx/ # Nx branding assets
│ │ ├── nx-cloud/ # Nx Cloud assets
│ └── nx-console/ # Nx Console assets
│ ├── components/ # React and Astro components
│ │ ├── layout/ # Layout components (e.g. Sidebar)
│ │ ├── markdoc/ # Markdoc tag components
│ │ └── utils/ # Utility functions
│ ├── content/ # Documentation content
│ │ ├── docs/ # Main documentation files (.mdoc, .mdx)
│ │ ├── approved-community-plugins.json # Powers plugin registry
│ │ └── notifications.json # Notifications banners for docs site
│ ├── pages/ # Dynamic pages and routes (e.g. devkit)
│ ├── plugins/ # Content loaders and plugins
│ │ ├── *.loader.ts # Dynamic content loaders (e.g. CLI commands and API docs generation)
│ │ └── utils/ # Plugin utilities
│ └── styles/ # Global styles
├── public/ # Static assets not to be optimized by Astro (fonts, robots.txt)
├── astro.config.mjs # Astro configuration
├── markdoc.config.mjs # Markdoc tags configuration
├── sidebar.mts # Sidebar structure definition
└── package.json
│ ├── assets/
│ ├── content/
│ │ ├── docs/
│ └── content.config.ts
├── astro.config.mjs
├── package.json
└── tsconfig.json
```
## Plugins and Loaders
Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name.
### Content Loaders
Images can be added to `src/assets/` and embedded in Markdown with a relative link.
The site uses custom content loaders to dynamically generate documentation:
Static assets, like favicons, can be placed in the `public/` directory.
- **PluginLoader** (`plugin.loader.ts`) - Generates official plugin documentation (generators, executors, migrations)
- **CommunityPluginsLoader** (`community-plugins.loader.ts`) - Generates data for plugin registry (e.g. GitHub stars, npm downloads)
- **NxReferencePackagesLoader** (`nx-reference-packages.loader.ts`) - Generated data for CNW, Devkit, nx cli (e.g. nx core related things)
## 🧞 Commands
## Content Management
All commands are run from the root of the project, from a terminal:
### Content Types
| Command | Action |
| :--------------------- | :----------------------------------------------- |
| `pnpm install` | Installs dependencies |
| `pnpm dev` | Starts local dev server at `localhost:4321` |
| `pnpm build` | Build your production site to `./dist/` |
| `pnpm preview` | Preview your build locally, before deploying |
| `pnpm astro ...` | Run CLI commands like `astro add`, `astro check` |
| `pnpm astro -- --help` | Get help using the Astro CLI |
1. **Regular Documentation** (`src/content/docs/`)
## 👀 Want to learn more?
- Written in `.mdoc` (Markdoc) or `.mdx` (MDX) format
- Organized by sections: getting-started, concepts, guides, api
- File-based routing (filename = URL path)
2. **Dynamic Plugin Documentation**
- Auto-generated from Nx packages
- Includes generators, executors, and migrations
- Updated during build process
- **Note**: Requires a rebuild and restart to reflect changes
3. **CLI Documentation**
- Auto-generated from Nx CLI commands
- Parsed from actual CLI implementation
- **Note**: Requires a rebuild and restart to reflect changes
### Markdoc Tags
The site includes custom Markdoc tags for rich content.
**Note**: Starlight supports many Markdown and Markdoc features, such as code blocks, asides, etc.
- https://starlight.astro.build/components/using-components/#using-a-component-in-markdoc
- https://starlight.astro.build/guides/authoring-content
#### Layout & Organization
- `{% aside %}` - Highlighted information boxes
- `{% cardgrid %}`, `{% card|linkcard %}` - Card layouts
- `{% tabs %}`, `{% tabitem label="some-label" %}` - Tab layouts
- Use the `syncKey` so tabs are auto switched to the users preference if it makes sense.
- e.g. `{% tabs syncKey="package-manager" %}`
#### Interactive Components
- `{% graph %}` - Interactive project/task graph visualization
- `{% project_details %}` - Project configuration viewer
#### Media & Embeds
- `{% youtube %}` - YouTube video embeds
- `{% video_player %}` - Custom video player
- `{% iframe %}` - Generic iframe embeds
#### Developer Tools
- `{% github_repository %}` - GitHub repo cards
- `{% stackblitz_button %}` - StackBlitz demo launcher
- `{% install_nx_console %}` - IDE extension installer
#### Content Enhancement
- `{% badge %}` - Status/label pills
- `{% metrics %}` - Metrics display
- `{% testimonial %}` - Customer testimonials
## Development Workflow
### Getting Started
```bash
# Install dependencies and link workspace packages
# This will build Nx packages as well for API docs
nx serve astro-docs
# Or run astro dev directly
# This will not build Nx packages
cd astro-docs
npx astro dev
# Custom ports (useful for AI agents with git worktrees)
npx astro dev --port 3000
```
### Adding New Content
#### Regular Documentation
1. Create `.mdoc` file in `src/content/docs/`
2. Add frontmatter with title and description
3. Use Markdoc tags for rich content
4. File location determines URL structure
Example:
```markdown
---
title: 'My New Guide'
description: 'Learn how to use this feature'
---
# Introduction
{% aside type="note" title="Important" %}
This is a note about the feature.
{% /aside %}
```
#### Adding Custom Markdoc Tags
1. Create Astro component in `src/components/markdoc/`
2. (Optional) Create React component for more complex components, or ones that need to be shared with blog or non-docs pages
3. Register in `markdoc.config.mjs`
4. Define attributes and validation
### Updating Plugin Documentation
Plugin documentation is auto-generated during build. To update:
1. Make changes to the plugin's schema/implementation
2. Run the build process
3. The loader will automatically fetch and generate updated docs
### Sidebar Management
The sidebar structure is defined in `sidebar.mts`. To add new sections:
```javascript
export const sidebar = [
{
label: 'Section Name',
items: [
{
label: 'Page Title',
link: 'path/to/page',
},
// Nested sections
{
label: 'Subsection',
collapsed: true,
items: [...]
}
]
}
];
```
> Note there is a special case for sidebar items appearing in the sidebar. Such as the `Reference` section which is handled via the `[sidebar-reference-updater](./src/plugins/sidebar-reference-updater.middleware.ts)` middleware.
## Styling and Theming
- Uses Tailwind CSS v4 with Vite plugin
- Global styles in `src/styles/global.css`
- Component-specific styles use Tailwind utilities
- Dark/light mode support built into Starlight and customized in `global.css`
## Configuration Files
### `astro.config.mjs`
- Site configuration
- Integration setup (React, Markdoc, Starlight)
- Vite plugins
- Build options
### `markdoc.config.mjs`
- Custom tag definitions
- Attribute validation
- Component mappings
### `sidebar.mts`
- Navigation structure
- Section organization
- Dynamic content injection points
Check out [Starlights docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).
+46 -78
View File
@@ -1,94 +1,35 @@
// @ts-check
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import { sectionSidebarPlugin } from './src/plugins/section-sidebar.plugin';
import netlify from '@astrojs/netlify';
import linkValidator from 'starlight-links-validator';
import react from '@astrojs/react';
import markdoc from '@astrojs/markdoc';
import tailwindcss from '@tailwindcss/vite';
import { sidebar } from './sidebar.mts';
const BASE = '/docs';
const PUBLIC_CONFIG = {
cookiebotDisabled: process.env.COOKIEBOT_DISABLED === 'true',
cookiebotId: process.env.COOKIEBOT_ID ?? null,
gaMeasurementId: 'UA-88380372-10',
gtmMeasurementId: 'GTM-KW8423B6',
isProd: process.env.NODE_ENV === 'production',
};
// https://astro.build/config
export default defineConfig({
base: BASE,
vite: { plugins: [tailwindcss()] },
// Allow this to be configured per environment
// Note: this happens during build time so we don't use `import.meta.env`
site: process.env.NX_DEV_URL ?? 'https://nx.dev',
image: {
service: {
entrypoint: 'astro/assets/services/sharp',
config: {
limitInputPixels: false, // Disable pixel limit
},
},
},
trailingSlash: 'never',
// This adapter doesn't support local previews, so only load it on Netlify.
adapter: process.env['NETLIFY'] ? netlify() : undefined,
site: 'https://docs.nx.dev',
adapter: netlify(),
integrations: [
markdoc(),
// https://starlight.astro.build/reference/configuration/
starlight({
title: 'Nx',
tagline:
'Get to green PRs in half the time. Nx optimizes your builds, scales your CI, and fixes failed PRs. Built for developers and AI agents.',
'An AI-first build platform that connects everything from your editor to CI. Helping you deliver fast, without breaking things.',
customCss: ['./src/styles/global.css'],
favicon: '/favicon.svg',
logo: {
light: './src/assets/nx/Nx-dark.png',
dark: './src/assets/nx/Nx-light.png',
src: './src/assets/nx/Nx-light.png',
replacesTitle: true,
},
head: [
{
tag: 'script',
content: `window.__CONFIG = ${JSON.stringify(PUBLIC_CONFIG)};`,
},
...(process.env.COOKIEBOT_ID &&
process.env.COOKIEBOT_DISABLED !== 'true'
? [
{
/** @type {"script"} */
tag: 'script',
attrs: {
id: 'Cookiebot',
src: 'https://consent.cookiebot.com/uc.js',
'data-cbid': process.env.COOKIEBOT_ID,
'data-blockingmode': 'auto',
type: 'text/javascript',
},
},
]
: []),
{
tag: 'script',
attrs: {
src: `${BASE}/global-scripts.js`,
defer: true,
},
},
],
plugins: [],
routeMiddleware: [
'./src/plugins/banner.middleware.ts',
// NOTE: this is responsibile for populating the Reference section
// with generated routes from the nx-reference-packages content collection
// since the sidebar doesn't auto generate w/ dynamic routes from src/pages/reference
// only the src/content/docs/reference files
'./src/plugins/sidebar-reference-updater.middleware.ts',
'./src/plugins/sidebar-icons.middleware.ts',
'./src/plugins/og.middleware.ts',
plugins: [
// linkValidator(),
sectionSidebarPlugin(),
],
routeMiddleware: ['./src/plugins/banner.middleware.ts'],
markdown: {
// this breaks the renderMarkdown function in the plugin loader due to starlight path normalization
// as to _why_ it has to normalize a path?
@@ -116,15 +57,42 @@ export default defineConfig({
editLink: {
baseUrl: 'https://github.com/nrwl/nx/tree/main/',
},
sidebar,
components: {
Header: './src/components/layout/Header.astro',
Footer: './src/components/layout/Footer.astro',
PageFrame: './src/components/layout/PageFrame.astro',
Sidebar: './src/components/layout/Sidebar.astro',
TwoColumnContent: './src/components/layout/TwoColumnContent.astro',
PageTitle: './src/components/layout/PageTitle.astro',
},
sidebar: [
{
label: 'Getting Started',
autogenerate: { directory: 'getting-started' },
},
{
label: 'Guides',
autogenerate: { directory: 'guides' },
},
{
label: 'Concepts',
autogenerate: { directory: 'concepts' },
},
{
label: 'References',
collapsed: true,
items: [
// have to use link bc slug is mapped to the /docs/ folder but we need the astro component in the pages/ dir
{ label: 'Nx CLI', link: 'api/nx-cli' },
{ label: 'Nx Cloud CLI', slug: 'api/nx-cloud-cli' },
{ label: 'create-nx-workspace', link: 'api/create-nx-workspace' },
{
label: 'devkit',
collapsed: true,
items: [
{ label: 'Overview', link: 'api/plugins/devkit/' },
{
label: 'Ng CLI Adapter',
link: 'api/plugins/devkit/ngcli_adapter',
},
],
},
// plugins are autogenerated from the Nx repository via the sidebar plugin
],
},
],
}),
react(),
],
@@ -1,45 +0,0 @@
import { test, expect } from '@playwright/test';
test('links in descriptions of properties should correctly link to the same page w/ url fragments', async ({
page,
}) => {
await page.goto('/docs/reference/devkit/NxJsonConfiguration');
await expect(
page.getByRole('heading', { name: 'NxJsonConfiguration' })
).toBeVisible();
await page
.getByTestId('main-pane')
.getByRole('link', { name: 'nxCloudAccessToken' })
.click();
await expect(
page.getByRole('heading', { name: 'nxCloudAccessToken' })
).toBeVisible();
const description = page
.getByRole('paragraph')
.filter({ has: page.getByRole('link', { name: 'tasksRunnerOptions' }) })
.first();
await expect(description).toBeVisible();
const linkedProperty = description.getByRole('link', {
name: 'tasksRunnerOptions',
});
await expect(linkedProperty).toBeVisible();
await expect(linkedProperty).toHaveAttribute(
'href',
'/docs/reference/devkit/NxJsonConfiguration#tasksrunneroptions'
);
await linkedProperty.click();
expect(page.url()).toContain('#tasksrunneroptions');
await expect(
page.getByRole('heading', { name: 'tasksRunnerOptions' })
).toBeVisible();
});
-129
View File
@@ -1,129 +0,0 @@
#!/usr/bin/env bash
# | xargs -0 sed -i '' 's/<match>/<replace>/g'
# replace links that start with /concepts to /docs/concepts
rg "\(/concepts" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/concepts|](/docs/concepts|g'
# usage in link card aka href="/concepts/..."
rg "=\"/concepts" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/concepts|="/docs/concepts|g'
# /recipes -> /docs/guides
rg "\(/recipes" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/recipes|](/docs/guides|g'
rg "=\"/recipes" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/recipes|="/docs/guides|g'
# /deprecated -> /docs/reference/deprecated
rg "\(/deprecated" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/deprecated|](/docs/reference/deprecated|g'
rg "=\"/deprecated" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/deprecated|="/docs/reference/deprecated|g'
# /troubleshooting -> /docs/troublshooting
rg "\(/troubleshooting" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/troubleshooting|](/docs/troubleshooting|g'
rg "=\"/troubleshooting" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/troubleshooting|="/docs/troubleshooting|g'
# /plugin-registry -> /docs/plugin-registry
rg "\(/plugin-registry" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/plugin-registry|](/docs/plugin-registry|g'
rg "=\"/plugin-registry" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/plugin-registry|="/docs/plugin-registry|g'
# /features -> /docs/features
rg "\(/features" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/features|](/docs/features|g'
rg "=\"/features" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/features|="/docs/features|g'
# /extending-nx -> /docs/extending-nx
rg "\(/extending-nx" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/extending-nx|](/docs/extending-nx|g'
rg "=\"/extending-nx" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/extending-nx|="/docs/extending-nx|g'
rg "/extending-nx/recipes" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|/extending-nx/recipes|/extending-nx|g'
# /tech -> /docs/tech
rg "\(/tech" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/tech|](/docs/tech|g'
rg "=\"/tech" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/tech|="/docs/tech|g'
## /recipes/running-tasks -> /docs/guides/tasks--caching
rg "\(/recipes/running-tasks" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/recipes/running-tasks|](/docs/guides/tasks--caching|g'
rg "=\"/recipes/running-tasks" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/recipes/running-tasks|="/docs/guides/tasks--caching|g'
# /ci/features -> /docs/features/ci-features
rg "\(/ci/features" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/features|](/docs/features/ci-features|g'
rg "=\"/ci/features" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/features|="/docs/features/ci-features|g'
# /ci/concepts -> /docs/concepts/ci-concepts
rg "\(/ci/concepts" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/concepts|](/docs/concepts/ci-concepts|g'
rg "=\"/ci/concepts" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/concepts|="/docs/concepts/ci-concepts|g'
# /ci/guides/security -> /docs/guides/nx-cloud
rg "\(/ci/guides/security" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/guides/security|](/docs/guides/nx-cloud|g'
rg "=\"/ci/guides/security" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/guides/security|="/docs/guides/nx-cloud|g'
rg "\(/ci/recipes/security" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/recipes/security|](/docs/guides/nx-cloud|g'
rg "=\"/ci/recipes/security" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/recipes/security|="/docs/guides/nx-cloud|g'
# /ci/recipes/enterprise -> /docs/enterprise
rg "\(/ci/recipes/enterprise" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/recipes/enterprise|](/docs/enterprise|g'
rg "=\"/ci/recipes/enterprise" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/recipes/enterprise|="/docs/enterprise|g'
# /ci/recipes -> /docs/guides/nx-cloud
rg "\(/ci/guides" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/guides|](/docs/guides/nx-cloud|g'
rg "=\"/ci/guides" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/guides|="/docs/guides/nx-cloud|g'
rg "\(/ci/recipes" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/recipes|](/docs/guides/nx-cloud|g'
rg "=\"/ci/recipes" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/recipes|="/docs/guides/nx-cloud|g'
# /getting-started -> /docs/getting-started
rg "\(/getting" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/getting|](/docs/getting|g'
rg "=\"/getting" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/getting|="/docs/getting|g'
# /ci/recipes/set-up -> /docs/guides/nx-cloud/setup-ci
rg "\(/ci/recipes/set-up" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/recipes/set-up|](/docs/guides/nx-cloud/setup-ci|g'
rg "=\"/ci/recipes/set-up" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/recipes/set-up|="/docs/guides/nx-cloud/setup-ci|g'
# I merged all the set-up ci guides into 1 page with tabs so we need to remove any links that go to specific guides
rg "/monorepo-ci-" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|\(/[^)]*\)/monorepo-ci-[^)]*\()\)|\1\2|g'
# /ci/reference/nx-cloud-cli -> /docs/reference/nx-cloud-cli
rg "\(/ci/reference/nx-cloud-cli" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/ci/reference/nx-cloud-cli|](/docs/reference/nx-cloud-cli|g'
rg "=\"/ci/reference/nx-cloud-cli" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/ci/reference/nx-cloud-cli|="/docs/reference/nx-cloud-cli|g'
# /blog -> https://nx.dev/blog
rg "\(/blog" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/blog|](https://nx.dev/blog|g'
rg "=\"/blog" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/blog|="https://nx.dev/blog|g'
# /enterprise -> https://nx.dev/enterprise
rg "\(/enterprise" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/enterprise|](https://nx.dev/enterprise|g'
rg "=\"/enterprise" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/enterprise|="https://nx.dev/enterprise|g'
# /pricing -> https://nx.dev/pricing
rg "\(/pricing" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/pricing|](https://nx.dev/pricing|g'
rg "=\"/pricing" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/pricing|="https://nx.dev/pricing|g'
# /contact -> https://nx.dev/contact
rg "\(/contact" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/contact|](https://nx.dev/contact|g'
rg "=\"/contact" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/contact|="https://nx.dev/contact|g'
# /nx-cloud -> https://nx.dev/nx-cloud
rg "\(/nx-cloud" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/nx-cloud|](https://nx.dev/nx-cloud|g'
rg "=\"/nx-cloud" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/nx-cloud|="https://nx.dev/nx-cloud|g'
# /courses -> https://nx.dev/courses
rg "\(/courses" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/courses|](https://nx.dev/courses|g'
rg "=\"/courses" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/courses|="https://nx.dev/courses|g'
# /community -> https://nx.dev/community
rg "\(/community" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/community|](https://nx.dev/community|g'
rg "=\"/community" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/community|="https://nx.dev/community|g'
# though these URLS that have `core-api` in them need to be special handled
# but we can search for 'core-api' later and do a different replace mechinism
# /reference -> /docs/reference
rg "\(/reference" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/reference|](/docs/reference|g'
rg "=\"/reference" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/reference|="/docs/reference|g'
# /docs/reference/core-api/nx/documents/:command -> /docs/reference/nx-commands#:command
rg "\(/docs/reference/core-api/nx/documents/" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|](/docs/reference/core-api/nx/documents/|](/docs/reference/nx-commands#|g'
rg "=\"/docs/reference/core-api/nx/documents/" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|="/docs/reference/core-api/nx/documents/|="/docs/reference/nx-commands#|g'
# /docs/reference/core-api/:remote-cache-plugin/overview -> /docs/reference/remote-cache-plugins/:remote-cache-plugin/overview
# For s3-cache
rg "/docs/reference/core-api/s3-cache" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|/docs/reference/core-api/s3-cache|/docs/reference/remote-cache-plugins/s3-cache|g'
# For azure-cache
rg "/docs/reference/core-api/azure-cache" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|/docs/reference/core-api/azure-cache|/docs/reference/remote-cache-plugins/azure-cache|g'
# For gcs-cache
rg "/docs/reference/core-api/gcs-cache" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|/docs/reference/core-api/gcs-cache|/docs/reference/remote-cache-plugins/gcs-cache|g'
# For shared-fs-cache
rg "/docs/reference/core-api/shared-fs-cache" --type-add "mdoc:*mdoc" -t mdoc -l --null | xargs -0 sed -i '' 's|/docs/reference/core-api/shared-fs-cache|/docs/reference/remote-cache-plugins/shared-fs-cache|g'
-35
View File
@@ -1,35 +0,0 @@
const url = 'http://localhost:4321/docs';
const timeout = 120000; // 2 minutes in milliseconds
console.log('starting up....');
export default async function globalSetup() {
const startTime = Date.now();
const maxEndTime = startTime + timeout;
console.log(`Waiting for ${url} to be available...`);
while (Date.now() < maxEndTime) {
try {
const response = await fetch(url);
if (response.ok) {
console.log(`✓ Server is ready at ${url}`);
return;
}
console.log(
`Server responded with status ${response.status}, retrying...`
);
} catch (error) {
// Server not available yet, continue polling
const remainingTime = Math.round((maxEndTime - Date.now()) / 1000);
if (remainingTime % 10 === 0 && remainingTime > 0) {
console.log(`Still waiting... ${remainingTime} seconds remaining`);
}
}
await new Promise((resolve) => setTimeout(resolve, 1000));
}
throw new Error(
`Server at ${url} did not become available within ${timeout / 1000} seconds`
);
}
+1 -369
View File
@@ -4,367 +4,8 @@ import starlightMarkdoc from '@astrojs/starlight-markdoc';
export default defineMarkdocConfig({
extends: [starlightMarkdoc()],
tags: {
call_to_action: {
render: component('./src/components/markdoc/CallToAction.astro'),
attributes: {
url: {
type: 'String',
required: true,
},
title: {
type: 'String',
required: true,
},
description: {
type: 'String',
required: false,
},
icon: {
type: 'String',
required: false,
},
variant: {
type: 'String',
required: false,
default: 'default',
matches: [
'default',
'gradient',
'inverted',
'gradient-alt',
'simple',
],
},
size: {
type: 'String',
required: false,
default: 'sm',
matches: ['sm', 'md', 'lg'],
},
},
},
callout: {
render: component('./src/components/markdoc/Callout.astro'),
children: ['paragraph', 'tag', 'list'],
attributes: {
type: {
type: 'String',
default: 'note',
matches: [
'announcement',
'caution',
'check',
'note',
'warning',
'deepdive',
],
errorLevel: 'critical',
},
title: {
type: 'String',
required: true,
},
expanded: {
type: 'Boolean',
default: false,
},
},
},
card: {
render: component('./src/components/markdoc/Card.astro'),
attributes: {
title: {
type: 'String',
required: true,
},
description: {
type: 'String',
default: '',
},
type: {
type: 'String',
default: 'documentation',
},
url: {
type: 'String',
default: '',
},
},
},
cards: {
render: component('./src/components/markdoc/Cards.astro'),
attributes: {
cols: {
type: 'Number',
},
smCols: {
type: 'Number',
},
mdCols: {
type: 'Number',
},
lgCols: {
type: 'Number',
},
moreLink: {
type: 'String',
},
},
},
course_video: {
render: component('./src/components/markdoc/CourseVideo.astro'),
attributes: {
src: {
type: 'String',
required: true,
},
courseTitle: {
type: 'String',
required: true,
},
courseUrl: {
type: 'String',
required: true,
},
},
},
github_repository: {
render: component('./src/components/markdoc/GithubRepository.astro'),
attributes: {
url: {
type: 'String',
required: true,
},
title: {
type: 'String',
required: false,
},
},
},
graph: {
render: component('./src/components/markdoc/Graph.astro'),
children: [],
attributes: {
jsonFile: {
type: 'String',
},
title: {
type: 'String',
},
type: {
type: 'String',
matches: ['project', 'task'],
default: 'project',
},
height: {
type: 'String',
required: true,
},
},
},
iframe: {
render: component('./src/components/markdoc/Iframe.astro'),
attributes: {
src: {
type: 'String',
required: true,
},
title: {
type: 'String',
required: true,
},
width: {
type: 'String',
default: '50%',
},
},
},
install_nx_console: {
render: component('./src/components/markdoc/InstallNxConsole.astro'),
attributes: {},
},
link_card: {
render: component('./src/components/markdoc/LinkCard.astro'),
attributes: {
title: {
type: 'String',
required: true,
},
type: {
type: 'String',
required: true,
},
icon: {
type: 'String',
required: false,
},
url: {
type: 'String',
default: '',
},
appearance: {
type: 'String',
default: 'default',
},
},
},
index_page_cards: {
render: component('./src/components/markdoc/IndexPageCards.astro'),
attributes: {
path: {
type: 'String',
required: true,
},
},
},
metrics: {
render: component('./src/components/markdoc/Metrics.astro'),
attributes: {
metrics: {
type: 'Array',
required: true,
},
},
},
persona: {
render: component('./src/components/markdoc/Persona.astro'),
children: ['paragraph', 'tag', 'list'],
attributes: {
title: {
type: 'String',
},
type: {
type: 'String',
default: 'integrated',
required: true,
matches: [
'cache',
'distribute',
'javascript',
'lerna',
'react',
'angular',
'integrated',
],
errorLevel: 'critical',
},
url: {
type: 'String',
required: true,
errorLevel: 'critical',
},
},
},
personas: {
render: component('./src/components/markdoc/Personas.astro'),
},
pill: {
render: component('./src/components/markdoc/Pill.astro'),
attributes: {
url: {
type: 'String',
default: '',
},
},
},
project_details: {
render: component('./src/components/markdoc/ProjectDetails.astro'),
children: [],
attributes: {
jsonFile: {
type: 'String',
},
title: {
type: 'String',
},
height: {
type: 'String',
},
expandedTargets: {
type: 'Array',
},
},
},
stackblitz_button: {
render: component('./src/components/markdoc/StackblitzButton.astro'),
attributes: {
url: {
type: 'String',
required: true,
},
title: {
type: 'String',
required: false,
},
},
},
testimonial: {
render: component('./src/components/markdoc/Testimonial.astro'),
children: ['paragraph'],
attributes: {
name: {
type: 'String',
},
title: {
type: 'String',
},
image: {
type: 'String',
},
},
},
video_link: {
render: component('./src/components/markdoc/VideoLink.astro'),
attributes: {
link: {
type: 'String',
required: true,
},
text: {
type: 'String',
required: false,
},
},
},
video_player: {
render: component('./src/components/markdoc/VideoPlayer.astro'),
attributes: {
src: {
type: 'String',
required: true,
},
alt: {
type: 'String',
required: false,
},
link: {
type: 'String',
required: false,
},
showDescription: {
type: 'Boolean',
required: false,
default: false,
},
showControls: {
type: 'Boolean',
required: false,
default: false,
},
autoPlay: {
type: 'Boolean',
required: false,
default: false,
},
loop: {
type: 'Boolean',
required: false,
default: false,
},
},
},
youtube: {
render: component('./src/components/markdoc/Youtube.astro'),
render: component('./src/components/Youtube.astro'),
attributes: {
src: {
type: 'String',
@@ -384,14 +25,5 @@ export default defineMarkdocConfig({
},
},
},
side_by_side: {
render: component('./src/components/markdoc/SideBySide.astro'),
attributes: {
align: {
type: 'String',
default: 'center',
},
},
},
},
});
-22
View File
@@ -1,22 +0,0 @@
# Permanent redirects (301 by default)
[[redirects]]
from = "/"
to = "/docs/getting-started/intro"
[[redirects]]
from = "/showcase"
to = "/docs/quickstart"
[[redirects]]
from = "/showcase/example-repos/*"
to = "/docs/quickstart"
[[redirects]]
from = "/showcase/benchmarks/*"
to = "/docs/reference/benchmarks/:splat"
# Rewrite for base path handling (keeps URL the same)
[[redirects]]
from = "/docs/*"
to = "/:splat"
status = 200
-3
View File
@@ -10,13 +10,10 @@
"@astrojs/starlight": "0.34.6",
"@astrojs/starlight-markdoc": "^0.4.0",
"@astrojs/starlight-tailwind": "^4.0.1",
"@nx/nx-dev-ui-common": "workspace:*",
"@nx/nx-dev-ui-icons": "workspace:*",
"@nx/nx-dev-ui-markdoc": "workspace:*",
"@tailwindcss/vite": "^4.1.11",
"astro": "^5.10.1",
"astro-og-canvas": "^0.7.0",
"canvaskit-wasm": "^0.40.0",
"tailwindcss": "4.1.11"
}
}
-42
View File
@@ -1,42 +0,0 @@
import { defineConfig, devices } from '@playwright/test';
import { nxE2EPreset } from '@nx/playwright/preset';
import { workspaceRoot } from '@nx/devkit';
import { join } from 'path';
// For CI, you may want to set BASE_URL to the deployed application.
const baseURL = process.env['BASE_URL'] || 'http://localhost:4321';
const reportDir = join(
workspaceRoot,
'dist',
'astro-docs',
'playwright-report'
);
export default defineConfig({
...nxE2EPreset(__filename, { testDir: './e2e' }),
reporter: [
['list', { printSteps: true }],
['html', { outputFolder: reportDir, open: 'never' }],
[
'junit',
{
// JUnit only respects the outputFile option, and not outputDir or outputFolder
outputFile: `${reportDir}/test-e2e-nx-cloud.xml`,
},
],
],
/* Global setup to wait for server */
globalSetup: require.resolve('./global-setup.e2e.ts'),
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
baseURL,
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});
+1 -46
View File
@@ -1,8 +1,7 @@
{
"name": "astro-docs",
"$schema": "../node_modules/nx/schemas/project-schema.json",
"comment": "package.json#scripts runs in the project root directory with astro assumes is where the node_modules is. which fails. so run the scripts in project.json#targets with --root command instead",
"targets": {
"comment": "package.json#scripts runs in the project root directory with astro assumes is where the node_modules is. which fails. so run the scripts in project.json#targets with --root command instead",
"serve": {
"continuous": true,
"dependsOn": [
@@ -23,60 +22,16 @@
"target": "build"
}
],
"outputs": [
"{projectRoot}/dist",
"{projectRoot}/.astro",
"{projectRoot}/.netlify"
],
"command": "astro build",
"options": {
"cwd": "astro-docs"
}
},
"preview": {
"dependsOn": ["build"],
"command": "astro preview",
"continuous": true,
"options": {
"cwd": "astro-docs"
}
},
"astro": {
"command": "astro",
"options": {
"cwd": "astro-docs"
}
},
"test": {
"dependsOn": ["validate-links"],
"command": "echo done"
},
"pw-e2e": {
"dependsOn": ["serve"],
"parallelism": true
},
"e2e-ci--**/*": {
"dependsOn": ["preview"],
"parallelism": true
},
"show-report": {
"command": "playwright show-report dist/astro-docs/playwright-report"
},
"validate-links": {
"dependsOn": ["build"],
"cache": true,
"inputs": [
"{projectRoot}/src/**/*",
"{projectRoot}/astro.config.mjs",
"{projectRoot}/sidebar.mts",
"{projectRoot}/markdoc.config.mjs",
"{projectRoot}/tsconfig.json",
"{projectRoot}/package.json"
],
"command": "npx tsx validate-links.ts",
"options": {
"cwd": "astro-docs"
}
}
}
}
-162
View File
@@ -1,162 +0,0 @@
(function () {
const config = window.__CONFIG || {};
if (!config.isProd) return;
const isCookiebotDisabled = config.cookiebotDisabled ?? false;
const gaMeasurementId = config.gaMeasurementId ?? 'UA-88380372-10';
const gtmMeasurementId = config.gtmMeasurementId ?? 'GTM-KW8423B6';
// Initialize global objects
window.Cookiebot = window.Cookiebot || {};
window.dataLayer = window.dataLayer || [];
window.gtag =
window.gtag ||
function () {
window.dataLayer.push(arguments);
};
const loadGoogleAnalytics = () => {
const script = document.createElement('script');
script.src = `https://www.googletagmanager.com/gtag/js?id=${gaMeasurementId}`;
script.async = true;
document.head.appendChild(script);
// Initialize gtag
window.gtag('js', new Date());
window.gtag('config', gaMeasurementId, {
page_path: window.location.pathname,
});
};
const loadGTM = () => {
if (!gtmMeasurementId) return;
(function (w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', gtmMeasurementId);
};
const loadHubSpot = () => {
const hsScript = document.createElement('script');
hsScript.src = 'https://js.hs-scripts.com/2757427.js';
hsScript.async = true;
hsScript.defer = true;
document.head.appendChild(hsScript);
// Load HubSpot Forms
const hsFormsScript = document.createElement('script');
hsFormsScript.src = '//js.hsforms.net/forms/v2.js';
hsFormsScript.async = true;
hsFormsScript.defer = true;
document.head.appendChild(hsFormsScript);
};
const loadApollo = () => {
const n = Math.random().toString(36).substring(7);
const script = document.createElement('script');
script.src = `https://assets.apollo.io/micro/website-tracker/tracker.iife.js?nocache=${n}`;
script.async = true;
script.defer = true;
script.onload = function () {
if (window.trackingFunctions?.onLoad) {
window.trackingFunctions.onLoad({
appId: '65e1db2f1976f30300fd8b26',
});
}
};
document.head.appendChild(script);
};
const loadHotjar = () => {
(function (h, o, t, j, a, r) {
h.hj =
h.hj ||
function () {
(h.hj.q = h.hj.q || []).push(arguments);
};
h._hjSettings = { hjid: 2774127, hjsv: 6 };
a = o.getElementsByTagName('head')[0];
r = o.createElement('script');
r.async = 1;
r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
a.appendChild(r);
})(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv=');
};
const loadTwitterPixel = () => {
!(function (e, t, n, s, u, a) {
e.twq ||
((s = e.twq =
function () {
s.exe ? s.exe.apply(s, arguments) : s.queue.push(arguments);
}),
(s.version = '1.1'),
(s.queue = []),
(u = t.createElement(n)),
(u.async = !0),
(u.src = 'https://static.ads-twitter.com/uwt.js'),
(a = t.getElementsByTagName(n)[0]),
a.parentNode.insertBefore(u, a));
})(window, document, 'script');
window.twq('config', 'obtp4');
};
const checkAndLoadScripts = () => {
if (isCookiebotDisabled) {
loadGoogleAnalytics();
loadGTM();
loadHubSpot();
} else if (window.Cookiebot && window.Cookiebot.consent) {
// Statistics cookies (Google Analytics, GTM)
if (window.Cookiebot.consent.statistics) {
loadGoogleAnalytics();
loadGTM();
}
// Marketing cookies (HubSpot, Apollo, Hotjar, Twitter)
if (window.Cookiebot.consent.marketing) {
loadHubSpot();
loadApollo();
loadHotjar();
loadTwitterPixel();
}
} else {
// Wait for Cookiebot to load
setTimeout(checkAndLoadScripts, 100);
}
};
// Add GTM noscript iframe to body
const addGTMNoScript = () => {
const noscript = document.createElement('noscript');
const iframe = document.createElement('iframe');
iframe.src = `https://www.googletagmanager.com/ns.html?id=${gtmMeasurementId}`;
iframe.height = '0';
iframe.width = '0';
iframe.style.display = 'none';
iframe.style.visibility = 'hidden';
iframe.title = 'Google Tag Manager';
noscript.appendChild(iframe);
document.body.insertBefore(noscript, document.body.firstChild);
};
// Listen for user consent to cookies
window.addEventListener('CookiebotOnAccept', checkAndLoadScripts);
// Initial check
checkAndLoadScripts();
// Add GTM noscript on DOM ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', addGTMNoScript);
} else {
addGTMNoScript();
}
})();
@@ -1 +0,0 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Angular</title><path d="M16.712 17.711H7.288l-1.204 2.916L12 24l5.916-3.373-1.204-2.916ZM14.692 0l7.832 16.855.814-12.856L14.692 0ZM9.308 0 .662 3.999l.814 12.856L9.308 0Zm-.405 13.93h6.198L12 6.396 8.903 13.93Z"/></svg>

Before

Width:  |  Height:  |  Size: 299 B

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="m21 7.5-9-5.25L3 7.5m18 0-9 5.25m9-5.25v9l-9 5.25M3 7.5l9 5.25M3 7.5v9l9 5.25m0-9v9" />
</svg>

Before

Width:  |  Height:  |  Size: 284 B

@@ -1 +0,0 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>ESLint</title><path d="M7.257 9.132L11.816 6.5a.369.369 0 0 1 .368 0l4.559 2.632a.369.369 0 0 1 .184.32v5.263a.37.37 0 0 1-.184.319l-4.559 2.632a.369.369 0 0 1-.368 0l-4.559-2.632a.369.369 0 0 1-.184-.32V9.452a.37.37 0 0 1 .184-.32M23.852 11.53l-5.446-9.475c-.198-.343-.564-.596-.96-.596H6.555c-.396 0-.762.253-.96.596L.149 11.509a1.127 1.127 0 0 0 0 1.117l5.447 9.398c.197.342.563.517.959.517h10.893c.395 0 .76-.17.959-.512l5.446-9.413a1.069 1.069 0 0 0 0-1.086m-4.51 4.556a.4.4 0 0 1-.204.338L12.2 20.426a.395.395 0 0 1-.392 0l-6.943-4.002a.4.4 0 0 1-.205-.338V8.08c0-.14.083-.269.204-.338L11.8 3.74c.12-.07.272-.07.392 0l6.943 4.003a.4.4 0 0 1 .206.338z"/></svg>

Before

Width:  |  Height:  |  Size: 743 B

-9
View File
@@ -1,9 +0,0 @@
<svg
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
>
<title>Java</title>
<path d="m16.5093 4.9869-.0607-.0347c-1.1014.369-4.4915 1.707-4.4915 4.202 0 1.411 1.378 2.1925 1.378 3.5158 0 .472-.2666.9146-.4836 1.1791l.1091.063c.5735-.3728 1.589-1.18 1.589-2.2222 0-.8825-1.2216-1.943-1.2216-3.0774 0-1.7875 2.357-3.1899 3.1813-3.6256zm-1.6642-3.27c0 3.6925-5.0604 5.1055-5.0604 7.7309 0 1.843 1.2222 2.9987 1.8983 3.7293l-.055.0317c-.8536-.534-3.0995-1.876-3.0995-4.0927 0-3.112 5.8123-4.599 5.8123-8.134 0-.435-.0644-.7683-.1095-.9482L14.2901 0c.1842.2315.555.8102.555 1.7168m.514 14.9392c-.5962.1688-1.9389.4441-3.859.4441-1.8844 0-3.424-.3226-3.4289-.7024-.0032-.2527.3024-.3628.3024-.3628l-.0544-.0316c-.9023.1595-1.7406.406-1.7357.7752.0084.6698 2.5697 1.1728 4.9129 1.1728 1.992 0 3.9053-.3343 4.7684-.7722zm-6.368 2.0708c-.4185.0832-1.3305.2926-1.3305.7361 0 .6144 1.9513 1.085 3.835 1.085 2.5922 0 3.6539-.667 3.702-.7016l-1.078-.6235c-.4583.1092-1.2306.2808-2.6214.2808-1.5521 0-2.5634-.2658-2.5634-.5569 0-.0617.0386-.135.1106-.1886zm10.5923-4.1337c-.0725 1.3911-1.3577 2.2573-2.6423 2.9893l.1164.067c1.3708-.3855 3.8166-1.5085 3.6144-3.2346-.1007-.8608-.8875-1.4758-1.9133-1.4758-.3194 0-.6036.0563-.834.1265l-.0007.0022-.0486.1224c.9175-.1796 1.7558.4904 1.7082 1.403zm-8.1232 8.1638c3.6058-.0313 7.6402-.737 7.6298-1.9232-.0019-.215-.1418-.3622-.2635-.4513l-.0592.034c-.3333.9188-3.1508 1.5977-7.3132 1.634-2.6859.0234-6.4063-.62-6.4128-1.3636-.0065-.7455 1.7625-1.1552 1.7625-1.1552l-.125-.0714c-1.1854.1632-3.3697.731-3.3625 1.5506.0104 1.185 5.0304 1.7734 8.1439 1.7461zm-.375.847c-1.4333.0126-3.1833-.1061-4.6555-.3535l-.1363.0784c1.4664.43 3.508.6896 5.7514.6702 4.4059-.0386 7.9779-1.1311 8.0485-2.446l-.051-.0297c-.2953.3604-2.2009 2.0216-8.9572 2.0806zm-5.5195-9.328c0-.6646 2.521-1.0374 3.6947-1.1277l.112.0647c-.451.082-2.26.401-2.26.8172 0 .4532 2.7747.7501 4.3853.7501 2.7355 0 4.595-.414 5.095-.5505l.6997.4072c-.4792.2346-2.5362.8495-5.7945.8495-3.6214 0-5.9322-.7086-5.9322-1.2105" />
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

@@ -1,18 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1244_718)">
<path d="M9.35205 3.72154V7.35041L12.0002 8.93803M9.35205 3.72154L12.0002 2.13391L14.6483 3.72154M9.35205 3.72154L12.0002 5.08236M12.0002 8.93803L14.6483 7.35041V3.72154M12.0002 8.93803V5.08236M14.6483 3.72154L12.0002 5.08236" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
<path d="M8.3335 3.26804L12.0002 1L15.6668 3.26804V7.80412L12.0002 10.0722L8.3335 7.80412V3.26804Z" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
<path d="M2.01855 15.2888V18.9177L4.6667 20.5053M2.01855 15.2888L4.6667 13.7012L7.31485 15.2888M2.01855 15.2888L4.6667 16.8764M4.6667 20.5053L7.31485 18.9177V15.2888M4.6667 20.5053V16.8764M7.31485 15.2888L4.6667 16.8764" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
<path d="M1 14.8349L4.66667 12.5669L8.33333 14.8349V19.371L4.66667 21.6391L1 19.371V14.8349Z" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
<path d="M16.6855 15.2888V18.9177L19.3337 20.5053M16.6855 15.2888L19.3337 13.7012L21.9818 15.2888M16.6855 15.2888L19.3337 16.6496M19.3337 20.5053L21.9818 18.9177V15.2888M19.3337 20.5053V16.6496M21.9818 15.2888L19.3337 16.6496" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
<path d="M15.6665 14.8349L19.3332 12.5669L22.9998 14.8349V19.371L19.3332 21.6391L15.6665 19.371V14.8349Z" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
<path d="M8.33317 6.89685L4.6665 9.16489V12.567" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
<path d="M15.6668 6.89685L19.3335 9.16489V12.567" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
<path d="M7.51855 19.8248L12 23.0001L16.4815 19.8248" stroke="black" stroke-width="0.5" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1244_718">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

@@ -1 +0,0 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Node.js</title><path d="M11.998,24c-0.321,0-0.641-0.084-0.922-0.247l-2.936-1.737c-0.438-0.245-0.224-0.332-0.08-0.383 c0.585-0.203,0.703-0.25,1.328-0.604c0.065-0.037,0.151-0.023,0.218,0.017l2.256,1.339c0.082,0.045,0.197,0.045,0.272,0l8.795-5.076 c0.082-0.047,0.134-0.141,0.134-0.238V6.921c0-0.099-0.053-0.192-0.137-0.242l-8.791-5.072c-0.081-0.047-0.189-0.047-0.271,0 L3.075,6.68C2.99,6.729,2.936,6.825,2.936,6.921v10.15c0,0.097,0.054,0.189,0.139,0.235l2.409,1.392 c1.307,0.654,2.108-0.116,2.108-0.89V7.787c0-0.142,0.114-0.253,0.256-0.253h1.115c0.139,0,0.255,0.112,0.255,0.253v10.021 c0,1.745-0.95,2.745-2.604,2.745c-0.508,0-0.909,0-2.026-0.551L2.28,18.675c-0.57-0.329-0.922-0.945-0.922-1.604V6.921 c0-0.659,0.353-1.275,0.922-1.603l8.795-5.082c0.557-0.315,1.296-0.315,1.848,0l8.794,5.082c0.57,0.329,0.924,0.944,0.924,1.603 v10.15c0,0.659-0.354,1.273-0.924,1.604l-8.794,5.078C12.643,23.916,12.324,24,11.998,24z M19.099,13.993 c0-1.9-1.284-2.406-3.987-2.763c-2.731-0.361-3.009-0.548-3.009-1.187c0-0.528,0.235-1.233,2.258-1.233 c1.807,0,2.473,0.389,2.747,1.607c0.024,0.115,0.129,0.199,0.247,0.199h1.141c0.071,0,0.138-0.031,0.186-0.081 c0.048-0.054,0.074-0.123,0.067-0.196c-0.177-2.098-1.571-3.076-4.388-3.076c-2.508,0-4.004,1.058-4.004,2.833 c0,1.925,1.488,2.457,3.895,2.695c2.88,0.282,3.103,0.703,3.103,1.269c0,0.983-0.789,1.402-2.642,1.402 c-2.327,0-2.839-0.584-3.011-1.742c-0.02-0.124-0.126-0.215-0.253-0.215h-1.137c-0.141,0-0.254,0.112-0.254,0.253 c0,1.482,0.806,3.248,4.655,3.248C17.501,17.007,19.099,15.91,19.099,13.993z"/></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

-1
View File
@@ -1 +0,0 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>React</title><path d="M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z"/></svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

@@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.75 3.104v5.714a2.25 2.25 0 0 1-.659 1.591L5 14.5M9.75 3.104c-.251.023-.501.05-.75.082m.75-.082a24.301 24.301 0 0 1 4.5 0m0 0v5.714c0 .597.237 1.17.659 1.591L19.8 15.3M14.25 3.104c.251.023.501.05.75.082M19.8 15.3l-1.57.393A9.065 9.065 0 0 1 12 15a9.065 9.065 0 0 0-6.23-.693L5 14.5m14.8.8 1.402 1.402c1.232 1.232.65 3.318-1.067 3.611A48.309 48.309 0 0 1 12 21c-2.773 0-5.491-.235-8.135-.687-1.718-.293-2.3-2.379-1.067-3.61L5 14.5" />
</svg>

Before

Width:  |  Height:  |  Size: 632 B

@@ -1,4 +0,0 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>TypeScript</title>
<path d="M0 12v12h24V0H0zm19.341-.956c.61.152 1.074.423 1.501.865.221.236.549.666.575.77.008.03-1.036.73-1.668 1.123-.023.015-.115-.084-.217-.236-.31-.45-.633-.644-1.128-.678-.728-.05-1.196.331-1.192.967a.88.88 0 0 0 .102.45c.16.331.458.53 1.39.933 1.719.74 2.454 1.227 2.911 1.92.51.773.625 2.008.278 2.926-.38.998-1.325 1.676-2.655 1.9-.411.073-1.386.062-1.828-.018-.964-.172-1.878-.648-2.442-1.273-.221-.243-.652-.88-.625-.925.011-.016.11-.077.22-.141.108-.061.511-.294.892-.515l.69-.4.145.214c.202.308.643.731.91.872.766.404 1.817.347 2.335-.118a.883.883 0 0 0 .313-.72c0-.278-.035-.4-.18-.61-.186-.266-.567-.49-1.649-.96-1.238-.533-1.771-.864-2.259-1.39a3.165 3.165 0 0 1-.659-1.2c-.091-.339-.114-1.189-.042-1.531.255-1.197 1.158-2.03 2.461-2.278.423-.08 1.406-.05 1.821.053zm-5.634 1.002l.008.983H10.59v8.876H8.38v-8.876H5.258v-.964c0-.534.011-.98.026-.99.012-.016 1.913-.024 4.217-.02l4.195.012z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1019 B

@@ -1 +0,0 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Vue.js</title><path d="M24,1.61H14.06L12,5.16,9.94,1.61H0L12,22.39ZM12,14.08,5.16,2.23H9.59L12,6.41l2.41-4.18h4.43Z"/></svg>

Before

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 KiB

+1 -6
View File
@@ -1,9 +1,4 @@
# *
User-agent: *
Allow: /
# Host
Host: https://nx.dev
# Sitemaps
Sitemap: https://nx.dev/sitemap-index.xml
Sitemap: https://<YOUR SITE>/sitemap-index.xml
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://nx.dev/docs/sitemap-0.xml</loc>
</sitemap>
</sitemapindex>
-220
View File
@@ -1,220 +0,0 @@
import type { StarlightUserConfig } from '@astrojs/starlight/types';
import { getPluginItems } from './src/plugins/utils/plugin-mappings';
export const sidebar: StarlightUserConfig['sidebar'] = [
{
label: 'Getting Started',
collapsed: false,
autogenerate: { directory: 'getting-started', collapsed: true },
},
{
label: 'Features',
collapsed: false,
autogenerate: { directory: 'features', collapsed: true },
},
{
label: 'Core Guides',
collapsed: true,
autogenerate: { directory: 'guides', collapsed: true },
},
{
label: 'Core Concepts',
collapsed: true,
autogenerate: { directory: 'concepts', collapsed: true },
},
{
label: 'Technologies',
collapsed: false,
// manually type the tech routes due to complexity of order and structure
items: [
{
label: 'TypeScript',
collapsed: true,
items: getPluginItems('js'),
},
{
label: 'Angular',
collapsed: true,
items: [
...getPluginItems('angular'),
{
label: 'Angular Rspack',
collapsed: true,
items: getPluginItems('angular-rspack', 'angular'),
},
{
label: 'Angular Rsbuild',
collapsed: true,
items: getPluginItems('angular-rsbuild', 'angular'),
},
],
},
{
label: 'React',
collapsed: true,
items: [
...getPluginItems('react'),
{
label: 'Next',
collapsed: true,
items: getPluginItems('next', 'react'),
},
{
label: 'Remix',
collapsed: true,
items: getPluginItems('remix', 'react'),
},
{
label: 'React Native',
collapsed: true,
items: getPluginItems('react-native', 'react'),
},
{
label: 'Expo',
collapsed: true,
items: getPluginItems('expo', 'react'),
},
],
},
{
label: 'Vue',
collapsed: true,
items: [
...getPluginItems('vue'),
{
label: 'Nuxt',
collapsed: true,
items: getPluginItems('nuxt', 'vue'),
},
],
},
{
label: 'Node.js',
collapsed: true,
items: [
...getPluginItems('node'),
{
label: 'Express',
collapsed: true,
items: getPluginItems('express', 'node'),
},
{
label: 'Nest',
collapsed: true,
items: getPluginItems('nest', 'node'),
},
],
},
{
label: 'Java',
collapsed: true,
// when we have maven this will change to not have gradle as the top docs for Java
items: getPluginItems('gradle', 'java'),
},
{
label: 'Module Federation',
collapsed: true,
items: getPluginItems('module-federation'),
},
{
label: 'ESLint',
collapsed: true,
items: [
...getPluginItems('eslint'),
{
label: 'ESLint Plugin',
collapsed: true,
items: getPluginItems('eslint-plugin', 'eslint'),
},
],
},
{
label: 'Build Tools',
collapsed: true,
items: [
{
label: 'Webpack',
collapsed: true,
items: getPluginItems('webpack', 'build-tools'),
},
{
label: 'Vite',
collapsed: true,
items: getPluginItems('vite', 'build-tools'),
},
{
label: 'Rollup',
collapsed: true,
items: getPluginItems('rollup', 'build-tools'),
},
{
label: 'ESBuild',
collapsed: true,
items: getPluginItems('esbuild', 'build-tools'),
},
{
label: 'Rspack',
collapsed: true,
items: getPluginItems('rspack', 'build-tools'),
},
{
label: 'Rsbuild',
collapsed: true,
items: getPluginItems('rsbuild', 'build-tools'),
},
],
},
{
label: 'Test Tools',
collapsed: true,
items: [
{
label: 'Cypress',
collapsed: true,
items: getPluginItems('cypress', 'test-tools'),
},
{
label: 'Jest',
collapsed: true,
items: getPluginItems('jest', 'test-tools'),
},
{
label: 'Playwright',
collapsed: true,
items: getPluginItems('playwright', 'test-tools'),
},
{
label: 'Storybook',
collapsed: true,
items: getPluginItems('storybook', 'test-tools'),
},
{
label: 'Detox',
collapsed: true,
items: getPluginItems('detox', 'test-tools'),
},
],
},
],
},
{
label: 'Enterprise',
collapsed: true,
autogenerate: { directory: 'enterprise', collapsed: true },
},
{
label: 'Extending Nx',
collapsed: true,
autogenerate: { directory: 'extending-nx', collapsed: true },
},
{
label: 'Reference',
collapsed: false,
autogenerate: { directory: 'reference', collapsed: true },
},
{
label: 'Troubleshooting',
collapsed: false,
autogenerate: { directory: 'troubleshooting', collapsed: true },
},
];
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 66 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Some files were not shown because too many files have changed in this diff Show More