1
0
mirror of synced 2025-12-19 09:57:42 -05:00

Support "npm run writers" to display a list of writer-focused tools (#58326)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Sarah Schneider
2025-11-03 14:18:43 -05:00
committed by GitHub
parent 00e523c65d
commit d6cb86c0bf
17 changed files with 287 additions and 67 deletions

45
package-lock.json generated
View File

@@ -240,7 +240,6 @@
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz",
"integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==", "integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@octokit/auth-token": "^4.0.0", "@octokit/auth-token": "^4.0.0",
"@octokit/graphql": "^7.1.0", "@octokit/graphql": "^7.1.0",
@@ -401,6 +400,7 @@
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
"peer": true,
"dependencies": { "dependencies": {
"@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24" "@jridgewell/trace-mapping": "^0.3.24"
@@ -586,6 +586,7 @@
"version": "7.23.3", "version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz",
"integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==",
"peer": true,
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@@ -623,12 +624,14 @@
"node_modules/@babel/core/node_modules/convert-source-map": { "node_modules/@babel/core/node_modules/convert-source-map": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"peer": true
}, },
"node_modules/@babel/core/node_modules/semver": { "node_modules/@babel/core/node_modules/semver": {
"version": "6.3.1", "version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"peer": true,
"bin": { "bin": {
"semver": "bin/semver.js" "semver": "bin/semver.js"
} }
@@ -662,6 +665,7 @@
"version": "7.22.15", "version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz",
"integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==",
"peer": true,
"dependencies": { "dependencies": {
"@babel/compat-data": "^7.22.9", "@babel/compat-data": "^7.22.9",
"@babel/helper-validator-option": "^7.22.15", "@babel/helper-validator-option": "^7.22.15",
@@ -677,6 +681,7 @@
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"peer": true,
"dependencies": { "dependencies": {
"yallist": "^3.0.2" "yallist": "^3.0.2"
} }
@@ -685,6 +690,7 @@
"version": "6.3.1", "version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"peer": true,
"bin": { "bin": {
"semver": "bin/semver.js" "semver": "bin/semver.js"
} }
@@ -692,7 +698,8 @@
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": { "node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"peer": true
}, },
"node_modules/@babel/helper-environment-visitor": { "node_modules/@babel/helper-environment-visitor": {
"version": "7.22.20", "version": "7.22.20",
@@ -740,6 +747,7 @@
"version": "7.23.3", "version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz",
"integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==",
"peer": true,
"dependencies": { "dependencies": {
"@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-module-imports": "^7.22.15", "@babel/helper-module-imports": "^7.22.15",
@@ -766,6 +774,7 @@
"version": "7.22.5", "version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
"integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
"peer": true,
"dependencies": { "dependencies": {
"@babel/types": "^7.22.5" "@babel/types": "^7.22.5"
}, },
@@ -804,6 +813,7 @@
"version": "7.22.15", "version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz",
"integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==",
"peer": true,
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@@ -812,6 +822,7 @@
"version": "7.26.10", "version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz",
"integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==", "integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==",
"peer": true,
"dependencies": { "dependencies": {
"@babel/template": "^7.26.9", "@babel/template": "^7.26.9",
"@babel/types": "^7.26.10" "@babel/types": "^7.26.10"
@@ -2695,7 +2706,6 @@
"version": "7.0.2", "version": "7.0.2",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.2.tgz", "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.2.tgz",
"integrity": "sha512-ODsoD39Lq6vR6aBgvjTnA3nZGliknKboc9Gtxr7E4WDNqY24MxANKcuDQSF0jzapvGb3KWOEDrKfve4HoWGK+g==", "integrity": "sha512-ODsoD39Lq6vR6aBgvjTnA3nZGliknKboc9Gtxr7E4WDNqY24MxANKcuDQSF0jzapvGb3KWOEDrKfve4HoWGK+g==",
"peer": true,
"dependencies": { "dependencies": {
"@octokit/auth-token": "^6.0.0", "@octokit/auth-token": "^6.0.0",
"@octokit/graphql": "^9.0.1", "@octokit/graphql": "^9.0.1",
@@ -3343,7 +3353,6 @@
"integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==", "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==",
"devOptional": true, "devOptional": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"dependencies": { "dependencies": {
"playwright": "1.56.1" "playwright": "1.56.1"
}, },
@@ -4155,7 +4164,6 @@
"integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/body-parser": "*", "@types/body-parser": "*",
"@types/express-serve-static-core": "^5.0.0", "@types/express-serve-static-core": "^5.0.0",
@@ -4317,7 +4325,6 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz",
"integrity": "sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==", "integrity": "sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/prop-types": "*", "@types/prop-types": "*",
"csstype": "^3.0.2" "csstype": "^3.0.2"
@@ -4329,7 +4336,6 @@
"integrity": "sha512-nf22//wEbKXusP6E9pfOCDwFdHAX4u172eaJI4YkDRQEZiorm6KfYnSC2SWLDMVWUOWPERmJnN0ujeAfTBLvrw==", "integrity": "sha512-nf22//wEbKXusP6E9pfOCDwFdHAX4u172eaJI4YkDRQEZiorm6KfYnSC2SWLDMVWUOWPERmJnN0ujeAfTBLvrw==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"peer": true,
"peerDependencies": { "peerDependencies": {
"@types/react": "^18.0.0" "@types/react": "^18.0.0"
} }
@@ -4500,7 +4506,6 @@
"integrity": "sha512-pUXGCuHnnKw6PyYq93lLRiZm3vjuslIy7tus1lIQTYVK9bL8XBgJnCWm8a0KcTtHC84Yya1Q6rtll+duSMj0dg==", "integrity": "sha512-pUXGCuHnnKw6PyYq93lLRiZm3vjuslIy7tus1lIQTYVK9bL8XBgJnCWm8a0KcTtHC84Yya1Q6rtll+duSMj0dg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.39.1", "@typescript-eslint/scope-manager": "8.39.1",
"@typescript-eslint/types": "8.39.1", "@typescript-eslint/types": "8.39.1",
@@ -5139,7 +5144,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -5169,7 +5173,6 @@
"version": "8.17.1", "version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1", "fast-uri": "^3.0.1",
@@ -5669,7 +5672,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"caniuse-lite": "^1.0.30001733", "caniuse-lite": "^1.0.30001733",
"electron-to-chromium": "^1.5.199", "electron-to-chromium": "^1.5.199",
@@ -5920,7 +5922,6 @@
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
"integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"cheerio-select": "^2.1.0", "cheerio-select": "^2.1.0",
"dom-serializer": "^2.0.0", "dom-serializer": "^2.0.0",
@@ -7142,7 +7143,6 @@
"integrity": "sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==", "integrity": "sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
@@ -7204,7 +7204,6 @@
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"eslint-config-prettier": "bin/cli.js" "eslint-config-prettier": "bin/cli.js"
}, },
@@ -7463,7 +7462,6 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@rtsao/scc": "^1.1.0", "@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9", "array-includes": "^3.1.9",
@@ -8623,6 +8621,7 @@
"node_modules/gensync": { "node_modules/gensync": {
"version": "1.0.0-beta.2", "version": "1.0.0-beta.2",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@@ -8828,7 +8827,6 @@
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz",
"integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==",
"dev": true, "dev": true,
"peer": true,
"engines": { "engines": {
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
} }
@@ -10203,7 +10201,6 @@
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
"dev": true, "dev": true,
"peer": true,
"bin": { "bin": {
"jiti": "lib/jiti-cli.mjs" "jiti": "lib/jiti-cli.mjs"
} }
@@ -10300,6 +10297,7 @@
"node_modules/json5": { "node_modules/json5": {
"version": "2.2.3", "version": "2.2.3",
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"json5": "lib/cli.js" "json5": "lib/cli.js"
}, },
@@ -13129,7 +13127,6 @@
"integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
"devOptional": true, "devOptional": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"playwright-core": "cli.js" "playwright-core": "cli.js"
}, },
@@ -13193,7 +13190,6 @@
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"
}, },
@@ -13363,7 +13359,6 @@
"version": "18.3.1", "version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"peer": true,
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0" "loose-envify": "^1.1.0"
}, },
@@ -13384,7 +13379,6 @@
"version": "18.3.1", "version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"peer": true,
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0", "loose-envify": "^1.1.0",
"scheduler": "^0.23.2" "scheduler": "^0.23.2"
@@ -14052,7 +14046,6 @@
"integrity": "sha512-d0NoFH4v6SjEK7BoX810Jsrhj7IQSYHAHLi/iSpgqKc7LaIDshFRlSg5LOymf9FqQhxEHs2W5ZQXlvy0KD45Uw==", "integrity": "sha512-d0NoFH4v6SjEK7BoX810Jsrhj7IQSYHAHLi/iSpgqKc7LaIDshFRlSg5LOymf9FqQhxEHs2W5ZQXlvy0KD45Uw==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"chokidar": "^4.0.0", "chokidar": "^4.0.0",
"immutable": "^5.0.2", "immutable": "^5.0.2",
@@ -14975,7 +14968,6 @@
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz", "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz",
"integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==", "integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/helper-module-imports": "^7.0.0", "@babel/helper-module-imports": "^7.0.0",
"@babel/traverse": "^7.4.5", "@babel/traverse": "^7.4.5",
@@ -15222,7 +15214,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@@ -15538,7 +15529,6 @@
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@@ -15886,7 +15876,6 @@
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"napi-postinstall": "^0.2.2" "napi-postinstall": "^0.2.2"
}, },
@@ -16089,7 +16078,6 @@
"integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"esbuild": "^0.25.0", "esbuild": "^0.25.0",
"fdir": "^6.5.0", "fdir": "^6.5.0",
@@ -16198,7 +16186,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },

View File

@@ -19,11 +19,13 @@
"build": "next build --webpack", "build": "next build --webpack",
"check-content-type": "tsx src/workflows/check-content-type.ts", "check-content-type": "tsx src/workflows/check-content-type.ts",
"check-github-github-links": "tsx src/links/scripts/check-github-github-links.ts", "check-github-github-links": "tsx src/links/scripts/check-github-github-links.ts",
"clone-early-access": "./src/early-access/scripts/clone-locally",
"clone-translations": "./src/languages/scripts/clone-translations.sh", "clone-translations": "./src/languages/scripts/clone-translations.sh",
"cmp-files": "tsx src/workflows/cmp-files.ts", "cmp-files": "tsx src/workflows/cmp-files.ts",
"content-changes-table-comment": "tsx src/workflows/content-changes-table-comment.ts", "content-changes-table-comment": "tsx src/workflows/content-changes-table-comment.ts",
"copy-fixture-data": "tsx src/tests/scripts/copy-fixture-data.ts", "copy-fixture-data": "tsx src/tests/scripts/copy-fixture-data.ts",
"count-translation-corruptions": "cross-env NODE_OPTIONS=--max-old-space-size=8192 tsx src/languages/scripts/count-translation-corruptions.ts", "count-translation-corruptions": "cross-env NODE_OPTIONS=--max-old-space-size=8192 tsx src/languages/scripts/count-translation-corruptions.ts",
"create-early-access-branch": "./src/early-access/scripts/create-branch",
"create-enterprise-issue": "tsx src/ghes-releases/scripts/create-enterprise-issue.ts", "create-enterprise-issue": "tsx src/ghes-releases/scripts/create-enterprise-issue.ts",
"cta-builder": "tsx src/content-render/scripts/cta-builder.ts", "cta-builder": "tsx src/content-render/scripts/cta-builder.ts",
"debug": "cross-env NODE_ENV=development ENABLED_LANGUAGES=en nodemon --inspect src/frame/server.ts", "debug": "cross-env NODE_ENV=development ENABLED_LANGUAGES=en nodemon --inspect src/frame/server.ts",
@@ -102,7 +104,8 @@
"validate-asset-images": "tsx src/assets/scripts/validate-asset-images.ts", "validate-asset-images": "tsx src/assets/scripts/validate-asset-images.ts",
"validate-github-github-docs-urls": "tsx src/links/scripts/validate-github-github-docs-urls/index.ts", "validate-github-github-docs-urls": "tsx src/links/scripts/validate-github-github-docs-urls/index.ts",
"warmup-remotejson": "tsx src/archives/scripts/warmup-remotejson.ts", "warmup-remotejson": "tsx src/archives/scripts/warmup-remotejson.ts",
"what-docs-early-access-branch": "tsx src/early-access/scripts/what-docs-early-access-branch.ts" "what-docs-early-access-branch": "tsx src/early-access/scripts/what-docs-early-access-branch.ts",
"writers": "tsx src/workflows/writers-help-metadata.ts"
}, },
"lint-staged": { "lint-staged": {
"*.{ts,tsx}": "eslint --cache --fix", "*.{ts,tsx}": "eslint --cache --fix",

View File

@@ -1,6 +1,8 @@
/** /**
* This script iterates over all pages and all reusables and looks for * @purpose Writer tool
* mentions of variables in Liquid syntax. For example, * @description Look for mentions of variables in Liquid syntax across all pages
*
* For example,
* *
* --- * ---
* title: '{% data variables.product.prodname_mobile %} is cool' * title: '{% data variables.product.prodname_mobile %} is cool'

View File

@@ -1,3 +1,7 @@
/**
* @purpose Writer tool
* @description Run the Docs content linter, specifying paths and optional rules
*/
// @ts-nocheck // @ts-nocheck
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'

View File

@@ -1,7 +1,7 @@
// This script auto-populates the `contentType` frontmatter property based on /**
// the directory location of the content file. * @purpose Writer tool
// Run with: * @description Auto-populate the `contentType` frontmatter property based on the directory location of the content file
// npm run-script -- add-content-type --help */
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'

View File

@@ -1,3 +1,7 @@
/**
* @purpose Writer tool
* @description Create a properly formatted Call-to-Action URL with tracking parameters
*/
import { Command } from 'commander' import { Command } from 'commander'
import readline from 'readline' import readline from 'readline'
import chalk from 'chalk' import chalk from 'chalk'

View File

@@ -1,3 +1,7 @@
/**
* @purpose Writer tool
* @description Move or rename a file or a folder and automatically add redirects
*/
// @ts-nocheck // @ts-nocheck
// [start-readme] // [start-readme]
// //

View File

@@ -1,3 +1,7 @@
/**
* @purpose Writer tool
* @description Find all content files that use a specific reusable
*/
// Usage: npm run reusables -- --help // Usage: npm run reusables -- --help
// Usage: npm run reusables -- find used accounts/create-account.md // Usage: npm run reusables -- find used accounts/create-account.md
// Usage: npm run reusables -- find unused accounts/create-account.md // Usage: npm run reusables -- find unused accounts/create-account.md

View File

@@ -1,10 +1,7 @@
// [start-readme] /**
// * @purpose Writer tool
// Run this script to update filepaths to match short titles (or titles as a fallback). * @description Update content filenames to match short titles
// Use */
// npm run-script -- update-filepaths --help
//
// [end-readme]
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'

View File

@@ -1,5 +1,6 @@
/** /**
* Development tool that generates a local Table of Contents (TOC) for the GitHub Docs website. * @purpose Writer tool
* @description Generate a local table of contents for the GitHub Docs website
* *
* This script creates static HTML files for each documentation version, renders page titles * This script creates static HTML files for each documentation version, renders page titles
* using Liquid templating, and opens the generated TOC in your browser for easy navigation * using Liquid templating, and opens the generated TOC in your browser for easy navigation

View File

@@ -1,10 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# [start-readme] # @purpose Writer tool
# # @description Clone the docs-early-access repo
# This script is run on a writer's machine to begin developing Early Access content locally.
#
# [end-readme]
set -e set -e

View File

@@ -1,10 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# [start-readme] # @purpose Writer tool
# # @description Create matching branches in docs-early-access and docs-internal
# This script is run on a writer's machine to create an Early Access branch that matches the current docs-internal branch.
#
# [end-readme]
set -e set -e

View File

@@ -1,10 +1,7 @@
// [start-readme] /**
// * @purpose Writer tool
// This script is run on a writer's machine while developing Early Access content locally. * @description Create or destroy symlinks to your local docs-early-access checkout
// You must pass the script the location of your local copy of */
// the `github/docs-early-access` git repo as the first argument.
//
// [end-readme]
import { rimraf } from 'rimraf' import { rimraf } from 'rimraf'
import fs from 'fs' import fs from 'fs'

View File

@@ -1,9 +1,7 @@
// [start-readme] /**
// * @purpose Writer tool
// This script is run on a writer's machine while developing Early Access content locally. It * @description Add or remove "early-access" from data and image paths
// updates the data and image paths to either include `early-access` or remove it. */
//
// [end-readme]
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'

View File

@@ -1,3 +1,8 @@
/**
* @purpose Writer tool
* @description Get data about a top-level docs product and output a CSV
*/
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
import { fileURLToPath } from 'url' import { fileURLToPath } from 'url'

View File

@@ -1,3 +1,8 @@
/**
* @purpose Writer tool
* @description Get a data snapshot of a given Docs URL for the last 30 days or specified period
*/
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
import { Command } from 'commander' import { Command } from 'commander'

View File

@@ -0,0 +1,215 @@
#!/usr/bin/env tsx
import { readFileSync } from 'fs'
import { glob } from 'glob'
import path from 'path'
import { fileURLToPath } from 'url'
const __scriptname = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__scriptname)
const PURPOSE_STRING = '@purpose Writer tool'
const DESCRIPTION_STRING = '@description'
const DESCRIPTION_REGEX = new RegExp(`${DESCRIPTION_STRING}\\s+(.+)`)
interface WriterTool {
name: string
description: string
priority?: number // Lower numbers = higher priority
}
interface WriterToolsCollection {
[category: string]: WriterTool[]
}
interface ScriptMetadata {
isWriterTool?: boolean
category?: string
description?: string
}
// Manual entries for scripts that aren't TypeScript files with metadata
const MANUAL_ENTRIES: WriterToolsCollection = {
'Validation and formatting': [
{ name: 'prettier', description: 'Format markdown, YAML, and other files' },
],
Development: [
{ name: 'dev', description: 'Start local development server' },
{ name: 'build', description: 'Build the application' },
],
}
async function discoverWriterTools(): Promise<WriterToolsCollection> {
const packageJsonPath = path.join(__dirname, '..', '..', 'package.json')
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
const tools: WriterToolsCollection = { ...MANUAL_ENTRIES } // Start with manual entries
// First get all files
const allFiles = await glob('src/**/*', {
cwd: path.join(__dirname, '..', '..'),
absolute: true,
ignore: ['**/node_modules/**', '**/tests/**', '**/test/**', '**/.*'],
})
// Then filter for .ts, .js, .sh scripts
const scriptFiles = allFiles.filter((file) => {
if (file === __scriptname) return false // skip the current file
const ext = path.extname(file)
if (['.ts', '.js', '.sh'].includes(ext)) return true
// For extensionless files, check if they're executable or have shebang
if (ext === '') {
try {
const content = readFileSync(file, 'utf8')
return content.startsWith('#!/bin/bash') || content.startsWith('#!/usr/bin/env bash')
} catch {
return false
}
}
return false
})
for (const filePath of scriptFiles) {
try {
const relativePath = path.relative(process.cwd(), filePath)
const content = readFileSync(filePath, 'utf8')
const metadata = extractMetadata(content)
if (metadata.isWriterTool) {
metadata.category = getCategory(relativePath)
// Find corresponding npm script
const scriptName = findScriptName(packageJson.scripts, relativePath)
if (scriptName) {
if (!tools[metadata.category]) tools[metadata.category] = []
// Check if not already added manually
const exists = tools[metadata.category].some((tool) => tool.name === scriptName)
if (!exists) {
tools[metadata.category].push({
name: scriptName,
description: metadata.description || `${scriptName} tool`,
})
}
}
}
} catch {
// Skip files that can't be read
continue
}
}
return tools
}
function extractMetadata(content: string): ScriptMetadata {
const metadata: ScriptMetadata = {}
const lines = content.split('\n').slice(0, 20) // Only check first 20 lines
for (const line of lines) {
if (line.includes(PURPOSE_STRING)) {
metadata.isWriterTool = true
}
if (line.includes(DESCRIPTION_STRING)) {
// Extract description from line like "@description Add content type frontmatter to articles"
const match = line.match(DESCRIPTION_REGEX)
if (match) {
metadata.description = match[1].trim()
}
}
}
return metadata
}
// Convert the DIR in src/DIR/ to a title-cased category name
// E.g. src/secret-scanning becomes Secret Scanning
function getCategory(relativePath: string): string {
const directory = relativePath.split(path.sep)[1]
const category = directory
.split('-')
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
.join(' ')
// Clarify this one category
return category.replace('Content Render', 'Content Tasks')
}
function findScriptName(scripts: Record<string, string>, relativePath: string): string | null {
for (const [scriptName, command] of Object.entries(scripts)) {
// Check if the command includes this file path
if (command.includes(relativePath)) {
return scriptName
}
// Also check for simplified paths without the src/ prefix
const simplifiedPath = relativePath.replace(/^src\//, '')
if (command.includes(simplifiedPath)) {
return scriptName
}
}
return null
}
function prioritizeOrder(tools: WriterToolsCollection) {
// Define priorities for specific tools
const priorities = {
'move-content': 1,
'cta-builder': 2,
'lint-content': 1,
docstat: 1,
dev: 1,
}
// Assign priorities to discovered tools
Object.values(tools)
.flat()
.forEach((tool) => {
if (priorities[tool.name as keyof typeof priorities]) {
tool.priority = priorities[tool.name as keyof typeof priorities]
}
})
// Sort each category by priority, then alphabetically
Object.keys(tools).forEach((category) => {
tools[category].sort((a, b) => {
// Items with priority come first
if (a.priority !== undefined && b.priority === undefined) return -1
if (a.priority === undefined && b.priority !== undefined) return 1
// Both have priority: sort by priority value
if (a.priority !== undefined && b.priority !== undefined) {
return a.priority - b.priority
}
// Neither has priority: sort alphabetically
return a.name.localeCompare(b.name)
})
})
return tools
}
async function main(): Promise<void> {
console.log('For more info, run a command with "-- --help".\n')
const tools = prioritizeOrder(await discoverWriterTools())
Object.entries(tools).forEach(([category, scripts]) => {
console.log(`${category}:`)
scripts.forEach((script) => {
const padding = ' '.repeat(Math.max(0, 34 - script.name.length))
console.log(` npm run ${script.name}${padding}# ${script.description}`)
})
console.log('')
})
}
if (import.meta.url === `file://${process.argv[1]}`) {
try {
await main()
} catch (error) {
console.error(error)
process.exit(1)
}
}