feat(planning): grille hebdomadaire complète avec API et filtres
- Connexion API via proxy Angular (résolution CORS, base path /api) - Import CSS ng-zorro global pour les modales et composants - Filtres Camion/Show câblés sur l'affichage de la grille - Camions affichés via TrucksService (linkés au show du même créneau) - Panneau de détails : spectacles + camions du jour sélectionné - Modale de création de spectacle stylisée avec fond et centrage - Positionnement précis des events à la minute dans leur créneau - Auto-scroll vers l'heure courante au chargement - Ligne "maintenant" sur la colonne du jour actuel - Régénération des services OpenAPI (nouveaux noms de types) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+3
-17
@@ -144,10 +144,6 @@ Like `normalize` but intended for preparing package.json files for publish.
|
||||
|
||||
---
|
||||
|
||||
### `PackageJson.syncNormalize()`
|
||||
|
||||
This calls normalize synchronously. Most consumers of this package should avoid using this. It was added because some parts of npm were normalizing package content in class constructors and needed this affordance. It will silently ignore any asynchronous steps asked for. Again, this is a compatiblity affordance for some code in npm that is currently impossible to change without a significant semver major change, and is best not used.
|
||||
|
||||
### **static** `async PackageJson.prepare(path, opts = {})`
|
||||
|
||||
Convenience static that calls `load` before calling `prepare`
|
||||
@@ -237,20 +233,10 @@ pkgJson.content
|
||||
|
||||
---
|
||||
|
||||
### `async PackageJson.save([options])`
|
||||
### `async PackageJson.save()`
|
||||
|
||||
|
||||
Saves the current `content` to the same location used when calling `load()`.
|
||||
|
||||
- `options`: `Object` (optional)
|
||||
- `sort`: `Boolean` (optional) — If true, sorts the keys in the resulting `package.json` file for consistency and readability.
|
||||
|
||||
> [!NOTE]
|
||||
> The sort order for `package.json` is based on the conventions from
|
||||
> [sort-package-json](https://github.com/keithamus/sort-package-json/blob/main/defaultRules.md),
|
||||
> cross-checked with the official npm types and documentation:
|
||||
> - https://github.com/npm/types/blob/main/types/index.d.ts#L104
|
||||
> - https://docs.npmjs.com/cli/configuring-npm/package-json
|
||||
Saves the current `content` to the same location used when calling
|
||||
`load()`.
|
||||
|
||||
## LICENSE
|
||||
|
||||
|
||||
+16
-26
@@ -5,7 +5,7 @@ const parseJSON = require('json-parse-even-better-errors')
|
||||
const updateDeps = require('./update-dependencies.js')
|
||||
const updateScripts = require('./update-scripts.js')
|
||||
const updateWorkspaces = require('./update-workspaces.js')
|
||||
const { normalize, syncNormalize } = require('./normalize.js')
|
||||
const normalize = require('./normalize.js')
|
||||
const { read, parse } = require('./read-package.js')
|
||||
const { packageSort } = require('./sort.js')
|
||||
|
||||
@@ -25,18 +25,6 @@ const knownKeys = new Set([
|
||||
])
|
||||
|
||||
class PackageJson {
|
||||
// npm pkg fix
|
||||
static fixSteps = Object.freeze([
|
||||
'binRefs',
|
||||
'bundleDependencies',
|
||||
'fixName',
|
||||
'fixVersionField',
|
||||
'fixRepositoryField',
|
||||
'fixDependencies',
|
||||
'devDependencies',
|
||||
'scriptpath',
|
||||
])
|
||||
|
||||
static normalizeSteps = Object.freeze([
|
||||
'_id',
|
||||
'_attributes',
|
||||
@@ -46,7 +34,20 @@ class PackageJson {
|
||||
'scripts',
|
||||
'funding',
|
||||
'bin',
|
||||
'binDir',
|
||||
])
|
||||
|
||||
// npm pkg fix
|
||||
static fixSteps = Object.freeze([
|
||||
'binRefs',
|
||||
'bundleDependencies',
|
||||
'bundleDependenciesFalse',
|
||||
'fixName',
|
||||
'fixNameField',
|
||||
'fixVersionField',
|
||||
'fixRepositoryField',
|
||||
'fixDependencies',
|
||||
'devDependencies',
|
||||
'scriptpath',
|
||||
])
|
||||
|
||||
static prepareSteps = Object.freeze([
|
||||
@@ -163,11 +164,7 @@ class PackageJson {
|
||||
return this
|
||||
}
|
||||
|
||||
// Manually set data from an existing object
|
||||
fromContent (data) {
|
||||
if (!data || typeof data !== 'object') {
|
||||
throw new Error('Content data must be an object')
|
||||
}
|
||||
this.#manifest = data
|
||||
this.#canSave = false
|
||||
return this
|
||||
@@ -225,7 +222,7 @@ class PackageJson {
|
||||
this.#manifest = step({ content, originalContent: this.content })
|
||||
}
|
||||
|
||||
// unknown properties will just be overwritten
|
||||
// unknown properties will just be overwitten
|
||||
for (const [key, value] of Object.entries(content)) {
|
||||
if (!knownKeys.has(key)) {
|
||||
this.content[key] = value
|
||||
@@ -262,13 +259,6 @@ class PackageJson {
|
||||
}
|
||||
}
|
||||
|
||||
// steps is NOT overrideable here because this is a legacy function that's not being used in new places
|
||||
syncNormalize (opts = {}) {
|
||||
opts.steps = this.constructor.normalizeSteps.filter(s => s !== '_attributes')
|
||||
syncNormalize(this, opts)
|
||||
return this
|
||||
}
|
||||
|
||||
async normalize (opts = {}) {
|
||||
if (!opts.steps) {
|
||||
opts.steps = this.constructor.normalizeSteps
|
||||
|
||||
+9
-6
@@ -1,8 +1,8 @@
|
||||
// Originally normalize-package-data
|
||||
|
||||
const { URL } = require('node:url')
|
||||
const url = require('node:url')
|
||||
const hostedGitInfo = require('hosted-git-info')
|
||||
const validateLicense = require('./license.js')
|
||||
const validateLicense = require('validate-npm-package-license')
|
||||
|
||||
const typos = {
|
||||
dependancies: 'dependencies',
|
||||
@@ -123,7 +123,8 @@ function normalizeData (data, changes) {
|
||||
if (typeof data.bugs === 'string') {
|
||||
if (isEmail(data.bugs)) {
|
||||
data.bugs = { email: data.bugs }
|
||||
} else if (URL.canParse(data.bugs)) {
|
||||
/* eslint-disable-next-line node/no-deprecated-api */
|
||||
} else if (url.parse(data.bugs).protocol) {
|
||||
data.bugs = { url: data.bugs }
|
||||
} else {
|
||||
changes?.push(`Bug string field must be url, email, or {email,url}`)
|
||||
@@ -139,7 +140,8 @@ function normalizeData (data, changes) {
|
||||
const oldBugs = data.bugs
|
||||
data.bugs = {}
|
||||
if (oldBugs.url) {
|
||||
if (URL.canParse(oldBugs.url)) {
|
||||
/* eslint-disable-next-line node/no-deprecated-api */
|
||||
if (typeof (oldBugs.url) === 'string' && url.parse(oldBugs.url).protocol) {
|
||||
data.bugs.url = oldBugs.url
|
||||
} else {
|
||||
changes?.push('bugs.url field must be a string url. Deleted.')
|
||||
@@ -214,7 +216,8 @@ function normalizeData (data, changes) {
|
||||
changes?.push('homepage field must be a string url. Deleted.')
|
||||
delete data.homepage
|
||||
} else {
|
||||
if (!URL.canParse(data.homepage)) {
|
||||
/* eslint-disable-next-line node/no-deprecated-api */
|
||||
if (!url.parse(data.homepage).protocol) {
|
||||
data.homepage = 'http://' + data.homepage
|
||||
}
|
||||
}
|
||||
@@ -230,7 +233,7 @@ function normalizeData (data, changes) {
|
||||
changes?.push('No license field.')
|
||||
} else if (typeof (license) !== 'string' || license.length < 1 || license.trim() === '') {
|
||||
changes?.push('license should be a valid SPDX license expression')
|
||||
} else if (!validateLicense(license)) {
|
||||
} else if (!validateLicense(license).validForNewPackages) {
|
||||
changes?.push('license should be a valid SPDX license expression')
|
||||
}
|
||||
// fixPeople
|
||||
|
||||
+211
-224
@@ -67,7 +67,7 @@ function normalizePackageBin (pkg, changes) {
|
||||
changes?.push(`"bin[${binKey}]" was renamed to "bin[${base}]"`)
|
||||
}
|
||||
if (binTarget !== pkg.bin[binKey]) {
|
||||
changes?.push(`"bin[${base}]" script name ${binTarget} was invalid and removed`)
|
||||
changes?.push(`"bin[${base}]" script name was cleaned`)
|
||||
}
|
||||
pkg.bin[base] = binTarget
|
||||
}
|
||||
@@ -133,9 +133,15 @@ function secureAndUnixifyPath (ref) {
|
||||
return secured.startsWith('./') ? '' : secured
|
||||
}
|
||||
|
||||
// Only steps that can be ran synchronously. There are some object constructors (i.e. Aborist Node) that need synchronous normalization so here we are.
|
||||
function syncSteps (pkg, { strict, steps, changes, allowLegacyCase }) {
|
||||
// We don't want the `changes` array in here by default because this is a hot
|
||||
// path for parsing packuments during install. So the calling method passes it
|
||||
// in if it wants to track changes.
|
||||
const normalize = async (pkg, { strict, steps, root, changes, allowLegacyCase }) => {
|
||||
if (!pkg.content) {
|
||||
throw new Error('Can not normalize without content')
|
||||
}
|
||||
const data = pkg.content
|
||||
const scripts = data.scripts || {}
|
||||
const pkgId = `${data.name ?? ''}@${data.version ?? ''}`
|
||||
|
||||
// name and version are load bearing so we have to clean them up first
|
||||
@@ -189,7 +195,6 @@ function syncSteps (pkg, { strict, steps, changes, allowLegacyCase }) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove attributes that start with "_"
|
||||
if (steps.includes('_attributes')) {
|
||||
for (const key in data) {
|
||||
@@ -209,14 +214,14 @@ function syncSteps (pkg, { strict, steps, changes, allowLegacyCase }) {
|
||||
}
|
||||
|
||||
// fix bundledDependencies typo
|
||||
// normalize bundleDependencies
|
||||
if (steps.includes('bundledDependencies')) {
|
||||
if (data.bundleDependencies === undefined && data.bundledDependencies !== undefined) {
|
||||
data.bundleDependencies = data.bundledDependencies
|
||||
changes?.push(`Deleted incorrect "bundledDependencies"`)
|
||||
}
|
||||
changes?.push(`Deleted incorrect "bundledDependencies"`)
|
||||
delete data.bundledDependencies
|
||||
}
|
||||
|
||||
// expand "bundleDependencies: true or translate from object"
|
||||
if (steps.includes('bundleDependencies')) {
|
||||
const bd = data.bundleDependencies
|
||||
@@ -255,6 +260,32 @@ function syncSteps (pkg, { strict, steps, changes, allowLegacyCase }) {
|
||||
}
|
||||
}
|
||||
|
||||
// add "install" attribute if any "*.gyp" files exist
|
||||
if (steps.includes('gypfile')) {
|
||||
if (!scripts.install && !scripts.preinstall && data.gypfile !== false) {
|
||||
const files = await lazyLoadGlob()('*.gyp', { cwd: pkg.path })
|
||||
if (files.length) {
|
||||
scripts.install = 'node-gyp rebuild'
|
||||
data.scripts = scripts
|
||||
data.gypfile = true
|
||||
changes?.push(`"scripts.install" was set to "node-gyp rebuild"`)
|
||||
changes?.push(`"gypfile" was set to "true"`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add "start" attribute if "server.js" exists
|
||||
if (steps.includes('serverjs') && !scripts.start) {
|
||||
try {
|
||||
await fs.access(path.join(pkg.path, 'server.js'))
|
||||
scripts.start = 'node server.js'
|
||||
data.scripts = scripts
|
||||
changes?.push('"scripts.start" was set to "node server.js"')
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
// strip "node_modules/.bin" from scripts entries
|
||||
// remove invalid scripts entries (non-strings)
|
||||
if ((steps.includes('scripts') || steps.includes('scriptpath')) && data.scripts !== undefined) {
|
||||
@@ -282,6 +313,179 @@ function syncSteps (pkg, { strict, steps, changes, allowLegacyCase }) {
|
||||
}
|
||||
}
|
||||
|
||||
// populate "authors" attribute
|
||||
if (steps.includes('authors') && !data.contributors) {
|
||||
try {
|
||||
const authorData = await fs.readFile(path.join(pkg.path, 'AUTHORS'), 'utf8')
|
||||
const authors = authorData.split(/\r?\n/g)
|
||||
.map(line => line.replace(/^\s*#.*$/, '').trim())
|
||||
.filter(line => line)
|
||||
data.contributors = authors
|
||||
changes?.push('"contributors" was auto-populated with the contents of the "AUTHORS" file')
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
// populate "readme" attribute
|
||||
if (steps.includes('readme') && !data.readme) {
|
||||
const mdre = /\.m?a?r?k?d?o?w?n?$/i
|
||||
const files = await lazyLoadGlob()('{README,README.*}', {
|
||||
cwd: pkg.path,
|
||||
nocase: true,
|
||||
mark: true,
|
||||
})
|
||||
let readmeFile
|
||||
for (const file of files) {
|
||||
// don't accept directories.
|
||||
if (!file.endsWith(path.sep)) {
|
||||
if (file.match(mdre)) {
|
||||
readmeFile = file
|
||||
break
|
||||
}
|
||||
if (file.endsWith('README')) {
|
||||
readmeFile = file
|
||||
}
|
||||
}
|
||||
}
|
||||
if (readmeFile) {
|
||||
const readmeData = await fs.readFile(path.join(pkg.path, readmeFile), 'utf8')
|
||||
data.readme = readmeData
|
||||
data.readmeFilename = readmeFile
|
||||
changes?.push(`"readme" was set to the contents of ${readmeFile}`)
|
||||
changes?.push(`"readmeFilename" was set to ${readmeFile}`)
|
||||
}
|
||||
if (!data.readme) {
|
||||
data.readme = 'ERROR: No README data found!'
|
||||
}
|
||||
}
|
||||
|
||||
// expand directories.man
|
||||
if (steps.includes('mans')) {
|
||||
if (data.directories?.man && !data.man) {
|
||||
const manDir = secureAndUnixifyPath(data.directories.man)
|
||||
const cwd = path.resolve(pkg.path, manDir)
|
||||
const files = await lazyLoadGlob()('**/*.[0-9]', { cwd })
|
||||
data.man = files.map(man =>
|
||||
path.relative(pkg.path, path.join(cwd, man)).split(path.sep).join('/')
|
||||
)
|
||||
}
|
||||
normalizePackageMan(data, changes)
|
||||
}
|
||||
|
||||
if (steps.includes('bin') || steps.includes('binDir') || steps.includes('binRefs')) {
|
||||
normalizePackageBin(data, changes)
|
||||
}
|
||||
|
||||
// expand "directories.bin"
|
||||
if (steps.includes('binDir') && data.directories?.bin && !data.bin) {
|
||||
const binsDir = path.resolve(pkg.path, secureAndUnixifyPath(data.directories.bin))
|
||||
const bins = await lazyLoadGlob()('**', { cwd: binsDir })
|
||||
data.bin = bins.reduce((acc, binFile) => {
|
||||
if (binFile && !binFile.startsWith('.')) {
|
||||
const binName = path.basename(binFile)
|
||||
acc[binName] = path.join(data.directories.bin, binFile)
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
// *sigh*
|
||||
normalizePackageBin(data, changes)
|
||||
}
|
||||
|
||||
// populate "gitHead" attribute
|
||||
if (steps.includes('gitHead') && !data.gitHead) {
|
||||
const git = require('@npmcli/git')
|
||||
const gitRoot = await git.find({ cwd: pkg.path, root })
|
||||
let head
|
||||
if (gitRoot) {
|
||||
try {
|
||||
head = await fs.readFile(path.resolve(gitRoot, '.git/HEAD'), 'utf8')
|
||||
} catch (err) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
let headData
|
||||
if (head) {
|
||||
if (head.startsWith('ref: ')) {
|
||||
const headRef = head.replace(/^ref: /, '').trim()
|
||||
const headFile = path.resolve(gitRoot, '.git', headRef)
|
||||
try {
|
||||
headData = await fs.readFile(headFile, 'utf8')
|
||||
headData = headData.replace(/^ref: /, '').trim()
|
||||
} catch (err) {
|
||||
// do nothing
|
||||
}
|
||||
if (!headData) {
|
||||
const packFile = path.resolve(gitRoot, '.git/packed-refs')
|
||||
try {
|
||||
let refs = await fs.readFile(packFile, 'utf8')
|
||||
if (refs) {
|
||||
refs = refs.split('\n')
|
||||
for (let i = 0; i < refs.length; i++) {
|
||||
const match = refs[i].match(/^([0-9a-f]{40}) (.+)$/)
|
||||
if (match && match[2].trim() === headRef) {
|
||||
headData = match[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
} else {
|
||||
headData = head.trim()
|
||||
}
|
||||
}
|
||||
if (headData) {
|
||||
data.gitHead = headData
|
||||
}
|
||||
}
|
||||
|
||||
// populate "types" attribute
|
||||
if (steps.includes('fillTypes')) {
|
||||
const index = data.main || 'index.js'
|
||||
|
||||
if (typeof index !== 'string') {
|
||||
throw new TypeError('The "main" attribute must be of type string.')
|
||||
}
|
||||
|
||||
// TODO exports is much more complicated than this in verbose format
|
||||
// We need to support for instance
|
||||
|
||||
// "exports": {
|
||||
// ".": [
|
||||
// {
|
||||
// "default": "./lib/npm.js"
|
||||
// },
|
||||
// "./lib/npm.js"
|
||||
// ],
|
||||
// "./package.json": "./package.json"
|
||||
// },
|
||||
// as well as conditional exports
|
||||
|
||||
// if (data.exports && typeof data.exports === 'string') {
|
||||
// index = data.exports
|
||||
// }
|
||||
|
||||
// if (data.exports && data.exports['.']) {
|
||||
// index = data.exports['.']
|
||||
// if (typeof index !== 'string') {
|
||||
// }
|
||||
// }
|
||||
const extless = path.join(path.dirname(index), path.basename(index, path.extname(index)))
|
||||
const dts = `./${extless}.d.ts`
|
||||
const hasDTSFields = 'types' in data || 'typings' in data
|
||||
if (!hasDTSFields) {
|
||||
try {
|
||||
await fs.access(path.join(pkg.path, dts))
|
||||
data.types = dts.split(path.sep).join('/')
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "normalizeData" from "read-package-json", which was just a call through to
|
||||
// "normalize-package-data". We only call the "fixer" functions because
|
||||
// outside of that it was also clobbering _id (which we already conditionally
|
||||
@@ -379,209 +583,6 @@ function syncSteps (pkg, { strict, steps, changes, allowLegacyCase }) {
|
||||
const { normalizeData } = require('./normalize-data.js')
|
||||
normalizeData(data, changes)
|
||||
}
|
||||
}
|
||||
|
||||
// Steps that require await, distinct from sync-steps.js
|
||||
async function asyncSteps (pkg, { steps, root, changes }) {
|
||||
const data = pkg.content
|
||||
const scripts = data.scripts || {}
|
||||
const pkgId = `${data.name ?? ''}@${data.version ?? ''}`
|
||||
|
||||
// add "install" attribute if any "*.gyp" files exist
|
||||
if (steps.includes('gypfile')) {
|
||||
if (!scripts.install && !scripts.preinstall && data.gypfile !== false) {
|
||||
const files = await lazyLoadGlob()('*.gyp', { cwd: pkg.path })
|
||||
if (files.length) {
|
||||
scripts.install = 'node-gyp rebuild'
|
||||
data.scripts = scripts
|
||||
data.gypfile = true
|
||||
changes?.push(`"scripts.install" was set to "node-gyp rebuild"`)
|
||||
changes?.push(`"gypfile" was set to "true"`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add "start" attribute if "server.js" exists
|
||||
if (steps.includes('serverjs') && !scripts.start) {
|
||||
try {
|
||||
await fs.access(path.join(pkg.path, 'server.js'))
|
||||
scripts.start = 'node server.js'
|
||||
data.scripts = scripts
|
||||
changes?.push('"scripts.start" was set to "node server.js"')
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
// populate "authors" attribute
|
||||
if (steps.includes('authors') && !data.contributors) {
|
||||
try {
|
||||
const authorData = await fs.readFile(path.join(pkg.path, 'AUTHORS'), 'utf8')
|
||||
const authors = authorData.split(/\r?\n/g)
|
||||
.map(line => line.replace(/^\s*#.*$/, '').trim())
|
||||
.filter(line => line)
|
||||
data.contributors = authors
|
||||
changes?.push('"contributors" was auto-populated with the contents of the "AUTHORS" file')
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
// populate "readme" attribute
|
||||
if (steps.includes('readme') && !data.readme) {
|
||||
const mdre = /\.m?a?r?k?d?o?w?n?$/i
|
||||
const files = await lazyLoadGlob()('{README,README.*}', {
|
||||
cwd: pkg.path,
|
||||
nocase: true,
|
||||
mark: true,
|
||||
})
|
||||
let readmeFile
|
||||
for (const file of files) {
|
||||
// don't accept directories.
|
||||
if (!file.endsWith(path.sep)) {
|
||||
if (file.match(mdre)) {
|
||||
readmeFile = file
|
||||
break
|
||||
}
|
||||
if (file.endsWith('README')) {
|
||||
readmeFile = file
|
||||
}
|
||||
}
|
||||
}
|
||||
if (readmeFile) {
|
||||
const readmeData = await fs.readFile(path.join(pkg.path, readmeFile), 'utf8')
|
||||
data.readme = readmeData
|
||||
data.readmeFilename = readmeFile
|
||||
changes?.push(`"readme" was set to the contents of ${readmeFile}`)
|
||||
changes?.push(`"readmeFilename" was set to ${readmeFile}`)
|
||||
}
|
||||
if (!data.readme) {
|
||||
data.readme = 'ERROR: No README data found!'
|
||||
}
|
||||
}
|
||||
|
||||
// expand directories.man
|
||||
if (steps.includes('mans')) {
|
||||
if (data.directories?.man && !data.man) {
|
||||
const manDir = secureAndUnixifyPath(data.directories.man)
|
||||
const cwd = path.resolve(pkg.path, manDir)
|
||||
const files = await lazyLoadGlob()('**/*.[0-9]', { cwd })
|
||||
data.man = files.map(man =>
|
||||
path.relative(pkg.path, path.join(cwd, man)).split(path.sep).join('/')
|
||||
)
|
||||
}
|
||||
normalizePackageMan(data, changes)
|
||||
}
|
||||
|
||||
// expand "directories.bin"
|
||||
if (steps.includes('binDir') && data.directories?.bin && !data.bin && pkg.path) {
|
||||
const binPath = secureAndUnixifyPath(data.directories.bin)
|
||||
const bins = await lazyLoadGlob()('**', { cwd: path.resolve(pkg.path, binPath) })
|
||||
data.bin = bins.reduce((acc, binFile) => {
|
||||
if (binFile && !binFile.startsWith('.')) {
|
||||
const binName = path.basename(binFile)
|
||||
// binPath is already cleaned and unixified, no need to path.join here.
|
||||
acc[binName] = `${binPath}/${secureAndUnixifyPath(binFile)}`
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
} else if (steps.includes('bin') || steps.includes('binDir') || steps.includes('binRefs')) {
|
||||
normalizePackageBin(data, changes)
|
||||
}
|
||||
|
||||
// populate "gitHead" attribute
|
||||
if (steps.includes('gitHead') && !data.gitHead) {
|
||||
const git = require('@npmcli/git')
|
||||
const gitRoot = await git.find({ cwd: pkg.path, root })
|
||||
let head
|
||||
if (gitRoot) {
|
||||
try {
|
||||
head = await fs.readFile(path.resolve(gitRoot, '.git/HEAD'), 'utf8')
|
||||
} catch (err) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
let headData
|
||||
if (head) {
|
||||
if (head.startsWith('ref: ')) {
|
||||
const headRef = head.replace(/^ref: /, '').trim()
|
||||
const headFile = path.resolve(gitRoot, '.git', headRef)
|
||||
try {
|
||||
headData = await fs.readFile(headFile, 'utf8')
|
||||
headData = headData.replace(/^ref: /, '').trim()
|
||||
} catch (err) {
|
||||
// do nothing
|
||||
}
|
||||
if (!headData) {
|
||||
const packFile = path.resolve(gitRoot, '.git/packed-refs')
|
||||
try {
|
||||
let refs = await fs.readFile(packFile, 'utf8')
|
||||
if (refs) {
|
||||
refs = refs.split('\n')
|
||||
for (let i = 0; i < refs.length; i++) {
|
||||
const match = refs[i].match(/^([0-9a-f]{40}) (.+)$/)
|
||||
if (match && match[2].trim() === headRef) {
|
||||
headData = match[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
} else {
|
||||
headData = head.trim()
|
||||
}
|
||||
}
|
||||
if (headData) {
|
||||
data.gitHead = headData
|
||||
}
|
||||
}
|
||||
|
||||
// populate "types" attribute
|
||||
if (steps.includes('fillTypes')) {
|
||||
const index = data.main || 'index.js'
|
||||
|
||||
if (typeof index !== 'string') {
|
||||
throw new TypeError('The "main" attribute must be of type string.')
|
||||
}
|
||||
|
||||
// TODO exports is much more complicated than this in verbose format
|
||||
// We need to support for instance
|
||||
|
||||
// "exports": {
|
||||
// ".": [
|
||||
// {
|
||||
// "default": "./lib/npm.js"
|
||||
// },
|
||||
// "./lib/npm.js"
|
||||
// ],
|
||||
// "./package.json": "./package.json"
|
||||
// },
|
||||
// as well as conditional exports
|
||||
|
||||
// if (data.exports && typeof data.exports === 'string') {
|
||||
// index = data.exports
|
||||
// }
|
||||
|
||||
// if (data.exports && data.exports['.']) {
|
||||
// index = data.exports['.']
|
||||
// if (typeof index !== 'string') {
|
||||
// }
|
||||
// }
|
||||
const extless = path.join(path.dirname(index), path.basename(index, path.extname(index)))
|
||||
const dts = `./${extless}.d.ts`
|
||||
const hasDTSFields = 'types' in data || 'typings' in data
|
||||
if (!hasDTSFields) {
|
||||
try {
|
||||
await fs.access(path.join(pkg.path, dts))
|
||||
data.types = dts.split(path.sep).join('/')
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Warn if the bin references don't point to anything. This might be better
|
||||
// in normalize-package-data if it had access to the file path.
|
||||
@@ -597,18 +598,4 @@ async function asyncSteps (pkg, { steps, root, changes }) {
|
||||
}
|
||||
}
|
||||
|
||||
// We don't want the `changes` array in here by default because this is a hot path for parsing packuments during install. The calling method passes it in if it wants to track changes.
|
||||
async function normalize (pkg, opts) {
|
||||
if (!pkg.content) {
|
||||
throw new Error('Can not normalize without content')
|
||||
}
|
||||
await asyncSteps(pkg, opts)
|
||||
// the normalizeData part of this needs to be the last thing ran, so sync comes second
|
||||
syncSteps(pkg, opts)
|
||||
}
|
||||
|
||||
function syncNormalize (pkg, opts) {
|
||||
syncSteps(pkg, opts)
|
||||
}
|
||||
|
||||
module.exports = { normalize, syncNormalize }
|
||||
module.exports = normalize
|
||||
|
||||
+13
-11
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@npmcli/package-json",
|
||||
"version": "7.0.5",
|
||||
"version": "6.2.0",
|
||||
"description": "Programmatic API to update package.json",
|
||||
"keywords": [
|
||||
"npm",
|
||||
@@ -29,25 +29,27 @@
|
||||
"eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@npmcli/git": "^7.0.0",
|
||||
"glob": "^13.0.0",
|
||||
"hosted-git-info": "^9.0.0",
|
||||
"json-parse-even-better-errors": "^5.0.0",
|
||||
"proc-log": "^6.0.0",
|
||||
"@npmcli/git": "^6.0.0",
|
||||
"glob": "^10.2.2",
|
||||
"hosted-git-info": "^8.0.0",
|
||||
"json-parse-even-better-errors": "^4.0.0",
|
||||
"proc-log": "^5.0.0",
|
||||
"semver": "^7.5.3",
|
||||
"spdx-expression-parse": "^4.0.0"
|
||||
"validate-npm-package-license": "^3.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@npmcli/eslint-config": "^6.0.0",
|
||||
"@npmcli/template-oss": "4.28.1",
|
||||
"@npmcli/eslint-config": "^5.1.0",
|
||||
"@npmcli/template-oss": "4.23.6",
|
||||
"read-package-json": "^7.0.0",
|
||||
"read-package-json-fast": "^4.0.0",
|
||||
"tap": "^16.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
"node": "^18.17.0 || >=20.5.0"
|
||||
},
|
||||
"templateOSS": {
|
||||
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
|
||||
"version": "4.28.1",
|
||||
"version": "4.23.6",
|
||||
"publish": "true"
|
||||
},
|
||||
"tap": {
|
||||
|
||||
Reference in New Issue
Block a user