Skip to content

Commit 4f0fc9a

Browse files
authored
chore: upgrade lockparse (#56)
Upgrades lockparse and adds many tests.
1 parent 2741684 commit 4f0fc9a

File tree

7 files changed

+530
-43
lines changed

7 files changed

+530
-43
lines changed

build/main.js

Lines changed: 126 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23935,11 +23935,12 @@ function processPackages(input) {
2393523935
optionalDependencies: []
2393623936
};
2393723937
}
23938-
const root = packageMap[""];
2393923938
for (const [pkgKey, pkg] of Object.entries(input)) {
2394023939
const parsedPkg = packageMap[pkgKey];
2394123940
processDependencyMap(pkg, parsedPkg, packageMap, pkgKey);
2394223941
}
23942+
const root = packageMap[""];
23943+
delete packageMap[""];
2394323944
return { packages: Object.values(packageMap), root };
2394423945
}
2394523946
function processDependencyMap(pkg, parsed, packageMap, parentKey) {
@@ -23978,7 +23979,7 @@ function* createLineReader(input) {
2397823979
yield line;
2397923980
}
2398023981
}
23981-
var yamlPairPattern = /^(?<indent> *)(['"](?<key>[^"']+)["']|(?<key>[^:]+)):( (["'](?<value>[^"']+)["']|(?<value>.+)))?$/;
23982+
var yamlPairPattern = /^(?<indent> *)(['"](?<quotedKey>[^"']+)["']|(?<key>[^:]+)):( (["'](?<quotedValue>[^"']+)["']|(?<value>.+)))?$/;
2398223983
var spacePattern = /^(?<spaces> *)[^ ]/;
2398323984
function* createYamlPairReader(input) {
2398423985
const lineReader = createLineReader(input);
@@ -23991,7 +23992,9 @@ function* createYamlPairReader(input) {
2399123992
}
2399223993
const pairMatch = line.match(yamlPairPattern);
2399323994
if (pairMatch && pairMatch.groups) {
23994-
const { indent, key, value } = pairMatch.groups;
23995+
const { indent, key: unquotedKey, value: unquotedValue, quotedKey, quotedValue } = pairMatch.groups;
23996+
const key = quotedKey ?? unquotedKey;
23997+
const value = quotedValue ?? unquotedValue;
2399523998
const indentSize = indent.length;
2399623999
adjustPath(indentSize, lastIndent, lastKey, path2);
2399724000
yield {
@@ -24026,8 +24029,113 @@ function adjustPath(indentSize, lastIndent, lastKey, path2) {
2402624029

2402724030
// node_modules/lockparse/lib/parsers/yarn.js
2402824031
async function parseYarn(input, packageJson) {
24032+
const isV1 = input.includes("yarn lockfile v1");
2402924033
const packageMap = {};
24034+
if (isV1) {
24035+
processYarnV1(input, packageMap);
24036+
} else {
24037+
processYarn(input, packageMap);
24038+
}
24039+
const root = {
24040+
name: "root",
24041+
version: "",
24042+
dependencies: [],
24043+
devDependencies: [],
24044+
optionalDependencies: [],
24045+
peerDependencies: []
24046+
};
24047+
if (packageJson) {
24048+
root.version = packageJson.version ?? "";
24049+
processRootDependencies(packageJson, root, packageMap);
24050+
}
24051+
return {
24052+
type: "yarn",
24053+
packages: Object.values(packageMap),
24054+
root
24055+
};
24056+
}
24057+
var indentPattern = /^( *)/;
24058+
var quotePattern = /^['"]|['"]$/g;
24059+
function processYarnV1(input, packageMap) {
24060+
const lineReader = createLineReader(input);
24061+
let currentPackage = null;
24062+
let currentDepType = null;
24063+
for (const line of lineReader) {
24064+
if (line === "") {
24065+
continue;
24066+
}
24067+
const indentMatch = line.match(indentPattern);
24068+
const indentSize = indentMatch ? indentMatch[1].length : 0;
24069+
if (indentSize === 0 && line.endsWith(":")) {
24070+
const pkgKeys = line.slice(0, -1).split(", ");
24071+
currentPackage = null;
24072+
for (const pkgKeyRaw of pkgKeys) {
24073+
const pkgKey = pkgKeyRaw.replace(quotePattern, "");
24074+
if (!currentPackage) {
24075+
let pkg = packageMap[pkgKey];
24076+
if (!pkg) {
24077+
pkg = {
24078+
name: "",
24079+
version: "",
24080+
dependencies: [],
24081+
devDependencies: [],
24082+
optionalDependencies: [],
24083+
peerDependencies: []
24084+
};
24085+
packageMap[pkgKey] = pkg;
24086+
}
24087+
currentPackage = pkg;
24088+
if (!pkg.name) {
24089+
const separatorIndex = pkgKey.indexOf("@", 1);
24090+
const name = pkgKey.slice(0, separatorIndex);
24091+
pkg.name = name;
24092+
}
24093+
} else {
24094+
packageMap[pkgKey] = currentPackage;
24095+
}
24096+
}
24097+
continue;
24098+
}
24099+
if (indentSize === 2) {
24100+
if (line.endsWith(":")) {
24101+
const key = line.slice(indentSize, -1);
24102+
if (dependencyTypes.includes(key)) {
24103+
currentDepType = key;
24104+
}
24105+
} else {
24106+
const separatorIndex = line.indexOf(" ", indentSize);
24107+
const key = line.slice(indentSize, separatorIndex);
24108+
const value = line.slice(separatorIndex + 1);
24109+
if (key === "version" && currentPackage) {
24110+
currentPackage.version = value.replace(quotePattern, "");
24111+
}
24112+
}
24113+
continue;
24114+
}
24115+
if (indentSize === 4 && currentDepType && currentPackage) {
24116+
const separatorIndex = line.indexOf(" ", indentSize);
24117+
const depName = line.slice(indentSize, separatorIndex).replace(quotePattern, "");
24118+
const depSemver = line.slice(separatorIndex + 1).replace(quotePattern, "");
24119+
const depPkgKey = `${depName}@${depSemver}`;
24120+
let depPkg = packageMap[depPkgKey];
24121+
if (!depPkg) {
24122+
depPkg = {
24123+
name: depName,
24124+
version: "",
24125+
dependencies: [],
24126+
devDependencies: [],
24127+
optionalDependencies: [],
24128+
peerDependencies: []
24129+
};
24130+
packageMap[depPkgKey] = depPkg;
24131+
}
24132+
currentPackage[currentDepType].push(depPkg);
24133+
}
24134+
}
24135+
}
24136+
function processYarn(input, packageMap) {
2403024137
const pairReader = createYamlPairReader(input);
24138+
const optionalDependencies = [];
2403124139
for (const pair of pairReader) {
2403224140
if (pair.path.length == 0 && !pair.value && pair.key.includes("@npm:")) {
2403324141
const pkgKeys = pair.key.split(", ");
@@ -24085,24 +24193,22 @@ async function parseYarn(input, packageJson) {
2408524193
if (pkg) {
2408624194
pkg[depType].push(depPkg);
2408724195
}
24196+
} else if (pair.path.length === 3 && pair.value === "true" && pair.key === "optional" && pair.path[1] === "dependenciesMeta") {
24197+
const pkgKey = pair.path[0];
24198+
optionalDependencies.push([pkgKey, pair.path[2]]);
2408824199
}
2408924200
}
24090-
const root = {
24091-
name: "root",
24092-
version: "",
24093-
dependencies: [],
24094-
devDependencies: [],
24095-
optionalDependencies: [],
24096-
peerDependencies: []
24097-
};
24098-
if (packageJson) {
24099-
processRootDependencies(packageJson, root, packageMap);
24201+
for (const [pkgKey, depName] of optionalDependencies) {
24202+
const pkg = packageMap[pkgKey];
24203+
if (pkg) {
24204+
const deps = pkg.dependencies;
24205+
const index = deps.findIndex((d) => d.name === depName);
24206+
if (index !== -1) {
24207+
const [dep] = deps.splice(index, 1);
24208+
pkg.optionalDependencies.push(dep);
24209+
}
24210+
}
2410024211
}
24101-
return {
24102-
type: "yarn",
24103-
packages: Object.values(packageMap),
24104-
root
24105-
};
2410624212
}
2410724213
function processRootDependencies(packageJson, root, packageMap) {
2410824214
for (const depType of dependencyTypes) {
@@ -24149,7 +24255,7 @@ async function parsePnpm(input) {
2414924255
const depVersionKey = pair.value;
2415024256
const depName = pair.key;
2415124257
const depMapKey = `${depName}@${depVersionKey}`;
24152-
const depPackage = getOrCreatePackage(packageMap, depMapKey, depName, depVersionKey);
24258+
const depPackage = getOrCreatePackage(packageMap, depMapKey, depName, depVersionKey ?? void 0);
2415324259
tryAddDependency(currentPackage, dependencyType, depPackage);
2415424260
}
2415524261
}
@@ -24297,7 +24403,7 @@ function parse(input, typeOrFileName, packageJson) {
2429724403
}
2429824404

2429924405
// src/lockfile.ts
24300-
import { existsSync, readFileSync } from "node:fs";
24406+
import { existsSync } from "node:fs";
2430124407
import { join } from "node:path";
2430224408
var supportedLockfiles = [
2430324409
"pnpm-lock.yaml",

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"@types/node": "^24.7.2",
4545
"esbuild": "^0.25.10",
4646
"eslint": "^9.37.0",
47-
"lockparse": "^0.2.1",
47+
"lockparse": "^0.3.0",
4848
"module-replacements": "^2.9.0",
4949
"pkg-types": "^2.3.0",
5050
"prettier": "^3.6.2",

src/lockfile.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type {ParsedLockFile} from 'lockparse';
2-
import {existsSync, readFileSync} from 'node:fs';
2+
import {existsSync} from 'node:fs';
33
import {join} from 'node:path';
44

55
export type VersionsSet = Map<string, Set<string>>;
@@ -31,10 +31,6 @@ export function detectLockfile(workspacePath: string): string | undefined {
3131
return undefined;
3232
}
3333

34-
export function readTextFile(path: string): string {
35-
return readFileSync(path, 'utf8');
36-
}
37-
3834
function addVersion(map: VersionsSet, name: string, version: string): void {
3935
let set = map.get(name);
4036
if (!set) {

test/git_test.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {describe, it, expect, beforeEach, vi} from 'vitest';
1+
import {describe, it, expect} from 'vitest';
22
import * as git from '../src/git.js';
33
import * as github from '@actions/github';
44
import * as process from 'process';
@@ -60,17 +60,6 @@ describe('getBaseRef', () => {
6060
});
6161

6262
describe('getFileFromRef', () => {
63-
beforeEach(() => {
64-
vi.mock(import('@actions/core'), async (importModule) => {
65-
const mod = await importModule();
66-
return {
67-
...mod,
68-
info: vi.fn(),
69-
error: vi.fn()
70-
};
71-
});
72-
});
73-
7463
it('should return file content from a given ref', () => {
7564
const content = git.getFileFromRef('HEAD', 'package.json', rootDir);
7665
expect(content).toBeDefined();
@@ -82,3 +71,21 @@ describe('getFileFromRef', () => {
8271
expect(content).toBeNull();
8372
});
8473
});
74+
75+
describe('tryGetJSONFromRef', () => {
76+
it('returns null for non-existent file', () => {
77+
const result = git.tryGetJSONFromRef('HEAD', 'nonexistent.json', rootDir);
78+
expect(result).toBeNull();
79+
});
80+
81+
it('returns null for invalid JSON content', () => {
82+
const result = git.tryGetJSONFromRef('HEAD', 'README.md', rootDir);
83+
expect(result).toBeNull();
84+
});
85+
86+
it('returns parsed JSON object for valid JSON content', () => {
87+
const result = git.tryGetJSONFromRef('HEAD', 'package.json', rootDir);
88+
expect(result).toBeDefined();
89+
expect(result).toHaveProperty('name');
90+
});
91+
});

0 commit comments

Comments
 (0)