Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
default-input.js287 linesDownload Raw Back to lib
1/* globals config, dirname, package, basename, yes, prompt */
2
3const fs = require('fs/promises')
4const path = require('path')
5const validateLicense = require('@npmcli/package-json/lib/license')
6const validateName = require('validate-npm-package-name')
7const npa = require('npm-package-arg')
8const semver = require('semver')
9
10// more popular packages should go here, maybe?
11const testPkgs = [
12  'coco',
13  'coffee-script',
14  'expresso',
15  'jasmine',
16  'jest',
17  'mocha',
18  'streamline',
19  'tap',
20]
21const isTestPkg = p => testPkgs.includes(p)
22
23const invalid = (msg) => Object.assign(new Error(msg), { notValid: true })
24
25const readDeps = (test, excluded) => async () => {
26  const dirs = await fs.readdir('node_modules').catch(() => null)
27
28  if (!dirs) {
29    return
30  }
31
32  const deps = {}
33  for (const dir of dirs) {
34    if (dir.match(/^\./) || test !== isTestPkg(dir) || excluded[dir]) {
35      continue
36    }
37
38    const dp = path.join(dirname, 'node_modules', dir, 'package.json')
39    const p = await fs.readFile(dp, 'utf8').then((d) => JSON.parse(d)).catch(() => null)
40
41    if (!p || !p.version || p?._requiredBy?.some((r) => r === '#USER')) {
42      continue
43    }
44
45    deps[dir] = config.get('save-exact') ? p.version : config.get('save-prefix') + p.version
46  }
47
48  return deps
49}
50
51const getConfig = (key) => {
52  // dots take precedence over dashes
53  const def = config?.defaults?.[`init.${key}`]
54  const val = config.get(`init.${key}`)
55  return (val !== def && val) ? val : config.get(`init-${key.replace(/\./g, '-')}`)
56}
57
58const getName = () => {
59  const rawName = package.name || basename
60  let name = rawName
61    .replace(/^node-|[.-]js$/g, '')
62    .replace(/\s+/g, ' ')
63    .replace(/ /g, '-')
64    .toLowerCase()
65
66  let spec
67  try {
68    spec = npa(name)
69  } catch {
70    spec = {}
71  }
72
73  let scope = config.get('scope')
74
75  if (scope) {
76    if (scope.charAt(0) !== '@') {
77      scope = '@' + scope
78    }
79    if (spec.scope) {
80      name = scope + '/' + spec.name.split('/')[1]
81    } else {
82      name = scope + '/' + name
83    }
84  }
85
86  return name
87}
88
89const name = getName()
90exports.name = yes ? name : prompt('package name', name, (data) => {
91  const its = validateName(data)
92  if (its.validForNewPackages) {
93    return data
94  }
95  const errors = (its.errors || []).concat(its.warnings || [])
96  return invalid(`Sorry, ${errors.join(' and ')}.`)
97})
98
99const version = package.version || getConfig('version') || '1.0.0'
100exports.version = yes ? version : prompt('version', version, (v) => {
101  if (semver.valid(v)) {
102    return v
103  }
104  return invalid(`Invalid version: "${v}"`)
105})
106
107if (!package.description) {
108  exports.description = yes ? '' : prompt('description')
109}
110
111if (!package.main) {
112  exports.main = async () => {
113    const files = await fs.readdir(dirname)
114      .then(list => list.filter((f) => f.match(/\.js$/)))
115      .catch(() => [])
116
117    let index
118    if (files.includes('index.js')) {
119      index = 'index.js'
120    } else if (files.includes('main.js')) {
121      index = 'main.js'
122    } else if (files.includes(basename + '.js')) {
123      index = basename + '.js'
124    } else {
125      index = files[0] || 'index.js'
126    }
127
128    return yes ? index : prompt('entry point', index)
129  }
130}
131
132if (!package.bin) {
133  exports.bin = async () => {
134    try {
135      const d = await fs.readdir(path.resolve(dirname, 'bin'))
136      // just take the first js file we find there, or nada
137      let r = d.find(f => f.match(/\.js$/))
138      if (r) {
139        r = `bin/${r}`
140      }
141      return r
142    } catch {
143      // no bins
144    }
145  }
146}
147
148exports.directories = async () => {
149  const dirs = await fs.readdir(dirname)
150
151  const res = dirs.reduce((acc, d) => {
152    if (/^examples?$/.test(d)) {
153      acc.example = d
154    } else if (/^tests?$/.test(d)) {
155      acc.test = d
156    } else if (/^docs?$/.test(d)) {
157      acc.doc = d
158    } else if (d === 'man') {
159      acc.man = d
160    } else if (d === 'lib') {
161      acc.lib = d
162    }
163
164    return acc
165  }, {})
166
167  return Object.keys(res).length === 0 ? undefined : res
168}
169
170if (!package.dependencies) {
171  exports.dependencies = readDeps(false, package.devDependencies || {})
172}
173
174if (!package.devDependencies) {
175  exports.devDependencies = readDeps(true, package.dependencies || {})
176}
177
178// MUST have a test script!
179if (!package.scripts) {
180  const scripts = package.scripts || {}
181  const notest = 'echo "Error: no test specified" && exit 1'
182  exports.scripts = async () => {
183    const d = await fs.readdir(path.join(dirname, 'node_modules')).catch(() => [])
184
185    // check to see what framework is in use, if any
186    let command
187    if (!scripts.test || scripts.test === notest) {
188      const commands = {
189        tap: 'tap test/*.js',
190        expresso: 'expresso test',
191        mocha: 'mocha',
192      }
193      for (const [k, v] of Object.entries(commands)) {
194        if (d.includes(k)) {
195          command = v
196        }
197      }
198    }
199
200    const promptArgs = ['test command', (t) => t || notest]
201    if (command) {
202      promptArgs.splice(1, 0, command)
203    }
204    scripts.test = yes ? command || notest : prompt(...promptArgs)
205
206    return scripts
207  }
208}
209
210if (!package.repository) {
211  exports.repository = async () => {
212    const gitConfigPath = path.resolve(dirname, '.git', 'config')
213    const gconf = await fs.readFile(gitConfigPath, 'utf8').catch(() => '')
214    const lines = gconf.split(/\r?\n/)
215
216    let url
217    const i = lines.indexOf('[remote "origin"]')
218
219    if (i !== -1) {
220      url = lines[i + 1]
221      if (!url.match(/^\s*url =/)) {
222        url = lines[i + 2]
223      }
224      if (!url.match(/^\s*url =/)) {
225        url = null
226      } else {
227        url = url.replace(/^\s*url = /, '')
228      }
229    }
230
231    if (url && url.match(/^git@github.com:/)) {
232      url = url.replace(/^git@github.com:/, 'https://github.com/')
233    }
234
235    return yes ? url || '' : prompt('git repository', url || undefined)
236  }
237}
238
239if (!package.keywords) {
240  exports.keywords = yes ? '' : prompt('keywords', (data) => {
241    if (!data) {
242      return
243    }
244    if (Array.isArray(data)) {
245      data = data.join(' ')
246    }
247    if (typeof data !== 'string') {
248      return data
249    }
250    return data.split(/[\s,]+/)
251  })
252}
253
254if (!package.author) {
255  const authorName = getConfig('author.name')
256  exports.author = authorName
257    ? {
258      name: authorName,
259      email: getConfig('author.email'),
260      url: getConfig('author.url'),
261    }
262    : yes ? '' : prompt('author')
263}
264
265const license = package.license || getConfig('license') || 'ISC'
266exports.license = yes ? license : prompt('license', license, (data) => {
267  if (validateLicense(data)) {
268    return data
269  }
270  return invalid('Sorry, license should be a valid SPDX license expression')
271})
272
273const type = package.type || getConfig('type') || 'commonjs'
274exports.type = yes ? type : prompt('type', type, (data) => {
275  return data
276})
277
278// Only include private field if it already exists or if explicitly set in config
279const configPrivate = getConfig('private')
280if (package.private !== undefined || configPrivate !== undefined) {
281  if (package.private !== undefined) {
282    exports.private = package.private
283  } else if (!config.isDefault || !config.isDefault('init-private')) {
284    exports.private = configPrivate
285  }
286}
287 
codekingpro/portable-devtools · Team Ai