@florianpat/lando-core 3.23.27-4florianPat.2 → 3.23.27-5florianPat.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ## {{ UNRELEASED_VERSION }} - [{{ UNRELEASED_DATE }}]({{ UNRELEASED_LINK }})
2
2
 
3
- ## v3.23.27-4florianPat.2 - [March 13, 2025](https://github.com/florianPat/lando-core/releases/tag/v3.23.27-4florianPat.2)
3
+ ## v3.23.27-5florianPat.0 - [August 22, 2025](https://github.com/florianPat/lando-core/releases/tag/v3.23.27-5florianPat.0)
4
4
 
5
5
  ## v3.23.26 - [January 24, 2025](https://github.com/lando/core/releases/tag/v3.23.26)
6
6
 
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ const write = require('../utils/write-file');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const os = require('os');
7
+ const {parse} = require('ini');
8
+
9
+ module.exports = async lando => {
10
+ if (!lando.config.loadNpmrcForPluginAuth) {
11
+ return;
12
+ }
13
+
14
+ const npmrcPath = path.resolve(os.homedir(), '.npmrc');
15
+ if (!fs.existsSync(npmrcPath)) {
16
+ return;
17
+ }
18
+ lando.log.debug('Reading home .npmrc for plugin-auth.json...');
19
+ const content = fs.readFileSync(npmrcPath, {
20
+ encoding: 'utf-8',
21
+ });
22
+ const data = parse(content);
23
+ write(lando.config.pluginConfigFile, data);
24
+ lando.plugins.updates = data;
25
+ };
package/index.js CHANGED
@@ -102,6 +102,8 @@ module.exports = async lando => {
102
102
  // move v3 scripts directories as needed
103
103
  lando.events.on('pre-engine-start', 0, async () => await require('./hooks/lando-copy-v3-scripts')(lando));
104
104
 
105
+ lando.events.on('post-bootstrap-config', async () => await require('./hooks/plugin-auth-from-npmrc')(lando));
106
+
105
107
  // return some default things
106
108
  return _.merge({}, defaults, uc(), {config: {
107
109
  appEnv: {
@@ -0,0 +1,15 @@
1
+ The ISC License
2
+
3
+ Copyright (c) Isaac Z. Schlueter and Contributors
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
15
+ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,180 @@
1
+
2
+ An INI format parser & serializer.
3
+
4
+ ## Note
5
+
6
+ - Sections are treated as nested objects.
7
+
8
+ - Section-less items are treated as globals.
9
+
10
+ ## Usage
11
+
12
+ Consider an INI file such as the following:
13
+
14
+ ```ini
15
+ ; This comment is being ignored
16
+ scope = global
17
+
18
+ [database]
19
+ user = dbuser
20
+ password = dbpassword
21
+ database = use_this_database
22
+
23
+ [paths.default]
24
+ datadir = /var/lib/data
25
+ array[] = first value
26
+ array[] = second value
27
+ array[] = third value
28
+ ```
29
+
30
+ You can **read**, **modify** and **write** it like so:
31
+
32
+ ```js
33
+ import { writeFile , readFile } from 'node:fs/promises'
34
+ import { stringify , parse } from 'ini'
35
+
36
+ // Read INI file as text
37
+
38
+ let text = await readFile(`./Original.ini`,{
39
+ encoding : 'utf-8'
40
+ })
41
+
42
+ // Parse text data to object
43
+
44
+ const config = parse(text)
45
+
46
+ // Modify data object
47
+
48
+ config.scope = 'local'
49
+ config.database.database = 'use_another_database'
50
+ config.paths.default.tmpdir = '/tmp'
51
+ delete config.paths.default.datadir
52
+ config.paths.default.array.push('fourth value')
53
+
54
+ // Stringify data object
55
+
56
+ text = stringify(config,{
57
+ section : 'section'
58
+ })
59
+
60
+ // Write INI file as text
61
+
62
+ await writeFile(`./Modified.ini`,text)
63
+ ```
64
+
65
+ The written file will contain the following:
66
+
67
+ ```ini
68
+ [section]
69
+ scope=local
70
+ [section.database]
71
+ user=dbuser
72
+ password=dbpassword
73
+ database=use_another_database
74
+ [section.paths.default]
75
+ tmpdir=/tmp
76
+ array[]=first value
77
+ array[]=second value
78
+ array[]=third value
79
+ array[]=fourth value
80
+ ```
81
+
82
+ ## API
83
+
84
+ ### Parse
85
+
86
+ Attempts to turn the given INI string into a nested data object.
87
+
88
+ ```js
89
+ // You can also use `decode`
90
+ const object = parse(`<INI Text>`)
91
+ ```
92
+
93
+ ### Stringify
94
+
95
+ Encodes the given data object as an INI formatted string.
96
+
97
+ ```js
98
+ // You can also use `encode`
99
+ stringify(object,{
100
+
101
+ /**
102
+ * Whether to insert spaces before & after `=`
103
+ *
104
+ * Disabled by default to have better
105
+ * compatibility with old picky parsers.
106
+ */
107
+
108
+ whitespace : false ,
109
+
110
+ /**
111
+ * Whether to align the `=` character for each section.
112
+ * -> Also enables the `whitespace` option
113
+ */
114
+
115
+ align : false ,
116
+
117
+ /**
118
+ * Identifier to use for global items
119
+ * and to prepend to all other sections.
120
+ */
121
+
122
+ section ,
123
+
124
+ /**
125
+ * Whether to sort all sections & their keys alphabetically.
126
+ */
127
+
128
+ sort : false ,
129
+
130
+ /**
131
+ * Whether to insert a newline after each section header.
132
+ *
133
+ * The TOSHIBA & FlashAir parser require this format.
134
+ */
135
+
136
+ newline : false ,
137
+
138
+ /**
139
+ * Which platforms line-endings should be used.
140
+ *
141
+ * win32 -> CR+LF
142
+ * other -> LF
143
+ *
144
+ * Default is the current platform
145
+ */
146
+
147
+ platform ,
148
+
149
+ /**
150
+ * Whether to append `[]` to array keys.
151
+ *
152
+ * Some parsers treat duplicate names by themselves as arrays
153
+ */
154
+
155
+ bracketedArray : true
156
+
157
+ })
158
+ ```
159
+
160
+ *For backwards compatibility any string passed as the*
161
+ *options parameter is treated as the `section` option.*
162
+
163
+ ```js
164
+ stringify(object,'section')
165
+ ```
166
+
167
+ ### Un / Escape
168
+
169
+ Turn the given string into a safe to
170
+ use key or value in your INI file.
171
+
172
+ ```js
173
+ safe(`"unsafe string"`) // -> \"unsafe string\"
174
+ ```
175
+
176
+ Or reverse the process with:
177
+
178
+ ```js
179
+ unsafe(`\\"safe string\\"`) // -> "safe string"
180
+ ```
@@ -0,0 +1,280 @@
1
+ const { hasOwnProperty } = Object.prototype
2
+
3
+ const encode = (obj, opt = {}) => {
4
+ if (typeof opt === 'string') {
5
+ opt = { section: opt }
6
+ }
7
+ opt.align = opt.align === true
8
+ opt.newline = opt.newline === true
9
+ opt.sort = opt.sort === true
10
+ opt.whitespace = opt.whitespace === true || opt.align === true
11
+ // The `typeof` check is required because accessing the `process` directly fails on browsers.
12
+ /* istanbul ignore next */
13
+ opt.platform = opt.platform || (typeof process !== 'undefined' && process.platform)
14
+ opt.bracketedArray = opt.bracketedArray !== false
15
+
16
+ /* istanbul ignore next */
17
+ const eol = opt.platform === 'win32' ? '\r\n' : '\n'
18
+ const separator = opt.whitespace ? ' = ' : '='
19
+ const children = []
20
+
21
+ const keys = opt.sort ? Object.keys(obj).sort() : Object.keys(obj)
22
+
23
+ let padToChars = 0
24
+ // If aligning on the separator, then padToChars is determined as follows:
25
+ // 1. Get the keys
26
+ // 2. Exclude keys pointing to objects unless the value is null or an array
27
+ // 3. Add `[]` to array keys
28
+ // 4. Ensure non empty set of keys
29
+ // 5. Reduce the set to the longest `safe` key
30
+ // 6. Get the `safe` length
31
+ if (opt.align) {
32
+ padToChars = safe(
33
+ (
34
+ keys
35
+ .filter(k => obj[k] === null || Array.isArray(obj[k]) || typeof obj[k] !== 'object')
36
+ .map(k => Array.isArray(obj[k]) ? `${k}[]` : k)
37
+ )
38
+ .concat([''])
39
+ .reduce((a, b) => safe(a).length >= safe(b).length ? a : b)
40
+ ).length
41
+ }
42
+
43
+ let out = ''
44
+ const arraySuffix = opt.bracketedArray ? '[]' : ''
45
+
46
+ for (const k of keys) {
47
+ const val = obj[k]
48
+ if (val && Array.isArray(val)) {
49
+ for (const item of val) {
50
+ out += safe(`${k}${arraySuffix}`).padEnd(padToChars, ' ') + separator + safe(item) + eol
51
+ }
52
+ } else if (val && typeof val === 'object') {
53
+ children.push(k)
54
+ } else {
55
+ out += safe(k).padEnd(padToChars, ' ') + separator + safe(val) + eol
56
+ }
57
+ }
58
+
59
+ if (opt.section && out.length) {
60
+ out = '[' + safe(opt.section) + ']' + (opt.newline ? eol + eol : eol) + out
61
+ }
62
+
63
+ for (const k of children) {
64
+ const nk = splitSections(k, '.').join('\\.')
65
+ const section = (opt.section ? opt.section + '.' : '') + nk
66
+ const child = encode(obj[k], {
67
+ ...opt,
68
+ section,
69
+ })
70
+ if (out.length && child.length) {
71
+ out += eol
72
+ }
73
+
74
+ out += child
75
+ }
76
+
77
+ return out
78
+ }
79
+
80
+ function splitSections (str, separator) {
81
+ var lastMatchIndex = 0
82
+ var lastSeparatorIndex = 0
83
+ var nextIndex = 0
84
+ var sections = []
85
+
86
+ do {
87
+ nextIndex = str.indexOf(separator, lastMatchIndex)
88
+
89
+ if (nextIndex !== -1) {
90
+ lastMatchIndex = nextIndex + separator.length
91
+
92
+ if (nextIndex > 0 && str[nextIndex - 1] === '\\') {
93
+ continue
94
+ }
95
+
96
+ sections.push(str.slice(lastSeparatorIndex, nextIndex))
97
+ lastSeparatorIndex = nextIndex + separator.length
98
+ }
99
+ } while (nextIndex !== -1)
100
+
101
+ sections.push(str.slice(lastSeparatorIndex))
102
+
103
+ return sections
104
+ }
105
+
106
+ const decode = (str, opt = {}) => {
107
+ opt.bracketedArray = opt.bracketedArray !== false
108
+ const out = Object.create(null)
109
+ let p = out
110
+ let section = null
111
+ // section |key = value
112
+ const re = /^\[([^\]]*)\]\s*$|^([^=]+)(=(.*))?$/i
113
+ const lines = str.split(/[\r\n]+/g)
114
+ const duplicates = {}
115
+
116
+ for (const line of lines) {
117
+ if (!line || line.match(/^\s*[;#]/) || line.match(/^\s*$/)) {
118
+ continue
119
+ }
120
+ const match = line.match(re)
121
+ if (!match) {
122
+ continue
123
+ }
124
+ if (match[1] !== undefined) {
125
+ section = unsafe(match[1])
126
+ if (section === '__proto__') {
127
+ // not allowed
128
+ // keep parsing the section, but don't attach it.
129
+ p = Object.create(null)
130
+ continue
131
+ }
132
+ p = out[section] = out[section] || Object.create(null)
133
+ continue
134
+ }
135
+ const keyRaw = unsafe(match[2])
136
+ let isArray
137
+ if (opt.bracketedArray) {
138
+ isArray = keyRaw.length > 2 && keyRaw.slice(-2) === '[]'
139
+ } else {
140
+ duplicates[keyRaw] = (duplicates?.[keyRaw] || 0) + 1
141
+ isArray = duplicates[keyRaw] > 1
142
+ }
143
+ const key = isArray && keyRaw.endsWith('[]')
144
+ ? keyRaw.slice(0, -2) : keyRaw
145
+
146
+ if (key === '__proto__') {
147
+ continue
148
+ }
149
+ const valueRaw = match[3] ? unsafe(match[4]) : true
150
+ const value = valueRaw === 'true' ||
151
+ valueRaw === 'false' ||
152
+ valueRaw === 'null' ? JSON.parse(valueRaw)
153
+ : valueRaw
154
+
155
+ // Convert keys with '[]' suffix to an array
156
+ if (isArray) {
157
+ if (!hasOwnProperty.call(p, key)) {
158
+ p[key] = []
159
+ } else if (!Array.isArray(p[key])) {
160
+ p[key] = [p[key]]
161
+ }
162
+ }
163
+
164
+ // safeguard against resetting a previously defined
165
+ // array by accidentally forgetting the brackets
166
+ if (Array.isArray(p[key])) {
167
+ p[key].push(value)
168
+ } else {
169
+ p[key] = value
170
+ }
171
+ }
172
+
173
+ // {a:{y:1},"a.b":{x:2}} --> {a:{y:1,b:{x:2}}}
174
+ // use a filter to return the keys that have to be deleted.
175
+ const remove = []
176
+ for (const k of Object.keys(out)) {
177
+ if (!hasOwnProperty.call(out, k) ||
178
+ typeof out[k] !== 'object' ||
179
+ Array.isArray(out[k])) {
180
+ continue
181
+ }
182
+
183
+ // see if the parent section is also an object.
184
+ // if so, add it to that, and mark this one for deletion
185
+ const parts = splitSections(k, '.')
186
+ p = out
187
+ const l = parts.pop()
188
+ const nl = l.replace(/\\\./g, '.')
189
+ for (const part of parts) {
190
+ if (part === '__proto__') {
191
+ continue
192
+ }
193
+ if (!hasOwnProperty.call(p, part) || typeof p[part] !== 'object') {
194
+ p[part] = Object.create(null)
195
+ }
196
+ p = p[part]
197
+ }
198
+ if (p === out && nl === l) {
199
+ continue
200
+ }
201
+
202
+ p[nl] = out[k]
203
+ remove.push(k)
204
+ }
205
+ for (const del of remove) {
206
+ delete out[del]
207
+ }
208
+
209
+ return out
210
+ }
211
+
212
+ const isQuoted = val => {
213
+ return (val.startsWith('"') && val.endsWith('"')) ||
214
+ (val.startsWith("'") && val.endsWith("'"))
215
+ }
216
+
217
+ const safe = val => {
218
+ if (
219
+ typeof val !== 'string' ||
220
+ val.match(/[=\r\n]/) ||
221
+ val.match(/^\[/) ||
222
+ (val.length > 1 && isQuoted(val)) ||
223
+ val !== val.trim()
224
+ ) {
225
+ return JSON.stringify(val)
226
+ }
227
+ return val.split(';').join('\\;').split('#').join('\\#')
228
+ }
229
+
230
+ const unsafe = val => {
231
+ val = (val || '').trim()
232
+ if (isQuoted(val)) {
233
+ // remove the single quotes before calling JSON.parse
234
+ if (val.charAt(0) === "'") {
235
+ val = val.slice(1, -1)
236
+ }
237
+ try {
238
+ val = JSON.parse(val)
239
+ } catch {
240
+ // ignore errors
241
+ }
242
+ } else {
243
+ // walk the val to find the first not-escaped ; character
244
+ let esc = false
245
+ let unesc = ''
246
+ for (let i = 0, l = val.length; i < l; i++) {
247
+ const c = val.charAt(i)
248
+ if (esc) {
249
+ if ('\\;#'.indexOf(c) !== -1) {
250
+ unesc += c
251
+ } else {
252
+ unesc += '\\' + c
253
+ }
254
+
255
+ esc = false
256
+ } else if (';#'.indexOf(c) !== -1) {
257
+ break
258
+ } else if (c === '\\') {
259
+ esc = true
260
+ } else {
261
+ unesc += c
262
+ }
263
+ }
264
+ if (esc) {
265
+ unesc += '\\'
266
+ }
267
+
268
+ return unesc.trim()
269
+ }
270
+ return val
271
+ }
272
+
273
+ module.exports = {
274
+ parse: decode,
275
+ decode,
276
+ stringify: encode,
277
+ encode,
278
+ safe,
279
+ unsafe,
280
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "author": "GitHub Inc.",
3
+ "name": "ini",
4
+ "description": "An ini encoder/decoder for node",
5
+ "version": "5.0.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/npm/ini.git"
9
+ },
10
+ "main": "lib/ini.js",
11
+ "scripts": {
12
+ "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"",
13
+ "lint": "npm run eslint",
14
+ "lintfix": "npm run eslint -- --fix",
15
+ "test": "tap",
16
+ "snap": "tap",
17
+ "posttest": "npm run lint",
18
+ "postlint": "template-oss-check",
19
+ "template-oss-apply": "template-oss-apply --force"
20
+ },
21
+ "devDependencies": {
22
+ "@npmcli/eslint-config": "^5.0.0",
23
+ "@npmcli/template-oss": "4.23.3",
24
+ "tap": "^16.0.1"
25
+ },
26
+ "license": "ISC",
27
+ "files": [
28
+ "bin/",
29
+ "lib/"
30
+ ],
31
+ "engines": {
32
+ "node": "^18.17.0 || >=20.5.0"
33
+ },
34
+ "templateOSS": {
35
+ "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
36
+ "version": "4.23.3",
37
+ "publish": "true"
38
+ },
39
+ "tap": {
40
+ "nyc-arg": [
41
+ "--exclude",
42
+ "tap-snapshots/**"
43
+ ]
44
+ }
45
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@florianpat/lando-core",
3
3
  "description": "The libraries that power all of Lando. Fork by flo for compose integration",
4
- "version": "3.23.27-4florianPat.2",
4
+ "version": "3.23.27-5florianPat.0",
5
5
  "author": "Florian Patruck @florianPat",
6
6
  "license": "GPL-3.0",
7
7
  "repository": "florianPat/lando-core",
@@ -127,6 +127,7 @@
127
127
  "figures": "^3.2.0",
128
128
  "fs-extra": "^11.1.1",
129
129
  "glob": "^7.1.3",
130
+ "ini": "^5.0.0",
130
131
  "inquirer": "^6.5.2",
131
132
  "inquirer-autocomplete-prompt": "^1.4.0",
132
133
  "is-class": "^0.0.9",
@@ -208,6 +209,7 @@
208
209
  "figures",
209
210
  "fs-extra",
210
211
  "glob",
212
+ "ini",
211
213
  "inquirer",
212
214
  "inquirer-autocomplete-prompt",
213
215
  "is-class",
@@ -247,9 +249,9 @@
247
249
  "yargs-parser"
248
250
  ],
249
251
  "dist": {
250
- "integrity": "sha512-md/dXWSDeZ/Yuv01a926LsoZUUFhVdhXKhuTsxueCV87DdsJ95SrVgwn8X7DiqD0sRb771j4oQ1wEYr01OId/g==",
251
- "shasum": "48b0d84ff591b9cc816be0d7ac6a68c952270de0",
252
- "filename": "florianpat-lando-core-3.23.27-4florianPat.2.tgz",
253
- "unpackedSize": 60967667
252
+ "integrity": "sha512-4XH8m3midLfVyHWYS3dPq978/MNrKtNQ2HcNrj/iYXgS0+E05NauocHPAt9vBRHb3FCcGT9Eo1e5StzZUjb7xw==",
253
+ "shasum": "15a076e7e025a35ddf5c82fc789f8057c10b54f1",
254
+ "filename": "florianpat-lando-core-3.23.27-5florianPat.0.tgz",
255
+ "unpackedSize": 60980579
254
256
  }
255
257
  }