aboutsummaryrefslogtreecommitdiff
path: root/src/resolver/dir_info.zig
blob: 92d6c2d75ae3092f438ea605d8afa4f5c67b65ca (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
const bun = @import("root").bun;
const std = @import("std");
const string = bun.string;
const Output = bun.Output;
const Global = bun.Global;
const Environment = bun.Environment;
const strings = bun.strings;
const MutableString = bun.MutableString;
const stringZ = bun.stringZ;
const default_allocator = bun.default_allocator;
const C = bun.C;
const StoredFileDescriptorType = bun.StoredFileDescriptorType;
const FeatureFlags = bun.FeatureFlags;

const allocators = @import("../allocators.zig");
const DirInfo = @This();
const Fs = @import("../fs.zig");
const TSConfigJSON = @import("./tsconfig_json.zig").TSConfigJSON;
const PackageJSON = @import("./package_json.zig").PackageJSON;

pub const Index = allocators.IndexType;

// These objects are immutable, so we can just point to the parent directory
// and avoid having to lock the cache again
parent: Index = allocators.NotFound,

// A pointer to the enclosing dirInfo with a valid "browser" field in
// package.json. We need this to remap paths after they have been resolved.
enclosing_browser_scope: Index = allocators.NotFound,
package_json_for_browser_field: ?*const PackageJSON = null,
enclosing_tsconfig_json: ?*const TSConfigJSON = null,

/// package.json used for bundling
/// it's the deepest one in the hierarchy with a "name" field
/// or, if using `bun run`, the name field is optional
/// https://github.com/oven-sh/bun/issues/229
enclosing_package_json: ?*PackageJSON = null,

package_json_for_dependencies: ?*PackageJSON = null,

abs_path: string = "",
entries: Index = undefined,
package_json: ?*PackageJSON = null, // Is there a "package.json" file?
tsconfig_json: ?*TSConfigJSON = null, // Is there a "tsconfig.json" file in this directory or a parent directory?
abs_real_path: string = "", // If non-empty, this is the real absolute path resolving any symlinks

flags: Flags.Set = Flags.Set{},

/// Is there a "node_modules" subdirectory?
pub inline fn hasNodeModules(this: *const DirInfo) bool {
    return this.flags.contains(.has_node_modules);
}
/// Is this a "node_modules" directory?
pub inline fn isNodeModules(this: *const DirInfo) bool {
    return this.flags.contains(.is_node_modules);
}

pub const Flags = enum {
    /// This directory is a node_modules directory
    is_node_modules,
    /// This directory has a node_modules subdirectory
    has_node_modules,

    pub const Set = std.enums.EnumSet(Flags);
};

pub fn hasParentPackage(this: *const DirInfo) bool {
    const parent = this.getParent() orelse return false;
    return !parent.isNodeModules();
}

pub fn getFileDescriptor(dirinfo: *const DirInfo) StoredFileDescriptorType {
    if (!FeatureFlags.store_file_descriptors) {
        return 0;
    }

    if (dirinfo.getEntries(0)) |entries| {
        return entries.fd;
    } else {
        return 0;
    }
}

pub fn getEntries(dirinfo: *const DirInfo, generation: bun.Generation) ?*Fs.FileSystem.DirEntry {
    var entries_ptr = Fs.FileSystem.instance.fs.entriesAt(dirinfo.entries, generation) orelse return null;
    switch (entries_ptr.*) {
        .entries => {
            return entries_ptr.entries;
        },
        .err => {
            return null;
        },
    }
}

pub fn getEntriesConst(dirinfo: *const DirInfo) ?*const Fs.FileSystem.DirEntry {
    const entries_ptr = Fs.FileSystem.instance.fs.entries.atIndex(dirinfo.entries) orelse return null;
    switch (entries_ptr.*) {
        .entries => {
            return entries_ptr.entries;
        },
        .err => {
            return null;
        },
    }
}

pub fn getParent(i: *const DirInfo) ?*DirInfo {
    return HashMap.instance.atIndex(i.parent);
}
pub fn getEnclosingBrowserScope(i: *const DirInfo) ?*DirInfo {
    return HashMap.instance.atIndex(i.enclosing_browser_scope);
}

// Goal: Really fast, low allocation directory map exploiting cache locality where we don't worry about lifetimes much.
// 1. Don't store the keys or values of directories that don't exist
// 2. Don't expect a provided key to exist after it's queried
// 3. Store whether a directory has been queried and whether that query was successful.
// 4. Allocate onto the https://en.wikipedia.org/wiki/.bss#BSS_in_C instead of the heap, so we can avoid memory leaks
pub const HashMap = allocators.BSSMap(DirInfo, Fs.Preallocate.Counts.dir_entry, false, 128, true);