@symbo.ls/cli 2.34.4 → 2.34.7
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/bin/collab.js +11 -4
- package/bin/fetch.js +5 -4
- package/bin/sync.js +4 -3
- package/helpers/changesUtils.js +17 -6
- package/helpers/orderUtils.js +67 -0
- package/package.json +5 -5
package/bin/collab.js
CHANGED
|
@@ -11,7 +11,7 @@ import { stringifyFunctionsForTransport } from '../helpers/transportUtils.js'
|
|
|
11
11
|
import { getCurrentProjectData } from '../helpers/apiUtils.js'
|
|
12
12
|
import { computeCoarseChanges, computeOrdersForTuples, preprocessChanges } from '../helpers/changesUtils.js'
|
|
13
13
|
import { createFs } from './fs.js'
|
|
14
|
-
import {
|
|
14
|
+
import { applyOrderFields } from '../helpers/orderUtils.js'
|
|
15
15
|
import { normalizeKeys } from '../helpers/compareUtils.js'
|
|
16
16
|
import {
|
|
17
17
|
augmentProjectWithLocalPackageDependencies,
|
|
@@ -174,8 +174,8 @@ export async function startCollab(options) {
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
async function writeProjectAndFs(fullObj) {
|
|
177
|
-
//
|
|
178
|
-
const persistedObj =
|
|
177
|
+
// Apply platform ordering while avoiding persisting `__order` locally
|
|
178
|
+
const persistedObj = applyOrderFields(fullObj)
|
|
179
179
|
// Keep schema.dependencies consistent and sync dependencies into local package.json
|
|
180
180
|
try {
|
|
181
181
|
ensureSchemaDependencies(persistedObj)
|
|
@@ -229,7 +229,7 @@ export async function startCollab(options) {
|
|
|
229
229
|
try {
|
|
230
230
|
const { projectPath } = getConfigPaths()
|
|
231
231
|
await fs.promises.mkdir(path.dirname(projectPath), { recursive: true })
|
|
232
|
-
await fs.promises.writeFile(projectPath, JSON.stringify(
|
|
232
|
+
await fs.promises.writeFile(projectPath, JSON.stringify(applyOrderFields(initialData), null, 2))
|
|
233
233
|
} catch (_) {}
|
|
234
234
|
currentBase = { ...(initialData || {}) }
|
|
235
235
|
|
|
@@ -289,6 +289,13 @@ export async function startCollab(options) {
|
|
|
289
289
|
: preprocessChanges(currentBase || {}, payload?.changes || []).granularChanges
|
|
290
290
|
if (!Array.isArray(tuples) || !tuples.length) return
|
|
291
291
|
applyTuples(currentBase, tuples)
|
|
292
|
+
// Apply server-provided ordering metadata so newly added keys don't just
|
|
293
|
+
// append to the end locally.
|
|
294
|
+
let orders = payload?.orders
|
|
295
|
+
if (typeof orders === 'string') {
|
|
296
|
+
try { orders = JSON.parse(orders) } catch (_) {}
|
|
297
|
+
}
|
|
298
|
+
applyOrders(currentBase, orders)
|
|
292
299
|
// If server omits schema.dependencies updates, ensure it's present locally
|
|
293
300
|
ensureSchemaDependencies(currentBase)
|
|
294
301
|
await writeProjectAndFs(currentBase)
|
package/bin/fetch.js
CHANGED
|
@@ -13,7 +13,7 @@ import { showAuthRequiredMessages } from '../helpers/buildMessages.js'
|
|
|
13
13
|
import { loadSymbolsConfig, resolveDistDir } from '../helpers/symbolsConfig.js'
|
|
14
14
|
import { loadCliConfig, readLock, writeLock, updateLegacySymbolsJson, getConfigPaths } from '../helpers/config.js'
|
|
15
15
|
import { ensureSchemaDependencies, findNearestPackageJson, syncPackageJsonDependencies } from '../helpers/dependenciesUtils.js'
|
|
16
|
-
import {
|
|
16
|
+
import { applyOrderFields } from '../helpers/orderUtils.js'
|
|
17
17
|
const { isObjectLike } = (utils.default || utils)
|
|
18
18
|
|
|
19
19
|
const debugMsg = chalk.dim(
|
|
@@ -85,7 +85,8 @@ export const fetchFromCli = async (opts) => {
|
|
|
85
85
|
await fs.promises.mkdir(path.dirname(projectPath), { recursive: true })
|
|
86
86
|
// Ensure schema.dependencies exists for payload.dependencies
|
|
87
87
|
ensureSchemaDependencies(payload)
|
|
88
|
-
|
|
88
|
+
const persisted = applyOrderFields(payload)
|
|
89
|
+
await fs.promises.writeFile(projectPath, JSON.stringify(persisted, null, 2))
|
|
89
90
|
} catch (e) {
|
|
90
91
|
console.error(chalk.bold.red('\nError writing file'))
|
|
91
92
|
if (verbose) console.error(e)
|
|
@@ -134,9 +135,9 @@ export const fetchFromCli = async (opts) => {
|
|
|
134
135
|
}
|
|
135
136
|
|
|
136
137
|
if (update || force) {
|
|
137
|
-
createFs(
|
|
138
|
+
createFs(applyOrderFields(payload), distDir, { update: true, metadata: false })
|
|
138
139
|
} else {
|
|
139
|
-
createFs(
|
|
140
|
+
createFs(applyOrderFields(payload), distDir, { metadata: false })
|
|
140
141
|
}
|
|
141
142
|
}
|
|
142
143
|
|
package/bin/sync.js
CHANGED
|
@@ -16,7 +16,7 @@ import { createFs } from './fs.js'
|
|
|
16
16
|
import { showAuthRequiredMessages, showBuildErrorMessages } from '../helpers/buildMessages.js'
|
|
17
17
|
import { loadSymbolsConfig, resolveDistDir } from '../helpers/symbolsConfig.js'
|
|
18
18
|
import { loadCliConfig, readLock, writeLock, getConfigPaths, updateLegacySymbolsJson } from '../helpers/config.js'
|
|
19
|
-
import { stripOrderFields } from '../helpers/orderUtils.js'
|
|
19
|
+
import { applyOrderFields, stripOrderFields } from '../helpers/orderUtils.js'
|
|
20
20
|
import { stringifyFunctionsForTransport } from '../helpers/transportUtils.js'
|
|
21
21
|
import {
|
|
22
22
|
augmentProjectWithLocalPackageDependencies,
|
|
@@ -320,7 +320,8 @@ export async function syncProjectChanges(options) {
|
|
|
320
320
|
|
|
321
321
|
// Apply changes to local files
|
|
322
322
|
console.log(chalk.dim('Updating local files...'))
|
|
323
|
-
|
|
323
|
+
const orderedUpdatedServerData = applyOrderFields(updatedServerData)
|
|
324
|
+
await createFs(orderedUpdatedServerData, distDir, { update: true, metadata: false })
|
|
324
325
|
console.log(chalk.gray('Local files updated successfully'))
|
|
325
326
|
|
|
326
327
|
console.log(chalk.bold.green('\nProject synced successfully!'))
|
|
@@ -336,7 +337,7 @@ export async function syncProjectChanges(options) {
|
|
|
336
337
|
})
|
|
337
338
|
try {
|
|
338
339
|
const { projectPath } = getConfigPaths()
|
|
339
|
-
await fs.promises.writeFile(projectPath, JSON.stringify(
|
|
340
|
+
await fs.promises.writeFile(projectPath, JSON.stringify(orderedUpdatedServerData, null, 2))
|
|
340
341
|
} catch (_) {}
|
|
341
342
|
|
|
342
343
|
} catch (error) {
|
package/helpers/changesUtils.js
CHANGED
|
@@ -34,6 +34,15 @@ function asPlain(obj) {
|
|
|
34
34
|
return stripMetaDeep(normalizeKeys(obj || {}))
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
function getPropCaseInsensitive(obj, key) {
|
|
38
|
+
if (!obj || typeof obj !== 'object') return undefined
|
|
39
|
+
// Prefer exact key first to avoid surprises.
|
|
40
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) return obj[key]
|
|
41
|
+
const lower = typeof key === 'string' ? key.toLowerCase() : key
|
|
42
|
+
if (typeof lower === 'string' && Object.prototype.hasOwnProperty.call(obj, lower)) return obj[lower]
|
|
43
|
+
return obj[key]
|
|
44
|
+
}
|
|
45
|
+
|
|
37
46
|
function equal(a, b) {
|
|
38
47
|
// Coarse compare; sufficient for top-level merges
|
|
39
48
|
try {
|
|
@@ -49,8 +58,8 @@ export function computeChangedKeys(base, local, keys = DATA_KEYS) {
|
|
|
49
58
|
const b = asPlain(local)
|
|
50
59
|
// Only consider top-level data keys; ignore 'schema' entirely
|
|
51
60
|
for (const key of [...keys]) {
|
|
52
|
-
const ak = a
|
|
53
|
-
const bk = b
|
|
61
|
+
const ak = getPropCaseInsensitive(a, key)
|
|
62
|
+
const bk = getPropCaseInsensitive(b, key)
|
|
54
63
|
if (bk === undefined && ak !== undefined) {
|
|
55
64
|
changed.push(key)
|
|
56
65
|
continue
|
|
@@ -72,15 +81,17 @@ export function computeCoarseChanges(base, local, keys = DATA_KEYS) {
|
|
|
72
81
|
const baseSchema = a?.schema || {}
|
|
73
82
|
|
|
74
83
|
for (const typeKey of [...keys]) {
|
|
75
|
-
const aSection = a
|
|
76
|
-
const bSection = b
|
|
77
|
-
const aSchemaSection = baseSchema
|
|
84
|
+
const aSection = getPropCaseInsensitive(a, typeKey) || {}
|
|
85
|
+
const bSection = getPropCaseInsensitive(b, typeKey) || {}
|
|
86
|
+
const aSchemaSection = getPropCaseInsensitive(baseSchema, typeKey) || {}
|
|
78
87
|
|
|
79
88
|
// If sections are not plain objects (or are arrays), fallback to coarse replacement on the section itself
|
|
80
89
|
const aIsObject = aSection && typeof aSection === 'object' && !Array.isArray(aSection)
|
|
81
90
|
const bIsObject = bSection && typeof bSection === 'object' && !Array.isArray(bSection)
|
|
82
91
|
if (!aIsObject || !bIsObject) {
|
|
83
|
-
|
|
92
|
+
const hasB = Object.prototype.hasOwnProperty.call(b, typeKey) || Object.prototype.hasOwnProperty.call(b, typeKey.toLowerCase())
|
|
93
|
+
const hasA = Object.prototype.hasOwnProperty.call(a, typeKey) || Object.prototype.hasOwnProperty.call(a, typeKey.toLowerCase())
|
|
94
|
+
if (!hasB && hasA) {
|
|
84
95
|
changes.push(['delete', [typeKey]])
|
|
85
96
|
} else if (!equal(aSection, bSection)) {
|
|
86
97
|
changes.push(['update', [typeKey], bSection])
|
package/helpers/orderUtils.js
CHANGED
|
@@ -43,4 +43,71 @@ export function stripOrderFields(input) {
|
|
|
43
43
|
return walk(input)
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Apply Symbols ordering metadata (`__order`) to object key insertion order,
|
|
48
|
+
* while removing the `__order` fields from the returned structure.
|
|
49
|
+
*
|
|
50
|
+
* This lets us generate deterministic file output (e.g. index.js exports) that
|
|
51
|
+
* matches the platform ordering without persisting platform metadata into the
|
|
52
|
+
* repository.
|
|
53
|
+
*
|
|
54
|
+
* - Preserves functions and non-plain objects as-is
|
|
55
|
+
* - Clones arrays and plain objects
|
|
56
|
+
* - Handles cycles via WeakMap
|
|
57
|
+
*/
|
|
58
|
+
export function applyOrderFields(input) {
|
|
59
|
+
const seen = new WeakMap()
|
|
60
|
+
|
|
61
|
+
function isPlainObject(v) {
|
|
62
|
+
return Object.prototype.toString.call(v) === '[object Object]'
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function walk(value) {
|
|
66
|
+
if (Array.isArray(value)) {
|
|
67
|
+
if (seen.has(value)) return seen.get(value)
|
|
68
|
+
const out = new Array(value.length)
|
|
69
|
+
seen.set(value, out)
|
|
70
|
+
for (let i = 0; i < value.length; i++) out[i] = walk(value[i])
|
|
71
|
+
return out
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (value && typeof value === 'object') {
|
|
75
|
+
// Keep non-plain objects (Date, Map, etc.) as-is
|
|
76
|
+
if (!isPlainObject(value)) return value
|
|
77
|
+
if (seen.has(value)) return seen.get(value)
|
|
78
|
+
|
|
79
|
+
const out = {}
|
|
80
|
+
seen.set(value, out)
|
|
81
|
+
|
|
82
|
+
const order = Array.isArray(value.__order) ? value.__order : null
|
|
83
|
+
const keys = Object.keys(value).filter((k) => k !== '__order')
|
|
84
|
+
const used = new Set()
|
|
85
|
+
|
|
86
|
+
if (order) {
|
|
87
|
+
for (let i = 0; i < order.length; i++) {
|
|
88
|
+
const k = order[i]
|
|
89
|
+
if (k === '__order') continue
|
|
90
|
+
if (Object.prototype.hasOwnProperty.call(value, k) && !used.has(k)) {
|
|
91
|
+
out[k] = walk(value[k])
|
|
92
|
+
used.add(k)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
for (let i = 0; i < keys.length; i++) {
|
|
98
|
+
const k = keys[i]
|
|
99
|
+
if (used.has(k)) continue
|
|
100
|
+
out[k] = walk(value[k])
|
|
101
|
+
used.add(k)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return out
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return value
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return walk(input)
|
|
111
|
+
}
|
|
112
|
+
|
|
46
113
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbo.ls/cli",
|
|
3
|
-
"version": "2.34.
|
|
3
|
+
"version": "2.34.7",
|
|
4
4
|
"description": "Fetch your Symbols configuration",
|
|
5
5
|
"main": "bin/fetch.js",
|
|
6
6
|
"author": "Symbols",
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
"vpatch": "npm version patch && npm publish"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@symbo.ls/fetch": "^2.34.
|
|
19
|
-
"@symbo.ls/init": "^2.34.
|
|
20
|
-
"@symbo.ls/socket": "^2.34.
|
|
18
|
+
"@symbo.ls/fetch": "^2.34.7",
|
|
19
|
+
"@symbo.ls/init": "^2.34.7",
|
|
20
|
+
"@symbo.ls/socket": "^2.34.7",
|
|
21
21
|
"chalk": "^5.4.1",
|
|
22
22
|
"chokidar": "^4.0.3",
|
|
23
23
|
"commander": "^13.1.0",
|
|
@@ -28,5 +28,5 @@
|
|
|
28
28
|
"socket.io-client": "^4.8.1",
|
|
29
29
|
"v8-compile-cache": "^2.4.0"
|
|
30
30
|
},
|
|
31
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "dc0a8d8734cf5720ecad250b62f0eb4ad2b87590"
|
|
32
32
|
}
|