aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/api/schema.d.ts98
-rw-r--r--src/api/schema.js421
-rw-r--r--src/api/schema.peechy62
-rw-r--r--src/api/schema.zig326
-rw-r--r--src/cli/install_command.zig42
-rw-r--r--src/install/install.zig29
-rw-r--r--src/install/semver.zig394
7 files changed, 1372 insertions, 0 deletions
diff --git a/src/api/schema.d.ts b/src/api/schema.d.ts
index d00dcfa6e..36be0a593 100644
--- a/src/api/schema.d.ts
+++ b/src/api/schema.d.ts
@@ -256,6 +256,22 @@ export const WebsocketCommandKindKeys = {
2: "manifest",
manifest: "manifest",
};
+export enum NPMPackageDataKind {
+ tarball = 1,
+ http = 2,
+ symlink = 3,
+ workspace = 4,
+}
+export const NPMPackageDataKindKeys = {
+ 1: "tarball",
+ tarball: "tarball",
+ 2: "http",
+ http: "http",
+ 3: "symlink",
+ symlink: "symlink",
+ 4: "workspace",
+ workspace: "workspace",
+};
export interface StackFrame {
function_name: string;
file: string;
@@ -608,6 +624,58 @@ export interface WebsocketMessageManifestFailure {
log: Log;
}
+export interface SemverQualifier {
+ pre?: string;
+ build?: string;
+}
+
+export interface Semver {
+ major: uint32;
+ minor: uint32;
+ patch: uint32;
+ raw: StringPointer;
+ qualifiers: SemverQualifier[];
+}
+
+export interface NPMPackageData {
+ kind: NPMPackageDataKind;
+ value: StringPointer;
+ integrity: StringPointer;
+ destination: StringPointer;
+}
+
+export interface NPMPackage {
+ id: uint32;
+ name: StringPointer;
+ version: StringPointer;
+ resolution: Semver;
+ data: NPMPackageData;
+ dependencies_hash: uint32;
+ dev_dependencies_hash: uint32;
+ peer_dependencies_hash: uint32;
+ optional_dependencies_hash: uint32;
+ dependencies: DependencyResolution[];
+}
+
+export interface DependencyResolution {
+ version: Semver;
+ package: uint32;
+ required: boolean;
+ optional: boolean;
+ peer: boolean;
+ dev: boolean;
+}
+
+export interface Lockfile {
+ version?: string;
+ registry?: string;
+ root?: uint32;
+ hashes?: Uint32Array;
+ name_hashes?: Uint32Array;
+ packages?: NPMPackage[];
+ blob?: Uint8Array;
+}
+
export declare function encodeStackFrame(
message: StackFrame,
bb: ByteBuffer
@@ -897,3 +965,33 @@ export declare function encodeWebsocketMessageManifestFailure(
export declare function decodeWebsocketMessageManifestFailure(
buffer: ByteBuffer
): WebsocketMessageManifestFailure;
+export declare function encodeSemverQualifier(
+ message: SemverQualifier,
+ bb: ByteBuffer
+): void;
+export declare function decodeSemverQualifier(
+ buffer: ByteBuffer
+): SemverQualifier;
+export declare function encodeSemver(message: Semver, bb: ByteBuffer): void;
+export declare function decodeSemver(buffer: ByteBuffer): Semver;
+export declare function encodeNPMPackageData(
+ message: NPMPackageData,
+ bb: ByteBuffer
+): void;
+export declare function decodeNPMPackageData(
+ buffer: ByteBuffer
+): NPMPackageData;
+export declare function encodeNPMPackage(
+ message: NPMPackage,
+ bb: ByteBuffer
+): void;
+export declare function decodeNPMPackage(buffer: ByteBuffer): NPMPackage;
+export declare function encodeDependencyResolution(
+ message: DependencyResolution,
+ bb: ByteBuffer
+): void;
+export declare function decodeDependencyResolution(
+ buffer: ByteBuffer
+): DependencyResolution;
+export declare function encodeLockfile(message: Lockfile, bb: ByteBuffer): void;
+export declare function decodeLockfile(buffer: ByteBuffer): Lockfile;
diff --git a/src/api/schema.js b/src/api/schema.js
index dc89e2b11..80ab949aa 100644
--- a/src/api/schema.js
+++ b/src/api/schema.js
@@ -2863,6 +2863,413 @@ function encodeWebsocketMessageManifestFailure(message, bb) {
}
}
+function decodeSemverQualifier(bb) {
+ var result = {};
+
+ while (true) {
+ switch (bb.readByte()) {
+ case 0:
+ return result;
+
+ case 1:
+ result["pre"] = bb.readString();
+ break;
+
+ case 2:
+ result["build"] = bb.readString();
+ break;
+
+ default:
+ throw new Error("Attempted to parse invalid message");
+ }
+ }
+}
+
+function encodeSemverQualifier(message, bb) {
+ var value = message["pre"];
+ if (value != null) {
+ bb.writeByte(1);
+ bb.writeString(value);
+ }
+
+ var value = message["build"];
+ if (value != null) {
+ bb.writeByte(2);
+ bb.writeString(value);
+ }
+ bb.writeByte(0);
+}
+
+function decodeSemver(bb) {
+ var result = {};
+
+ result["major"] = bb.readUint32();
+ result["minor"] = bb.readUint32();
+ result["patch"] = bb.readUint32();
+ result["raw"] = decodeStringPointer(bb);
+ var length = bb.readVarUint();
+ var values = (result["qualifiers"] = Array(length));
+ for (var i = 0; i < length; i++) values[i] = decodeSemverQualifier(bb);
+ return result;
+}
+
+function encodeSemver(message, bb) {
+ var value = message["major"];
+ if (value != null) {
+ bb.writeUint32(value);
+ } else {
+ throw new Error('Missing required field "major"');
+ }
+
+ var value = message["minor"];
+ if (value != null) {
+ bb.writeUint32(value);
+ } else {
+ throw new Error('Missing required field "minor"');
+ }
+
+ var value = message["patch"];
+ if (value != null) {
+ bb.writeUint32(value);
+ } else {
+ throw new Error('Missing required field "patch"');
+ }
+
+ var value = message["raw"];
+ if (value != null) {
+ encodeStringPointer(value, bb);
+ } else {
+ throw new Error('Missing required field "raw"');
+ }
+
+ var value = message["qualifiers"];
+ if (value != null) {
+ var values = value,
+ n = values.length;
+ bb.writeVarUint(n);
+ for (var i = 0; i < n; i++) {
+ value = values[i];
+ encodeSemverQualifier(value, bb);
+ }
+ } else {
+ throw new Error('Missing required field "qualifiers"');
+ }
+}
+const NPMPackageDataKind = {
+ 1: 1,
+ 2: 2,
+ 3: 3,
+ 4: 4,
+ tarball: 1,
+ http: 2,
+ symlink: 3,
+ workspace: 4,
+};
+const NPMPackageDataKindKeys = {
+ 1: "tarball",
+ 2: "http",
+ 3: "symlink",
+ 4: "workspace",
+ tarball: "tarball",
+ http: "http",
+ symlink: "symlink",
+ workspace: "workspace",
+};
+
+function decodeNPMPackageData(bb) {
+ var result = {};
+
+ result["kind"] = NPMPackageDataKind[bb.readVarUint()];
+ result["value"] = decodeStringPointer(bb);
+ result["integrity"] = decodeStringPointer(bb);
+ result["destination"] = decodeStringPointer(bb);
+ return result;
+}
+
+function encodeNPMPackageData(message, bb) {
+ var value = message["kind"];
+ if (value != null) {
+ var encoded = NPMPackageDataKind[value];
+ if (encoded === void 0)
+ throw new Error(
+ "Invalid value " +
+ JSON.stringify(value) +
+ ' for enum "NPMPackageDataKind"'
+ );
+ bb.writeVarUint(encoded);
+ } else {
+ throw new Error('Missing required field "kind"');
+ }
+
+ var value = message["value"];
+ if (value != null) {
+ encodeStringPointer(value, bb);
+ } else {
+ throw new Error('Missing required field "value"');
+ }
+
+ var value = message["integrity"];
+ if (value != null) {
+ encodeStringPointer(value, bb);
+ } else {
+ throw new Error('Missing required field "integrity"');
+ }
+
+ var value = message["destination"];
+ if (value != null) {
+ encodeStringPointer(value, bb);
+ } else {
+ throw new Error('Missing required field "destination"');
+ }
+}
+
+function decodeNPMPackage(bb) {
+ var result = {};
+
+ result["id"] = bb.readUint32();
+ result["name"] = decodeStringPointer(bb);
+ result["version"] = decodeStringPointer(bb);
+ result["resolution"] = decodeSemver(bb);
+ result["data"] = decodeNPMPackageData(bb);
+ result["dependencies_hash"] = bb.readUint32();
+ result["dev_dependencies_hash"] = bb.readUint32();
+ result["peer_dependencies_hash"] = bb.readUint32();
+ result["optional_dependencies_hash"] = bb.readUint32();
+ var length = bb.readVarUint();
+ var values = (result["dependencies"] = Array(length));
+ for (var i = 0; i < length; i++) values[i] = decodeDependencyResolution(bb);
+ return result;
+}
+
+function encodeNPMPackage(message, bb) {
+ var value = message["id"];
+ if (value != null) {
+ bb.writeUint32(value);
+ } else {
+ throw new Error('Missing required field "id"');
+ }
+
+ var value = message["name"];
+ if (value != null) {
+ encodeStringPointer(value, bb);
+ } else {
+ throw new Error('Missing required field "name"');
+ }
+
+ var value = message["version"];
+ if (value != null) {
+ encodeStringPointer(value, bb);
+ } else {
+ throw new Error('Missing required field "version"');
+ }
+
+ var value = message["resolution"];
+ if (value != null) {
+ encodeSemver(value, bb);
+ } else {
+ throw new Error('Missing required field "resolution"');
+ }
+
+ var value = message["data"];
+ if (value != null) {
+ encodeNPMPackageData(value, bb);
+ } else {
+ throw new Error('Missing required field "data"');
+ }
+
+ var value = message["dependencies_hash"];
+ if (value != null) {
+ bb.writeUint32(value);
+ } else {
+ throw new Error('Missing required field "dependencies_hash"');
+ }
+
+ var value = message["dev_dependencies_hash"];
+ if (value != null) {
+ bb.writeUint32(value);
+ } else {
+ throw new Error('Missing required field "dev_dependencies_hash"');
+ }
+
+ var value = message["peer_dependencies_hash"];
+ if (value != null) {
+ bb.writeUint32(value);
+ } else {
+ throw new Error('Missing required field "peer_dependencies_hash"');
+ }
+
+ var value = message["optional_dependencies_hash"];
+ if (value != null) {
+ bb.writeUint32(value);
+ } else {
+ throw new Error('Missing required field "optional_dependencies_hash"');
+ }
+
+ var value = message["dependencies"];
+ if (value != null) {
+ var values = value,
+ n = values.length;
+ bb.writeVarUint(n);
+ for (var i = 0; i < n; i++) {
+ value = values[i];
+ encodeDependencyResolution(value, bb);
+ }
+ } else {
+ throw new Error('Missing required field "dependencies"');
+ }
+}
+
+function decodeDependencyResolution(bb) {
+ var result = {};
+
+ result["version"] = decodeSemver(bb);
+ result["package"] = bb.readUint32();
+ result["required"] = !!bb.readByte();
+ result["optional"] = !!bb.readByte();
+ result["peer"] = !!bb.readByte();
+ result["dev"] = !!bb.readByte();
+ return result;
+}
+
+function encodeDependencyResolution(message, bb) {
+ var value = message["version"];
+ if (value != null) {
+ encodeSemver(value, bb);
+ } else {
+ throw new Error('Missing required field "version"');
+ }
+
+ var value = message["package"];
+ if (value != null) {
+ bb.writeUint32(value);
+ } else {
+ throw new Error('Missing required field "package"');
+ }
+
+ var value = message["required"];
+ if (value != null) {
+ bb.writeByte(value);
+ } else {
+ throw new Error('Missing required field "required"');
+ }
+
+ var value = message["optional"];
+ if (value != null) {
+ bb.writeByte(value);
+ } else {
+ throw new Error('Missing required field "optional"');
+ }
+
+ var value = message["peer"];
+ if (value != null) {
+ bb.writeByte(value);
+ } else {
+ throw new Error('Missing required field "peer"');
+ }
+
+ var value = message["dev"];
+ if (value != null) {
+ bb.writeByte(value);
+ } else {
+ throw new Error('Missing required field "dev"');
+ }
+}
+
+function decodeLockfile(bb) {
+ var result = {};
+
+ while (true) {
+ switch (bb.readByte()) {
+ case 0:
+ return result;
+
+ case 1:
+ result["version"] = bb.readString();
+ break;
+
+ case 2:
+ result["registry"] = bb.readString();
+ break;
+
+ case 3:
+ result["root"] = bb.readUint32();
+ break;
+
+ case 4:
+ result["hashes"] = bb.readUint32ByteArray();
+ break;
+
+ case 5:
+ result["name_hashes"] = bb.readUint32ByteArray();
+ break;
+
+ case 6:
+ var length = bb.readVarUint();
+ var values = (result["packages"] = Array(length));
+ for (var i = 0; i < length; i++) values[i] = decodeNPMPackage(bb);
+ break;
+
+ case 7:
+ result["blob"] = bb.readByteArray();
+ break;
+
+ default:
+ throw new Error("Attempted to parse invalid message");
+ }
+ }
+}
+
+function encodeLockfile(message, bb) {
+ var value = message["version"];
+ if (value != null) {
+ bb.writeByte(1);
+ bb.writeString(value);
+ }
+
+ var value = message["registry"];
+ if (value != null) {
+ bb.writeByte(2);
+ bb.writeString(value);
+ }
+
+ var value = message["root"];
+ if (value != null) {
+ bb.writeByte(3);
+ bb.writeUint32(value);
+ }
+
+ var value = message["hashes"];
+ if (value != null) {
+ bb.writeByte(4);
+ bb.writeUint32ByteArray(value);
+ }
+
+ var value = message["name_hashes"];
+ if (value != null) {
+ bb.writeByte(5);
+ bb.writeUint32ByteArray(value);
+ }
+
+ var value = message["packages"];
+ if (value != null) {
+ bb.writeByte(6);
+ var values = value,
+ n = values.length;
+ bb.writeVarUint(n);
+ for (var i = 0; i < n; i++) {
+ value = values[i];
+ encodeNPMPackage(value, bb);
+ }
+ }
+
+ var value = message["blob"];
+ if (value != null) {
+ bb.writeByte(7);
+ bb.writeByteArray(value);
+ }
+ bb.writeByte(0);
+}
+
export { Loader };
export { LoaderKeys };
export { FrameworkEntryPointType };
@@ -2997,3 +3404,17 @@ export { decodeWebsocketMessageManifestSuccess };
export { encodeWebsocketMessageManifestSuccess };
export { decodeWebsocketMessageManifestFailure };
export { encodeWebsocketMessageManifestFailure };
+export { decodeSemverQualifier };
+export { encodeSemverQualifier };
+export { decodeSemver };
+export { encodeSemver };
+export { NPMPackageDataKind };
+export { NPMPackageDataKindKeys };
+export { decodeNPMPackageData };
+export { encodeNPMPackageData };
+export { decodeNPMPackage };
+export { encodeNPMPackage };
+export { decodeDependencyResolution };
+export { encodeDependencyResolution };
+export { decodeLockfile };
+export { encodeLockfile };
diff --git a/src/api/schema.peechy b/src/api/schema.peechy
index 2cc78504a..035a7fa26 100644
--- a/src/api/schema.peechy
+++ b/src/api/schema.peechy
@@ -537,4 +537,66 @@ struct WebsocketMessageManifestFailure {
Log log;
}
+message SemverQualifier {
+ string pre = 1;
+ string build = 2;
+}
+
+struct Semver {
+ uint32 major;
+ uint32 minor;
+ uint32 patch;
+ StringPointer raw;
+ SemverQualifier[] qualifiers;
+}
+
+enum NPMPackageDataKind {
+ tarball = 1;
+ http = 2;
+ symlink = 3;
+ workspace = 4;
+}
+
+struct NPMPackageData {
+ NPMPackageDataKind kind;
+ StringPointer value;
+ StringPointer integrity;
+ StringPointer destination;
+}
+
+struct NPMPackage {
+ uint32 id;
+
+ StringPointer name;
+ StringPointer version;
+ Semver resolution;
+ NPMPackageData data;
+
+ uint32 dependencies_hash;
+ uint32 dev_dependencies_hash;
+ uint32 peer_dependencies_hash;
+ uint32 optional_dependencies_hash;
+
+ DependencyResolution[] dependencies;
+}
+
+struct DependencyResolution {
+ Semver version;
+ uint32 package;
+
+ bool required;
+ bool optional;
+ bool peer;
+ bool dev;
+}
+
+message Lockfile {
+ string version = 1;
+ string registry = 2;
+ uint32 root = 3;
+ uint32[] hashes = 4;
+ uint32[] name_hashes = 5;
+ NPMPackage[] packages = 6;
+ byte[] blob = 7;
+}
diff --git a/src/api/schema.zig b/src/api/schema.zig
index 45589a431..3c27a7fad 100644
--- a/src/api/schema.zig
+++ b/src/api/schema.zig
@@ -2693,4 +2693,330 @@ pub const Api = struct {
try writer.writeValue(@TypeOf(this.log), this.log);
}
};
+
+ pub const SemverQualifier = struct {
+ /// pre
+ pre: ?[]const u8 = null,
+
+ /// build
+ build: ?[]const u8 = null,
+
+ pub fn decode(reader: anytype) anyerror!SemverQualifier {
+ var this = std.mem.zeroes(SemverQualifier);
+
+ while (true) {
+ switch (try reader.readByte()) {
+ 0 => {
+ return this;
+ },
+
+ 1 => {
+ this.pre = try reader.readValue([]const u8);
+ },
+ 2 => {
+ this.build = try reader.readValue([]const u8);
+ },
+ else => {
+ return error.InvalidMessage;
+ },
+ }
+ }
+ unreachable;
+ }
+
+ pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
+ if (this.pre) |pre| {
+ try writer.writeFieldID(1);
+ try writer.writeValue(@TypeOf(pre), pre);
+ }
+ if (this.build) |build| {
+ try writer.writeFieldID(2);
+ try writer.writeValue(@TypeOf(build), build);
+ }
+ try writer.endMessage();
+ }
+ };
+
+ pub const Semver = struct {
+ /// major
+ major: u32 = 0,
+
+ /// minor
+ minor: u32 = 0,
+
+ /// patch
+ patch: u32 = 0,
+
+ /// raw
+ raw: StringPointer,
+
+ /// qualifiers
+ qualifiers: []const SemverQualifier,
+
+ pub fn decode(reader: anytype) anyerror!Semver {
+ var this = std.mem.zeroes(Semver);
+
+ this.major = try reader.readValue(u32);
+ this.minor = try reader.readValue(u32);
+ this.patch = try reader.readValue(u32);
+ this.raw = try reader.readValue(StringPointer);
+ this.qualifiers = try reader.readArray(SemverQualifier);
+ return this;
+ }
+
+ pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
+ try writer.writeInt(this.major);
+ try writer.writeInt(this.minor);
+ try writer.writeInt(this.patch);
+ try writer.writeValue(@TypeOf(this.raw), this.raw);
+ try writer.writeArray(SemverQualifier, this.qualifiers);
+ }
+ };
+
+ pub const NpmPackageDataKind = enum(u32) {
+ _none,
+ /// tarball
+ tarball,
+
+ /// http
+ http,
+
+ /// symlink
+ symlink,
+
+ /// workspace
+ workspace,
+
+ _,
+
+ pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void {
+ return try std.json.stringify(@tagName(self), opts, o);
+ }
+ };
+
+ pub const NpmPackageData = struct {
+ /// kind
+ kind: NpmPackageDataKind,
+
+ /// value
+ value: StringPointer,
+
+ /// integrity
+ integrity: StringPointer,
+
+ /// destination
+ destination: StringPointer,
+
+ pub fn decode(reader: anytype) anyerror!NpmPackageData {
+ var this = std.mem.zeroes(NpmPackageData);
+
+ this.kind = try reader.readValue(NpmPackageDataKind);
+ this.value = try reader.readValue(StringPointer);
+ this.integrity = try reader.readValue(StringPointer);
+ this.destination = try reader.readValue(StringPointer);
+ return this;
+ }
+
+ pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
+ try writer.writeEnum(this.kind);
+ try writer.writeValue(@TypeOf(this.value), this.value);
+ try writer.writeValue(@TypeOf(this.integrity), this.integrity);
+ try writer.writeValue(@TypeOf(this.destination), this.destination);
+ }
+ };
+
+ pub const NpmPackage = struct {
+ /// id
+ id: u32 = 0,
+
+ /// name
+ name: StringPointer,
+
+ /// version
+ version: StringPointer,
+
+ /// resolution
+ resolution: Semver,
+
+ /// data
+ data: NpmPackageData,
+
+ /// dependencies_hash
+ dependencies_hash: u32 = 0,
+
+ /// dev_dependencies_hash
+ dev_dependencies_hash: u32 = 0,
+
+ /// peer_dependencies_hash
+ peer_dependencies_hash: u32 = 0,
+
+ /// optional_dependencies_hash
+ optional_dependencies_hash: u32 = 0,
+
+ /// dependencies
+ dependencies: []const DependencyResolution,
+
+ pub fn decode(reader: anytype) anyerror!NpmPackage {
+ var this = std.mem.zeroes(NpmPackage);
+
+ this.id = try reader.readValue(u32);
+ this.name = try reader.readValue(StringPointer);
+ this.version = try reader.readValue(StringPointer);
+ this.resolution = try reader.readValue(Semver);
+ this.data = try reader.readValue(NpmPackageData);
+ this.dependencies_hash = try reader.readValue(u32);
+ this.dev_dependencies_hash = try reader.readValue(u32);
+ this.peer_dependencies_hash = try reader.readValue(u32);
+ this.optional_dependencies_hash = try reader.readValue(u32);
+ this.dependencies = try reader.readArray(DependencyResolution);
+ return this;
+ }
+
+ pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
+ try writer.writeInt(this.id);
+ try writer.writeValue(@TypeOf(this.name), this.name);
+ try writer.writeValue(@TypeOf(this.version), this.version);
+ try writer.writeValue(@TypeOf(this.resolution), this.resolution);
+ try writer.writeValue(@TypeOf(this.data), this.data);
+ try writer.writeInt(this.dependencies_hash);
+ try writer.writeInt(this.dev_dependencies_hash);
+ try writer.writeInt(this.peer_dependencies_hash);
+ try writer.writeInt(this.optional_dependencies_hash);
+ try writer.writeArray(DependencyResolution, this.dependencies);
+ }
+ };
+
+ pub const DependencyResolution = struct {
+ /// version
+ version: Semver,
+
+ /// package
+ package: u32 = 0,
+
+ /// required
+ required: bool = false,
+
+ /// optional
+ optional: bool = false,
+
+ /// peer
+ peer: bool = false,
+
+ /// dev
+ dev: bool = false,
+
+ pub fn decode(reader: anytype) anyerror!DependencyResolution {
+ var this = std.mem.zeroes(DependencyResolution);
+
+ this.version = try reader.readValue(Semver);
+ this.package = try reader.readValue(u32);
+ this.required = try reader.readValue(bool);
+ this.optional = try reader.readValue(bool);
+ this.peer = try reader.readValue(bool);
+ this.dev = try reader.readValue(bool);
+ return this;
+ }
+
+ pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
+ try writer.writeValue(@TypeOf(this.version), this.version);
+ try writer.writeInt(this.package);
+ try writer.writeInt(@as(u8, @boolToInt(this.required)));
+ try writer.writeInt(@as(u8, @boolToInt(this.optional)));
+ try writer.writeInt(@as(u8, @boolToInt(this.peer)));
+ try writer.writeInt(@as(u8, @boolToInt(this.dev)));
+ }
+ };
+
+ pub const Lockfile = struct {
+ /// version
+ version: ?[]const u8 = null,
+
+ /// registry
+ registry: ?[]const u8 = null,
+
+ /// root
+ root: ?u32 = null,
+
+ /// hashes
+ hashes: []const u32,
+
+ /// name_hashes
+ name_hashes: []const u32,
+
+ /// packages
+ packages: []const NpmPackage,
+
+ /// blob
+ blob: []const u8,
+
+ pub fn decode(reader: anytype) anyerror!Lockfile {
+ var this = std.mem.zeroes(Lockfile);
+
+ while (true) {
+ switch (try reader.readByte()) {
+ 0 => {
+ return this;
+ },
+
+ 1 => {
+ this.version = try reader.readValue([]const u8);
+ },
+ 2 => {
+ this.registry = try reader.readValue([]const u8);
+ },
+ 3 => {
+ this.root = try reader.readValue(u32);
+ },
+ 4 => {
+ this.hashes = try reader.readArray(u32);
+ },
+ 5 => {
+ this.name_hashes = try reader.readArray(u32);
+ },
+ 6 => {
+ this.packages = try reader.readArray(NpmPackage);
+ },
+ 7 => {
+ this.blob = try reader.readArray(u8);
+ },
+ else => {
+ return error.InvalidMessage;
+ },
+ }
+ }
+ unreachable;
+ }
+
+ pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
+ if (this.version) |version| {
+ try writer.writeFieldID(1);
+ try writer.writeValue(@TypeOf(version), version);
+ }
+ if (this.registry) |registry| {
+ try writer.writeFieldID(2);
+ try writer.writeValue(@TypeOf(registry), registry);
+ }
+ if (this.root) |root| {
+ try writer.writeFieldID(3);
+ try writer.writeInt(root);
+ }
+ if (this.hashes) |hashes| {
+ try writer.writeFieldID(4);
+ try writer.writeArray(u32, hashes);
+ }
+ if (this.name_hashes) |name_hashes| {
+ try writer.writeFieldID(5);
+ try writer.writeArray(u32, name_hashes);
+ }
+ if (this.packages) |packages| {
+ try writer.writeFieldID(6);
+ try writer.writeArray(NpmPackage, packages);
+ }
+ if (this.blob) |blob| {
+ try writer.writeFieldID(7);
+ try writer.writeArray(u8, blob);
+ }
+ try writer.endMessage();
+ }
+ };
};
diff --git a/src/cli/install_command.zig b/src/cli/install_command.zig
new file mode 100644
index 000000000..d4af860b8
--- /dev/null
+++ b/src/cli/install_command.zig
@@ -0,0 +1,42 @@
+usingnamespace @import("../global.zig");
+const std = @import("std");
+
+const lex = @import("../js_lexer.zig");
+const logger = @import("../logger.zig");
+const alloc = @import("../alloc.zig");
+const options = @import("../options.zig");
+const js_parser = @import("../js_parser.zig");
+const json_parser = @import("../json_parser.zig");
+const js_printer = @import("../js_printer.zig");
+const js_ast = @import("../js_ast.zig");
+const linker = @import("../linker.zig");
+usingnamespace @import("../ast/base.zig");
+usingnamespace @import("../defines.zig");
+const panicky = @import("../panic_handler.zig");
+const sync = @import("../sync.zig");
+const Api = @import("../api/schema.zig").Api;
+const resolve_path = @import("../resolver/resolve_path.zig");
+const configureTransformOptionsForBun = @import("../javascript/jsc/config.zig").configureTransformOptionsForBun;
+const Command = @import("../cli.zig").Command;
+const bundler = @import("../bundler.zig");
+const NodeModuleBundle = @import("../node_module_bundle.zig").NodeModuleBundle;
+const DotEnv = @import("../env_loader.zig");
+const which = @import("../which.zig").which;
+const Run = @import("../bun_js.zig").Run;
+var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+var path_buf2: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+const NpmArgs = struct {
+ // https://github.com/npm/rfcs/blob/main/implemented/0021-reduce-lifecycle-script-environment.md#detailed-explanation
+ pub const package_name: string = "npm_package_name";
+ pub const package_version: string = "npm_package_version";
+};
+
+const yarn_commands: []u64 = @import("./list-of-yarn-commands.zig").all_yarn_commands;
+
+const ShellCompletions = @import("./shell_completions.zig");
+
+pub const InstallCommand = struct {
+ pub fn exec(ctx: Command.Context) !void {
+
+ }
+};
diff --git a/src/install/install.zig b/src/install/install.zig
new file mode 100644
index 000000000..7c4324807
--- /dev/null
+++ b/src/install/install.zig
@@ -0,0 +1,29 @@
+usingnamespace @import("../global.zig");
+const std = @import("std");
+
+const lex = @import("../js_lexer.zig");
+const logger = @import("../logger.zig");
+const alloc = @import("../alloc.zig");
+const options = @import("../options.zig");
+const js_parser = @import("../js_parser.zig");
+const json_parser = @import("../json_parser.zig");
+const js_printer = @import("../js_printer.zig");
+const js_ast = @import("../js_ast.zig");
+const linker = @import("../linker.zig");
+usingnamespace @import("../ast/base.zig");
+usingnamespace @import("../defines.zig");
+const panicky = @import("../panic_handler.zig");
+const sync = @import("../sync.zig");
+const Api = @import("../api/schema.zig").Api;
+const resolve_path = @import("../resolver/resolve_path.zig");
+const configureTransformOptionsForBun = @import("../javascript/jsc/config.zig").configureTransformOptionsForBun;
+const Command = @import("../cli.zig").Command;
+const bundler = @import("../bundler.zig");
+const NodeModuleBundle = @import("../node_module_bundle.zig").NodeModuleBundle;
+const DotEnv = @import("../env_loader.zig");
+const which = @import("../which.zig").which;
+const Run = @import("../bun_js.zig").Run;
+
+var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+var path_buf2: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+
diff --git a/src/install/semver.zig b/src/install/semver.zig
new file mode 100644
index 000000000..14eb3097a
--- /dev/null
+++ b/src/install/semver.zig
@@ -0,0 +1,394 @@
+usingnamespace @import("../global.zig");
+const std = @import("std");
+
+pub const Version = struct {
+ major: u32 = 0,
+ minor: u32 = 0,
+ patch: u32 = 0,
+ tag: Tag = Tag{},
+ extra_tags: []const Tag = &[_]Tag{},
+ raw: strings.StringOrTinyString = strings.StringOrTinyString{},
+
+ inline fn atPart(i: u8) u32 {
+ return switch (i) {
+ 0 => self.major,
+ 1 => self.minor,
+ 2 => self.patch,
+ else => unreachable,
+ };
+ }
+
+ pub const Tag = struct {
+ pre: strings.StringOrTinyString = strings.StringOrTinyString{},
+ build: strings.StringOrTinyString = strings.StringOrTinyString{},
+
+ pub const TagResult = struct {
+ tag: Tag = Tag{},
+ extra_tags: []const Tag = &[_]Tag{},
+ len: u32 = 0,
+ };
+ pub fn parse(allocator: *std.mem.Allocator, input: string) TagResult {}
+ };
+
+ pub fn isGreaterThan(self: Version, other: Version) bool {
+ if (self.major > other.major) {
+ return true;
+ }
+
+ if (self.minor > other.minor) {
+ return true;
+ }
+
+ if (self.patch > other.patch) {
+ return true;
+ }
+ }
+
+ pub const ParseResult = struct {
+ wildcard: Query.Token.Wildcard = Query.Token.Wildcard.none,
+ valid: bool = true,
+ version: Version = Version{},
+ stopped_at: u32 = 0,
+ };
+
+ pub fn parse(input: string, allocator: *std.mem.Allocator) ParseResult {
+ var result = ParseResult{};
+
+ var part_i_: i8 = -1;
+ var part_start_i_: i32 = -1;
+ var last_char_i: u32 = 0;
+
+ if (input.len == 0) {
+ result.valid = false;
+ return result;
+ }
+ var is_done = false;
+ var stopped_at: i32 = 0;
+ for (input) |char, i| {
+ if (is_done) {
+ break;
+ }
+
+ stopped_at = i;
+ switch (char) {
+ ' ' => {
+ if (part_i_ > 2) {
+ is_done = true;
+ break;
+ }
+ },
+ '|', '^', '#', '&', '%', '!' => {
+ is_done = true;
+ stopped_at -= 1;
+ break;
+ },
+ '0'...'9' => {
+ if (part_start_i_ == -1) {
+ part_start_i_ = @intCast(i32, i);
+ }
+ last_char_i = @intCast(u32, i);
+ },
+ '.' => {
+ if (part_start_i_ > -1 and part_i <= 2) {
+ switch (part_i) {
+ 0 => {
+ result.version.major = parseVersionNumber(input[@intCast(usize, part_start_i)..i]);
+ },
+ 1 => {
+ result.version.minor = parseVersionNumber(input[@intCast(usize, part_start_i)..i]);
+ },
+ else => {},
+ }
+
+ part_start_i_ = -1;
+ part_i_ += 1;
+ // "fo.o.b.ar"
+ } else if (part_i > 2 or part_start_i_ == -1) {
+ result.valid = false;
+ is_done = true;
+ break;
+ }
+ },
+ '-', '+' => {
+ if (part_i == 2 and part_start_i_ > -1) {
+ result.version.patch = parseVersionNumber(input[@intCast(usize, part_start_i)..i]);
+ result.wildcard = Query.Token.Wildcard.none;
+ part_start_i_ = @intCast(i32, i);
+ part_i_ = 3;
+ is_done = true;
+ break;
+ } else {
+ result.valid = false;
+ is_done = true;
+ break;
+ }
+ },
+ 'x', '*', 'X' => {
+ if (part_start_i_ == -1) {
+ part_start_i_ = @intCast(i32, i);
+ }
+ last_char_i = @intCast(u32, i);
+
+ // We want min wildcard
+ if (result.wildcard == .none) {
+ switch (part_i_) {
+ 0 => {
+ result.wildcard = Query.Token.Wildcard.major;
+ },
+ 1 => {
+ result.wildcard = Query.Token.Wildcard.minor;
+ },
+ 2 => {
+ result.wildcard = Query.Token.Wildcard.patch;
+ },
+ else => unreachable,
+ }
+ }
+ },
+ else => {
+ last_char_i = 0;
+ result.is_valid = false;
+ is_done = true;
+ break;
+ },
+ }
+ }
+
+ const part_i = @intCast(u8, @maximum(0, part_i_));
+ result.valid = result.valid and part_i_ > -1;
+
+ const part_start_i = @intCast(u32, @maximum(0, part_start_i_));
+
+ if (last_char_i == -1 or part_start_i > last_char_i)
+ last_char_i = input.len - 1;
+
+ // Where did we leave off?
+ switch (part_i) {
+ // That means they used a match like this:
+ // "1"
+ // So its a wildcard major
+ 0 => {
+ if (result.wildcard == .none) {
+ result.wildcard = Query.Token.Wildcard.minor;
+ }
+
+ result.version.major = parseVersionNumber(input[@as(usize, part_start_i) .. last_char_i + 1]);
+ },
+ 1 => {
+ if (result.wildcard == .none) {
+ result.wildcard = Query.Token.Wildcard.patch;
+ }
+
+ result.version.minor = parseVersionNumber(input[@as(usize, part_start_i) .. last_char_i + 1]);
+ },
+ 2 => {
+ result.version.patch = parseVersionNumber(input[@as(usize, part_start_i) .. last_char_i + 1]);
+ },
+ 3 => {
+ const tag_result = Tag.parse(allocator, input[part_start_i..]);
+ result.version.tag = tag_result.tag;
+ if (tag_result.extra_tags.len > 0) {
+ result.version.extra_tags = tag_result.extra_tags;
+ }
+
+ stopped_at = @intCast(i32, tag_result.len) + part_start_i;
+ },
+ else => {},
+ }
+
+ result.stopped_at = @intCast(u32, @maximum(stopped_at, 0));
+
+ return result;
+ }
+
+ fn parseVersionNumber(input: string) u32 {
+ // max decimal u32 is 4294967295
+ var bytes: [10]u8 = undefined;
+ var byte_i: u8 = 0;
+
+ for (input) |char, i| {
+ switch (char) {
+ 'X', 'x', '*' => return 0,
+ '0'...'9' => {
+ // out of bounds
+ if (byte_i + 1 > bytes.len) return 0;
+ bytes[byte_i] = char;
+ byte_i += 1;
+ },
+ // ignore invalid characters
+ else => {},
+ }
+ }
+
+ // If there are no numbers, it's 0.
+ if (byte_i == 0) return 0;
+
+ return std.fmt.parseInt(u32, bytes[0..byte_i], 10) catch 0;
+ }
+};
+
+pub const Range = struct {
+ pub const Op = enum {
+ eql,
+ lt,
+ lte,
+ gt,
+ gte,
+ };
+
+ pub const Comparator = struct {
+ op: Op = Op.eql,
+ version: Version = Version{},
+ };
+
+ left: Comparator = Comparator{},
+ right: ?Comparator = null,
+};
+
+pub const Query = struct {
+ pub const Op = enum {
+ none,
+ AND,
+ OR,
+ };
+
+ range: Range = Range{},
+ next_op: Op = Op.none,
+
+ next: *Query = undefined,
+
+ pub const List = struct {
+ head: Query,
+ tail: ?*Query = null,
+ allocator: *std.mem.Allocator,
+ pub fn setVersion(self: *List, version: Version) void {}
+
+ pub fn andRange(self: *List, range: Range) !void {}
+
+ pub fn orRange(self: *List, range: Range) !void {}
+ };
+
+ pub const Token = struct {
+ tag: Tag = Tag.none,
+ wildcard: Wildcard = Wildcard.none,
+
+ pub const Tag = enum {
+ none,
+ logical_or,
+ gt,
+ gte,
+ lt,
+ lte,
+ version,
+ tilda,
+ caret,
+ };
+
+ pub const Wildcard = enum {
+ none,
+ major,
+ minor,
+ patch,
+ };
+ };
+
+ pub fn parse(allocator: *std.mem.Allocator, input: string) !Query {
+ var i: usize = 0;
+ var query = Query{};
+
+ var token = Token{};
+ var prev_token = Token{};
+
+ var count: u8 = 0;
+ var skip_round = false;
+ var is_or = false;
+
+ while (i < input.len) {
+ skip_round = false;
+
+ switch (input[i]) {
+ '>' => {
+ if (prev_token.tag == .version) {
+ is_or = false;
+ }
+
+ if (input.len > i + 1 and input[i + 1] == '=') {
+ token.tag = .gte;
+ i += 1;
+ } else {
+ token.tag = .gt;
+ }
+
+ i += 1;
+ while (i < input.len and input[i] == ' ') : (i += 1) {}
+ },
+ '<' => {
+ if (input.len > i + 1 and input[i + 1] == '=') {
+ token.tag = .lte;
+ i += 1;
+ } else {
+ token.tag = .lt;
+ }
+
+ i += 1;
+ while (i < input.len and input[i] == ' ') : (i += 1) {}
+ },
+ '=', 'v' => {
+ token.tag = .version;
+ is_or = true;
+ i += 1;
+ while (i < input.len and input[i] == ' ') : (i += 1) {}
+ },
+ '~' => {
+ token.tag = .tilda;
+ i += 1;
+
+ if (i < input.len and input[i] == '>') i += 1;
+
+ while (i < input.len and input[i] == ' ') : (i += 1) {}
+ },
+ '^' => {
+ token.tag = .caret;
+ i += 1;
+ while (i < input.len and input[i] == ' ') : (i += 1) {}
+ },
+ '0'...'9', 'X', 'x', '*' => {
+ token.tag = .version;
+ is_or = true;
+ },
+ '|' => {
+ i += 1;
+
+ while (i < input.len and input[i] == '|') : (i += 1) {}
+ while (i < input.len and input[i] == ' ') : (i += 1) {}
+ is_or = true;
+ token.tag = Token.Tag.none;
+ skip_round = true;
+ },
+ '-' => {
+ i += 1;
+ while (i < input.len and input[i] == ' ') : (i += 1) {}
+ },
+ ' ' => {
+ i += 1;
+ while (i < input.len and input[i] == ' ') : (i += 1) {}
+ skip_round = true;
+ },
+ else => {
+ i += 1;
+ token.tag = Token.Tag.none;
+ skip_round = true;
+ },
+ }
+
+ if (!skip_round) {
+ if (count == 0 and token.tag == .version) {
+ prev_token.tag = token.tag;
+ const parse_result = Version.parse(input[i..]);
+ }
+ }
+ }
+
+ return query;
+ }
+};