Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 136 additions & 22 deletions build/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -23935,11 +23935,12 @@ function processPackages(input) {
optionalDependencies: []
};
}
const root = packageMap[""];
for (const [pkgKey, pkg] of Object.entries(input)) {
const parsedPkg = packageMap[pkgKey];
processDependencyMap(pkg, parsedPkg, packageMap, pkgKey);
}
const root = packageMap[""];
delete packageMap[""];
return { packages: Object.values(packageMap), root };
}
function processDependencyMap(pkg, parsed, packageMap, parentKey) {
Expand Down Expand Up @@ -23978,7 +23979,7 @@ function* createLineReader(input) {
yield line;
}
}
var yamlPairPattern = /^(?<indent> *)(['"](?<key>[^"']+)["']|(?<key>[^:]+)):( (["'](?<value>[^"']+)["']|(?<value>.+)))?$/;
var yamlPairPattern = /^(?<indent> *)(['"](?<quotedKey>[^"']+)["']|(?<key>[^:]+)):( (["'](?<quotedValue>[^"']+)["']|(?<value>.+)))?$/;
var spacePattern = /^(?<spaces> *)[^ ]/;
function* createYamlPairReader(input) {
const lineReader = createLineReader(input);
Expand All @@ -23991,7 +23992,9 @@ function* createYamlPairReader(input) {
}
const pairMatch = line.match(yamlPairPattern);
if (pairMatch && pairMatch.groups) {
const { indent, key, value } = pairMatch.groups;
const { indent, key: unquotedKey, value: unquotedValue, quotedKey, quotedValue } = pairMatch.groups;
const key = quotedKey ?? unquotedKey;
const value = quotedValue ?? unquotedValue;
const indentSize = indent.length;
adjustPath(indentSize, lastIndent, lastKey, path2);
yield {
Expand Down Expand Up @@ -24026,8 +24029,113 @@ function adjustPath(indentSize, lastIndent, lastKey, path2) {

// node_modules/lockparse/lib/parsers/yarn.js
async function parseYarn(input, packageJson) {
const isV1 = input.includes("yarn lockfile v1");
const packageMap = {};
if (isV1) {
processYarnV1(input, packageMap);
} else {
processYarn(input, packageMap);
}
const root = {
name: "root",
version: "",
dependencies: [],
devDependencies: [],
optionalDependencies: [],
peerDependencies: []
};
if (packageJson) {
root.version = packageJson.version ?? "";
processRootDependencies(packageJson, root, packageMap);
}
return {
type: "yarn",
packages: Object.values(packageMap),
root
};
}
var indentPattern = /^( *)/;
var quotePattern = /^['"]|['"]$/g;
function processYarnV1(input, packageMap) {
const lineReader = createLineReader(input);
let currentPackage = null;
let currentDepType = null;
for (const line of lineReader) {
if (line === "") {
continue;
}
const indentMatch = line.match(indentPattern);
const indentSize = indentMatch ? indentMatch[1].length : 0;
if (indentSize === 0 && line.endsWith(":")) {
const pkgKeys = line.slice(0, -1).split(", ");
currentPackage = null;
for (const pkgKeyRaw of pkgKeys) {
const pkgKey = pkgKeyRaw.replace(quotePattern, "");
if (!currentPackage) {
let pkg = packageMap[pkgKey];
if (!pkg) {
pkg = {
name: "",
version: "",
dependencies: [],
devDependencies: [],
optionalDependencies: [],
peerDependencies: []
};
packageMap[pkgKey] = pkg;
}
currentPackage = pkg;
if (!pkg.name) {
const separatorIndex = pkgKey.indexOf("@", 1);
const name = pkgKey.slice(0, separatorIndex);
pkg.name = name;
}
} else {
packageMap[pkgKey] = currentPackage;
}
}
continue;
}
if (indentSize === 2) {
if (line.endsWith(":")) {
const key = line.slice(indentSize, -1);
if (dependencyTypes.includes(key)) {
currentDepType = key;
}
} else {
const separatorIndex = line.indexOf(" ", indentSize);
const key = line.slice(indentSize, separatorIndex);
const value = line.slice(separatorIndex + 1);
if (key === "version" && currentPackage) {
currentPackage.version = value.replace(quotePattern, "");
}
}
continue;
}
if (indentSize === 4 && currentDepType && currentPackage) {
const separatorIndex = line.indexOf(" ", indentSize);
const depName = line.slice(indentSize, separatorIndex).replace(quotePattern, "");
const depSemver = line.slice(separatorIndex + 1).replace(quotePattern, "");
const depPkgKey = `${depName}@${depSemver}`;
let depPkg = packageMap[depPkgKey];
if (!depPkg) {
depPkg = {
name: depName,
version: "",
dependencies: [],
devDependencies: [],
optionalDependencies: [],
peerDependencies: []
};
packageMap[depPkgKey] = depPkg;
}
currentPackage[currentDepType].push(depPkg);
}
}
}
function processYarn(input, packageMap) {
const pairReader = createYamlPairReader(input);
const optionalDependencies = [];
for (const pair of pairReader) {
if (pair.path.length == 0 && !pair.value && pair.key.includes("@npm:")) {
const pkgKeys = pair.key.split(", ");
Expand Down Expand Up @@ -24085,24 +24193,22 @@ async function parseYarn(input, packageJson) {
if (pkg) {
pkg[depType].push(depPkg);
}
} else if (pair.path.length === 3 && pair.value === "true" && pair.key === "optional" && pair.path[1] === "dependenciesMeta") {
const pkgKey = pair.path[0];
optionalDependencies.push([pkgKey, pair.path[2]]);
}
}
const root = {
name: "root",
version: "",
dependencies: [],
devDependencies: [],
optionalDependencies: [],
peerDependencies: []
};
if (packageJson) {
processRootDependencies(packageJson, root, packageMap);
for (const [pkgKey, depName] of optionalDependencies) {
const pkg = packageMap[pkgKey];
if (pkg) {
const deps = pkg.dependencies;
const index = deps.findIndex((d) => d.name === depName);
if (index !== -1) {
const [dep] = deps.splice(index, 1);
pkg.optionalDependencies.push(dep);
}
}
}
return {
type: "yarn",
packages: Object.values(packageMap),
root
};
}
function processRootDependencies(packageJson, root, packageMap) {
for (const depType of dependencyTypes) {
Expand Down Expand Up @@ -24149,7 +24255,7 @@ async function parsePnpm(input) {
const depVersionKey = pair.value;
const depName = pair.key;
const depMapKey = `${depName}@${depVersionKey}`;
const depPackage = getOrCreatePackage(packageMap, depMapKey, depName, depVersionKey);
const depPackage = getOrCreatePackage(packageMap, depMapKey, depName, depVersionKey ?? void 0);
tryAddDependency(currentPackage, dependencyType, depPackage);
}
}
Expand Down Expand Up @@ -24297,7 +24403,7 @@ function parse(input, typeOrFileName, packageJson) {
}

// src/lockfile.ts
import { existsSync, readFileSync } from "node:fs";
import { existsSync } from "node:fs";
import { join } from "node:path";
var supportedLockfiles = [
"pnpm-lock.yaml",
Expand Down Expand Up @@ -24974,13 +25080,21 @@ async function run() {
let parsedCurrentLock;
let parsedBaseLock;
try {
parsedCurrentLock = await parse(currentPackageLock, lockfilePath, currentPackageJson ?? void 0);
parsedCurrentLock = await parse(
currentPackageLock,
lockfilePath,
currentPackageJson ?? void 0
);
} catch (err) {
core7.setFailed(`Failed to parse current lockfile: ${err}`);
return;
}
try {
parsedBaseLock = await parse(basePackageLock, lockfilePath, basePackageJson ?? void 0);
parsedBaseLock = await parse(
basePackageLock,
lockfilePath,
basePackageJson ?? void 0
);
} catch (err) {
core7.setFailed(`Failed to parse base lockfile: ${err}`);
return;
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"@types/node": "^24.7.0",
"esbuild": "^0.25.10",
"eslint": "^9.37.0",
"lockparse": "^0.2.1",
"lockparse": "^0.3.0",
"module-replacements": "^2.9.0",
"pkg-types": "^2.3.0",
"prettier": "^3.6.2",
Expand Down
6 changes: 1 addition & 5 deletions src/lockfile.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {ParsedLockFile} from 'lockparse';
import {existsSync, readFileSync} from 'node:fs';
import {existsSync} from 'node:fs';
import {join} from 'node:path';

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

export function readTextFile(path: string): string {
return readFileSync(path, 'utf8');
}

function addVersion(map: VersionsSet, name: string, version: string): void {
let set = map.get(name);
if (!set) {
Expand Down
31 changes: 19 additions & 12 deletions test/git_test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {describe, it, expect, beforeEach, vi} from 'vitest';
import {describe, it, expect} from 'vitest';
import * as git from '../src/git.js';
import * as github from '@actions/github';
import * as process from 'process';
Expand Down Expand Up @@ -60,17 +60,6 @@ describe('getBaseRef', () => {
});

describe('getFileFromRef', () => {
beforeEach(() => {
vi.mock(import('@actions/core'), async (importModule) => {
const mod = await importModule();
return {
...mod,
info: vi.fn(),
error: vi.fn()
};
});
});

it('should return file content from a given ref', () => {
const content = git.getFileFromRef('HEAD', 'package.json', rootDir);
expect(content).toBeDefined();
Expand All @@ -82,3 +71,21 @@ describe('getFileFromRef', () => {
expect(content).toBeNull();
});
});

describe('tryGetJSONFromRef', () => {
it('returns null for non-existent file', () => {
const result = git.tryGetJSONFromRef('HEAD', 'nonexistent.json', rootDir);
expect(result).toBeNull();
});

it('returns null for invalid JSON content', () => {
const result = git.tryGetJSONFromRef('HEAD', 'README.md', rootDir);
expect(result).toBeNull();
});

it('returns parsed JSON object for valid JSON content', () => {
const result = git.tryGetJSONFromRef('HEAD', 'package.json', rootDir);
expect(result).toBeDefined();
expect(result).toHaveProperty('name');
});
});
Loading