mirror of
https://github.com/ether/etherpad-lite.git
synced 2026-07-17 16:47:05 +00:00
chore(deps): drop three unmaintained dependencies (unorm, find-root, jsonminify) (#7992)
* chore(deps): drop three unmaintained dependencies from core
Remove dependencies whose upstreams are effectively abandoned, replacing
each with a maintained alternative or native API. No behaviour change for
users; reduces the production dependency surface.
- unorm (last publish 2019): replace `UNorm.nfc(s)` in contentcollector
with native `String.prototype.normalize('NFC')`, available in every
supported Node and browser. Also drop it from Minify's LIBRARY_WHITELIST.
- find-root (last publish 2017): inline a ~10-line equivalent in
AbsolutePaths.findEtherpadRoot(), mirroring find-root's semantics
(closest ancestor containing package.json, throw if none).
- jsonminify (last publish 2021): swap settings parsing to jsonc-parser
(already used by the admin workspace, actively maintained). The old
`jsonminify(str).replace(',]', ']').replace(',}', '}')` had two bugs that
jsonc-parser's allowTrailingComma fixes: String#replace only swapped the
FIRST trailing comma of each kind, and the blind replace corrupted ',]' /
',}' byte sequences inside string values (e.g. URLs).
Added a regression test in settings.ts covering multiple trailing commas
and ',]'/',}' inside string values.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: drop stale $unorm bundle entry from tar.json
The unorm removal left `$unorm/lib/unorm.js` listed in the ace2_inner.js
client bundle manifest. With unorm uninstalled, getTar() would point at a
node_modules asset that no longer exists, producing 404s when loading that
bundle. Nothing imports unorm anymore (contentcollector now uses native
String.prototype.normalize), so the entry is dead and removed.
Caught by Qodo review.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: update container loadSettings helper to jsonc-parser
tests/container/loadSettings.js is a standalone helper (separate from
node/utils/Settings.ts) that parsed settings.json.docker with jsonminify
directly. Removing jsonminify from dependencies broke the container test
suite with MODULE_NOT_FOUND. Switch it to jsonc-parser to match Settings.ts.
Verified loadSettings() parses settings.json.docker and applies the
container ip/port overrides.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
01d0b08a4e
commit
7168f14f0a
9 changed files with 101 additions and 49 deletions
37
pnpm-lock.yaml
generated
37
pnpm-lock.yaml
generated
|
|
@ -229,9 +229,6 @@ importers:
|
|||
express-session:
|
||||
specifier: ^1.19.0
|
||||
version: 1.19.0
|
||||
find-root:
|
||||
specifier: 1.1.0
|
||||
version: 1.1.0
|
||||
formidable:
|
||||
specifier: ^3.5.4
|
||||
version: 3.5.4
|
||||
|
|
@ -253,9 +250,9 @@ importers:
|
|||
jsdom:
|
||||
specifier: ^29.1.1
|
||||
version: 29.1.1(@noble/hashes@1.8.0)
|
||||
jsonminify:
|
||||
specifier: 0.4.2
|
||||
version: 0.4.2
|
||||
jsonc-parser:
|
||||
specifier: ^3.3.1
|
||||
version: 3.3.1
|
||||
jsonwebtoken:
|
||||
specifier: ^9.0.3
|
||||
version: 9.0.3
|
||||
|
|
@ -373,9 +370,6 @@ importers:
|
|||
undici:
|
||||
specifier: ^8.5.0
|
||||
version: 8.5.0
|
||||
unorm:
|
||||
specifier: 1.6.0
|
||||
version: 1.6.0
|
||||
wtfnode:
|
||||
specifier: ^0.10.1
|
||||
version: 0.10.1
|
||||
|
|
@ -416,9 +410,6 @@ importers:
|
|||
'@types/jsdom':
|
||||
specifier: ^28.0.3
|
||||
version: 28.0.3
|
||||
'@types/jsonminify':
|
||||
specifier: ^0.4.3
|
||||
version: 0.4.3
|
||||
'@types/jsonwebtoken':
|
||||
specifier: ^9.0.10
|
||||
version: 9.0.10
|
||||
|
|
@ -1847,9 +1838,6 @@ packages:
|
|||
'@types/json5@0.0.29':
|
||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||
|
||||
'@types/jsonminify@0.4.3':
|
||||
resolution: {integrity: sha512-+oz7EbPz1Nwmn/sr3UztgXpRhdFpvFrjGi5ictEYxUri5ZvQMTcdTi36MTfD/gCb1A5xhJKdH8Hwz2uz5k6s9A==}
|
||||
|
||||
'@types/jsonwebtoken@9.0.10':
|
||||
resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==}
|
||||
|
||||
|
|
@ -3326,9 +3314,6 @@ packages:
|
|||
resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==}
|
||||
engines: {node: '>= 18.0.0'}
|
||||
|
||||
find-root@1.1.0:
|
||||
resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
|
||||
|
||||
find-up@5.0.0:
|
||||
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
@ -3904,10 +3889,6 @@ packages:
|
|||
jsonfile@6.1.0:
|
||||
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
|
||||
|
||||
jsonminify@0.4.2:
|
||||
resolution: {integrity: sha512-mEtP5ECD0293D+s45JhDutqF5mFCkWY8ClrPFxjSFR2KUoantofky7noSzyKnAnD9Gd8pXHZSUd5bgzLDUBbfA==}
|
||||
engines: {node: '>=0.8.0', npm: '>=1.1.0'}
|
||||
|
||||
jsonschema-draft4@1.0.0:
|
||||
resolution: {integrity: sha512-sBV3UnQPRiyCTD6uzY/Oao2Yohv6KKgQq7zjPwjFHeR6scg/QSXnzDxdugsGaLQDmFUrUlTbMYdEE+72PizhGA==}
|
||||
|
||||
|
|
@ -5509,10 +5490,6 @@ packages:
|
|||
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
|
||||
unorm@1.6.0:
|
||||
resolution: {integrity: sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
|
||||
unpipe@1.0.0:
|
||||
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
|
@ -7120,8 +7097,6 @@ snapshots:
|
|||
|
||||
'@types/json5@0.0.29': {}
|
||||
|
||||
'@types/jsonminify@0.4.3': {}
|
||||
|
||||
'@types/jsonwebtoken@9.0.10':
|
||||
dependencies:
|
||||
'@types/ms': 2.1.0
|
||||
|
|
@ -8774,8 +8749,6 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
find-root@1.1.0: {}
|
||||
|
||||
find-up@5.0.0:
|
||||
dependencies:
|
||||
locate-path: 6.0.0
|
||||
|
|
@ -9430,8 +9403,6 @@ snapshots:
|
|||
optionalDependencies:
|
||||
graceful-fs: 4.2.11
|
||||
|
||||
jsonminify@0.4.2: {}
|
||||
|
||||
jsonschema-draft4@1.0.0: {}
|
||||
|
||||
jsonschema@1.2.4: {}
|
||||
|
|
@ -11181,8 +11152,6 @@ snapshots:
|
|||
|
||||
universalify@2.0.1: {}
|
||||
|
||||
unorm@1.6.0: {}
|
||||
|
||||
unpipe@1.0.0: {}
|
||||
|
||||
update-browserslist-db@1.2.3(browserslist@4.28.2):
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
import log4js from 'log4js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import _ from 'underscore';
|
||||
|
||||
|
|
@ -30,6 +31,25 @@ const absPathLogger = log4js.getLogger('AbsolutePaths');
|
|||
*/
|
||||
let etherpadRoot: string|null = null;
|
||||
|
||||
/**
|
||||
* Walks up the directory tree from `start`, returning the closest ancestor
|
||||
* directory (including `start` itself) that contains a package.json. Replaces
|
||||
* the unmaintained `find-root` package, mirroring its semantics: it throws if
|
||||
* no package.json is found before reaching the filesystem root.
|
||||
*
|
||||
* @param {string} start - The directory to start searching from.
|
||||
* @return {string} The closest ancestor directory containing a package.json.
|
||||
*/
|
||||
const findRoot = (start: string): string => {
|
||||
let dir = start;
|
||||
for (;;) {
|
||||
if (fs.existsSync(path.join(dir, 'package.json'))) return dir;
|
||||
const parent = path.dirname(dir);
|
||||
if (parent === dir) throw new Error('package.json not found in path');
|
||||
dir = parent;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* If stringArray's last elements are exactly equal to lastDesiredElements,
|
||||
* returns a copy in which those last elements are popped, or false otherwise.
|
||||
|
|
@ -79,7 +99,6 @@ export const findEtherpadRoot = () => {
|
|||
return etherpadRoot;
|
||||
}
|
||||
|
||||
const findRoot = require('find-root');
|
||||
const foundRoot = findRoot(__dirname);
|
||||
const splitFoundRoot = foundRoot.split(path.sep);
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ const LIBRARY_WHITELIST = [
|
|||
'split-grid',
|
||||
'tinycon',
|
||||
'underscore',
|
||||
'unorm',
|
||||
];
|
||||
|
||||
// What follows is a terrible hack to avoid loop-back within the server.
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import fs from 'node:fs';
|
|||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import {argv} from './Cli'
|
||||
import jsonminify from 'jsonminify';
|
||||
import {parse as parseJsonc, printParseErrorCode, ParseError} from 'jsonc-parser';
|
||||
import log4js from 'log4js';
|
||||
import {createHash} from 'node:crypto';
|
||||
import randomString from './randomstring';
|
||||
|
|
@ -116,9 +116,18 @@ const parseSettings = (settingsFilename: string, isSettings: boolean) => {
|
|||
}
|
||||
|
||||
try {
|
||||
settingsStr = jsonminify(settingsStr).replace(',]', ']').replace(',}', '}');
|
||||
// jsonc-parser tolerates comments and trailing commas, so settings files
|
||||
// can stay annotated. Unlike the old jsonminify + naive ',]'/',}' string
|
||||
// replace, it fixes *every* trailing comma (not just the first of each
|
||||
// kind) and never mangles those sequences when they appear inside strings.
|
||||
const errors: ParseError[] = [];
|
||||
const settings = parseJsonc(settingsStr, errors, {allowTrailingComma: true});
|
||||
|
||||
const settings = JSON.parse(settingsStr);
|
||||
if (errors.length > 0) {
|
||||
const {error, offset} = errors[0];
|
||||
throw new Error(`${printParseErrorCode(error)} at offset ${offset}`);
|
||||
}
|
||||
if (settings === undefined) throw new Error('file is empty or not valid JSON');
|
||||
|
||||
logger.info(`${settingsType} loaded from: ${settingsFilename}`);
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@
|
|||
, "skiplist.js"
|
||||
, "colorutils.js"
|
||||
, "undomodule.js"
|
||||
, "$unorm/lib/unorm.js"
|
||||
, "contentcollector.js"
|
||||
, "changesettracker.js"
|
||||
, "linestylefilter.js"
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
"express": "^5.2.1",
|
||||
"express-rate-limit": "^8.5.1",
|
||||
"express-session": "^1.19.0",
|
||||
"find-root": "1.1.0",
|
||||
"formidable": "^3.5.4",
|
||||
"html-to-docx": "^1.8.0",
|
||||
"htmlparser2": "^12.0.0",
|
||||
|
|
@ -50,7 +49,7 @@
|
|||
"jose": "^6.2.3",
|
||||
"js-cookie": "^3.0.8",
|
||||
"jsdom": "^29.1.1",
|
||||
"jsonminify": "0.4.2",
|
||||
"jsonc-parser": "^3.3.1",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"languages4translatewiki": "0.1.3",
|
||||
|
|
@ -90,7 +89,6 @@
|
|||
"ueberdb2": "6.1.13",
|
||||
"underscore": "1.13.8",
|
||||
"undici": "^8.5.0",
|
||||
"unorm": "1.6.0",
|
||||
"wtfnode": "^0.10.1"
|
||||
},
|
||||
"bin": {
|
||||
|
|
@ -110,7 +108,6 @@
|
|||
"@types/jquery": "^4.0.1",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/jsdom": "^28.0.3",
|
||||
"@types/jsonminify": "^0.4.3",
|
||||
"@types/jsonwebtoken": "^9.0.10",
|
||||
"@types/mime-types": "^3.0.1",
|
||||
"@types/mocha": "^10.0.9",
|
||||
|
|
|
|||
|
|
@ -31,12 +31,13 @@ import Op from "./Op";
|
|||
const _MAX_LIST_LEVEL = 16;
|
||||
|
||||
import AttributeMap from './AttributeMap';
|
||||
import UNorm from 'unorm';
|
||||
import {subattribution} from './Changeset';
|
||||
import {SmartOpAssembler} from "./SmartOpAssembler";
|
||||
const hooks = require('./pluginfw/hooks');
|
||||
|
||||
const sanitizeUnicode = (s) => UNorm.nfc(s);
|
||||
// NFC-normalize via the native String API (replaces the unmaintained `unorm`
|
||||
// polyfill; String.prototype.normalize is available in every supported runtime).
|
||||
const sanitizeUnicode = (s: string) => s.normalize('NFC');
|
||||
const tagName = (n) => n.tagName && n.tagName.toLowerCase();
|
||||
// supportedElems are Supported natively within Etherpad and don't require a plugin
|
||||
const supportedElems = new Set([
|
||||
|
|
|
|||
|
|
@ -278,4 +278,62 @@ describe(__filename, function () {
|
|||
assert.strictEqual(over!.privacy.pluginCatalog, false);
|
||||
});
|
||||
});
|
||||
|
||||
// Regression test for the jsonminify -> jsonc-parser migration.
|
||||
// The old parser was `jsonminify(str).replace(',]', ']').replace(',}', '}')`,
|
||||
// which had two correctness bugs that jsonc-parser (allowTrailingComma) fixes:
|
||||
// 1. String#replace with a string needle only swaps the FIRST match, so a
|
||||
// file with more than one trailing comma of the same kind stayed invalid.
|
||||
// 2. The blind ',]' / ',}' replace also corrupted those byte sequences when
|
||||
// they appeared *inside* a string value (e.g. a URL or literal text).
|
||||
describe('JSONC settings parsing (jsonminify -> jsonc-parser)', function () {
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
let tmpFile: string;
|
||||
|
||||
const writeTmp = (contents: string) => {
|
||||
tmpFile = path.join(os.tmpdir(), `ep-settings-jsonc-${process.pid}.json`);
|
||||
fs.writeFileSync(tmpFile, contents);
|
||||
return tmpFile;
|
||||
};
|
||||
|
||||
afterEach(function () {
|
||||
if (tmpFile) { try { fs.unlinkSync(tmpFile); } catch (e) { /* ignore */ } }
|
||||
});
|
||||
|
||||
it('strips comments and tolerates multiple trailing commas', function () {
|
||||
const file = writeTmp(`// leading line comment
|
||||
/* block comment */
|
||||
{
|
||||
"list": [
|
||||
"a",
|
||||
"b",
|
||||
],
|
||||
"nested": [
|
||||
[1, 2,],
|
||||
[3, 4,],
|
||||
],
|
||||
"obj": {
|
||||
"x": 1,
|
||||
"y": 2,
|
||||
},
|
||||
}`);
|
||||
const s: any = exportedForTestingOnly.parseSettings(file, true);
|
||||
assert.deepEqual(s.list, ['a', 'b']);
|
||||
assert.deepEqual(s.nested, [[1, 2], [3, 4]]);
|
||||
assert.deepEqual(s.obj, {x: 1, y: 2});
|
||||
});
|
||||
|
||||
it('does not corrupt ",]" / ",}" sequences inside string values', function () {
|
||||
const file = writeTmp(`{
|
||||
"url": "http://example.com/a,]b,}c",
|
||||
"text": "trailing-comma-like ,] and ,} must survive"
|
||||
}`);
|
||||
const s: any = exportedForTestingOnly.parseSettings(file, true);
|
||||
// The old replace() would have stripped the comma and produced
|
||||
// "http://example.com/a]b}c" here.
|
||||
assert.strictEqual(s.url, 'http://example.com/a,]b,}c');
|
||||
assert.strictEqual(s.text, 'trailing-comma-like ,] and ,} must survive');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -13,15 +13,16 @@
|
|||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const jsonminify = require('jsonminify');
|
||||
const {parse: parseJsonc} = require('jsonc-parser');
|
||||
|
||||
function loadSettings() {
|
||||
let settingsStr = fs.readFileSync(`${__dirname}/../../../settings.json.docker`).toString();
|
||||
// try to parse the settings
|
||||
try {
|
||||
if (settingsStr) {
|
||||
settingsStr = jsonminify(settingsStr).replace(',]', ']').replace(',}', '}');
|
||||
const settings = JSON.parse(settingsStr);
|
||||
// jsonc-parser tolerates the comments and trailing commas in the docker
|
||||
// settings file, matching node/utils/Settings.ts.
|
||||
const settings = parseJsonc(settingsStr, [], {allowTrailingComma: true});
|
||||
|
||||
// custom settings for running in a container
|
||||
settings.ip = 'localhost';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue