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:
45
package-lock.json
generated
45
package-lock.json
generated
@@ -240,7 +240,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz",
|
||||
"integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^4.0.0",
|
||||
"@octokit/graphql": "^7.1.0",
|
||||
@@ -401,6 +400,7 @@
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
@@ -586,6 +586,7 @@
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz",
|
||||
"integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -623,12 +624,14 @@
|
||||
"node_modules/@babel/core/node_modules/convert-source-map": {
|
||||
"version": "2.0.0",
|
||||
"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": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -662,6 +665,7 @@
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz",
|
||||
"integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.22.9",
|
||||
"@babel/helper-validator-option": "^7.22.15",
|
||||
@@ -677,6 +681,7 @@
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"yallist": "^3.0.2"
|
||||
}
|
||||
@@ -685,6 +690,7 @@
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -692,7 +698,8 @@
|
||||
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
|
||||
"version": "3.1.1",
|
||||
"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": {
|
||||
"version": "7.22.20",
|
||||
@@ -740,6 +747,7 @@
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz",
|
||||
"integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-module-imports": "^7.22.15",
|
||||
@@ -766,6 +774,7 @@
|
||||
"version": "7.22.5",
|
||||
"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==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
@@ -804,6 +813,7 @@
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz",
|
||||
"integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -812,6 +822,7 @@
|
||||
"version": "7.26.10",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz",
|
||||
"integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.26.9",
|
||||
"@babel/types": "^7.26.10"
|
||||
@@ -2695,7 +2706,6 @@
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.2.tgz",
|
||||
"integrity": "sha512-ODsoD39Lq6vR6aBgvjTnA3nZGliknKboc9Gtxr7E4WDNqY24MxANKcuDQSF0jzapvGb3KWOEDrKfve4HoWGK+g==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^6.0.0",
|
||||
"@octokit/graphql": "^9.0.1",
|
||||
@@ -3343,7 +3353,6 @@
|
||||
"integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"playwright": "1.56.1"
|
||||
},
|
||||
@@ -4155,7 +4164,6 @@
|
||||
"integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/body-parser": "*",
|
||||
"@types/express-serve-static-core": "^5.0.0",
|
||||
@@ -4317,7 +4325,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz",
|
||||
"integrity": "sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.0.2"
|
||||
@@ -4329,7 +4336,6 @@
|
||||
"integrity": "sha512-nf22//wEbKXusP6E9pfOCDwFdHAX4u172eaJI4YkDRQEZiorm6KfYnSC2SWLDMVWUOWPERmJnN0ujeAfTBLvrw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.0.0"
|
||||
}
|
||||
@@ -4500,7 +4506,6 @@
|
||||
"integrity": "sha512-pUXGCuHnnKw6PyYq93lLRiZm3vjuslIy7tus1lIQTYVK9bL8XBgJnCWm8a0KcTtHC84Yya1Q6rtll+duSMj0dg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.39.1",
|
||||
"@typescript-eslint/types": "8.39.1",
|
||||
@@ -5139,7 +5144,6 @@
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -5169,7 +5173,6 @@
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
@@ -5669,7 +5672,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001733",
|
||||
"electron-to-chromium": "^1.5.199",
|
||||
@@ -5920,7 +5922,6 @@
|
||||
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
|
||||
"integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cheerio-select": "^2.1.0",
|
||||
"dom-serializer": "^2.0.0",
|
||||
@@ -7142,7 +7143,6 @@
|
||||
"integrity": "sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
@@ -7204,7 +7204,6 @@
|
||||
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
},
|
||||
@@ -7463,7 +7462,6 @@
|
||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.9",
|
||||
@@ -8623,6 +8621,7 @@
|
||||
"node_modules/gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -8828,7 +8827,6 @@
|
||||
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz",
|
||||
"integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"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",
|
||||
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
@@ -10300,6 +10297,7 @@
|
||||
"node_modules/json5": {
|
||||
"version": "2.2.3",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
},
|
||||
@@ -13129,7 +13127,6 @@
|
||||
"integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
@@ -13193,7 +13190,6 @@
|
||||
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -13363,7 +13359,6 @@
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
@@ -13384,7 +13379,6 @@
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
@@ -14052,7 +14046,6 @@
|
||||
"integrity": "sha512-d0NoFH4v6SjEK7BoX810Jsrhj7IQSYHAHLi/iSpgqKc7LaIDshFRlSg5LOymf9FqQhxEHs2W5ZQXlvy0KD45Uw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"chokidar": "^4.0.0",
|
||||
"immutable": "^5.0.2",
|
||||
@@ -14975,7 +14968,6 @@
|
||||
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz",
|
||||
"integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-module-imports": "^7.0.0",
|
||||
"@babel/traverse": "^7.4.5",
|
||||
@@ -15222,7 +15214,6 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -15538,7 +15529,6 @@
|
||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -15886,7 +15876,6 @@
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"napi-postinstall": "^0.2.2"
|
||||
},
|
||||
@@ -16089,7 +16078,6 @@
|
||||
"integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -16198,7 +16186,6 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
||||
@@ -19,11 +19,13 @@
|
||||
"build": "next build --webpack",
|
||||
"check-content-type": "tsx src/workflows/check-content-type.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",
|
||||
"cmp-files": "tsx src/workflows/cmp-files.ts",
|
||||
"content-changes-table-comment": "tsx src/workflows/content-changes-table-comment.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",
|
||||
"create-early-access-branch": "./src/early-access/scripts/create-branch",
|
||||
"create-enterprise-issue": "tsx src/ghes-releases/scripts/create-enterprise-issue.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",
|
||||
@@ -102,7 +104,8 @@
|
||||
"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",
|
||||
"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": {
|
||||
"*.{ts,tsx}": "eslint --cache --fix",
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* This script iterates over all pages and all reusables and looks for
|
||||
* mentions of variables in Liquid syntax. For example,
|
||||
* @purpose Writer tool
|
||||
* @description Look for mentions of variables in Liquid syntax across all pages
|
||||
*
|
||||
* For example,
|
||||
*
|
||||
* ---
|
||||
* title: '{% data variables.product.prodname_mobile %} is cool'
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* @purpose Writer tool
|
||||
* @description Run the Docs content linter, specifying paths and optional rules
|
||||
*/
|
||||
// @ts-nocheck
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This script auto-populates the `contentType` frontmatter property based on
|
||||
// the directory location of the content file.
|
||||
// Run with:
|
||||
// npm run-script -- add-content-type --help
|
||||
/**
|
||||
* @purpose Writer tool
|
||||
* @description Auto-populate the `contentType` frontmatter property based on the directory location of the content file
|
||||
*/
|
||||
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* @purpose Writer tool
|
||||
* @description Create a properly formatted Call-to-Action URL with tracking parameters
|
||||
*/
|
||||
import { Command } from 'commander'
|
||||
import readline from 'readline'
|
||||
import chalk from 'chalk'
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* @purpose Writer tool
|
||||
* @description Move or rename a file or a folder and automatically add redirects
|
||||
*/
|
||||
// @ts-nocheck
|
||||
// [start-readme]
|
||||
//
|
||||
|
||||
@@ -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 -- find used accounts/create-account.md
|
||||
// Usage: npm run reusables -- find unused accounts/create-account.md
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
// [start-readme]
|
||||
//
|
||||
// Run this script to update filepaths to match short titles (or titles as a fallback).
|
||||
// Use
|
||||
// npm run-script -- update-filepaths --help
|
||||
//
|
||||
// [end-readme]
|
||||
/**
|
||||
* @purpose Writer tool
|
||||
* @description Update content filenames to match short titles
|
||||
*/
|
||||
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
@@ -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
|
||||
* using Liquid templating, and opens the generated TOC in your browser for easy navigation
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# [start-readme]
|
||||
#
|
||||
# This script is run on a writer's machine to begin developing Early Access content locally.
|
||||
#
|
||||
# [end-readme]
|
||||
# @purpose Writer tool
|
||||
# @description Clone the docs-early-access repo
|
||||
|
||||
set -e
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# [start-readme]
|
||||
#
|
||||
# This script is run on a writer's machine to create an Early Access branch that matches the current docs-internal branch.
|
||||
#
|
||||
# [end-readme]
|
||||
# @purpose Writer tool
|
||||
# @description Create matching branches in docs-early-access and docs-internal
|
||||
|
||||
set -e
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
// [start-readme]
|
||||
//
|
||||
// This script is run on a writer's machine while developing Early Access content locally.
|
||||
// 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]
|
||||
/**
|
||||
* @purpose Writer tool
|
||||
* @description Create or destroy symlinks to your local docs-early-access checkout
|
||||
*/
|
||||
|
||||
import { rimraf } from 'rimraf'
|
||||
import fs from 'fs'
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// [start-readme]
|
||||
//
|
||||
// This script is run on a writer's machine while developing Early Access content locally. It
|
||||
// updates the data and image paths to either include `early-access` or remove it.
|
||||
//
|
||||
// [end-readme]
|
||||
/**
|
||||
* @purpose Writer tool
|
||||
* @description Add or remove "early-access" from data and image paths
|
||||
*/
|
||||
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
@@ -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 path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
@@ -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 path from 'path'
|
||||
import { Command } from 'commander'
|
||||
|
||||
215
src/workflows/writers-help-metadata.ts
Normal file
215
src/workflows/writers-help-metadata.ts
Normal 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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user