Skip to content

Commit

Permalink
cli: implement node run <script-in-package-json>
Browse files Browse the repository at this point in the history
  • Loading branch information
anonrig committed Mar 22, 2024
1 parent d1d5da2 commit 424a48c
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 0 deletions.
51 changes: 51 additions & 0 deletions lib/internal/main/run.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'use strict';

const {
JSONParse,
ObjectKeys,
} = primordials;

const {
prepareMainThreadExecution,
markBootstrapComplete,
} = require('internal/process/pre_execution');
const { getPackageJSONScripts } = internalBinding('modules');
const { execSync } = require('child_process');
const { log, error } = require('internal/console/global');

prepareMainThreadExecution(false, false);

markBootstrapComplete();

const json_string = getPackageJSONScripts('package.json');

// Check if package.json exists and is parseable
if (json_string === undefined) {
process.exit(1);
return;
}
const scripts = JSONParse(json_string);
const id = process.argv.at(2);
const command = scripts[id];

if (!command) {
error(`Missing script: "${id}"`);

const keys = ObjectKeys(scripts);
if (keys.length === 0) {
error('There are no scripts available in package.json');
} else {
error('Available scripts are:\n');
for (const script of ObjectKeys(scripts)) {
error(` ${script}: ${scripts[script]}`);
}
}
process.exit(1);
}

log('');
log('>', id);
log('>', command);
log('');

execSync(command, { stdio: 'inherit' });
4 changes: 4 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,10 @@ MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) {
return StartExecution(env, "internal/main/watch_mode");
}

if (!first_argv.empty() && first_argv == "run") {
return StartExecution(env, "internal/main/run");
}

if (!first_argv.empty() && first_argv != "-") {
return StartExecution(env, "internal/main/run_main_module");
}
Expand Down
44 changes: 44 additions & 0 deletions src/node_modules.cc
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,21 @@ const BindingData::PackageConfig* BindingData::GetPackageJSON(
if (field_value == "commonjs" || field_value == "module") {
package_config.type = field_value;
}
} else if (key == "scripts") {
if (value.type().get(field_type)) {
return throw_invalid_package_config();
}
switch (field_type) {
case simdjson::ondemand::json_type::object: {
if (value.raw_json().get(field_value)) {
return throw_invalid_package_config();
}
package_config.scripts = field_value;
break;
}
default:
break;
}
}
}
// package_config could be quite large, so we should move it instead of
Expand Down Expand Up @@ -344,6 +359,33 @@ void BindingData::GetNearestParentPackageJSONType(
args.GetReturnValue().Set(Array::New(realm->isolate(), values, 3));
}

void BindingData::GetPackageJSONScripts(
const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsString());

Realm* realm = Realm::GetCurrent(args);
Utf8Value path(realm->isolate(), args[0]);

THROW_IF_INSUFFICIENT_PERMISSIONS(
realm->env(),
permission::PermissionScope::kFileSystemRead,
path.ToStringView());

auto package_json = GetPackageJSON(realm, path.ToString());
if (package_json == nullptr) {
printf("Can't read package.json\n");
return;
} else if (!package_json->scripts.has_value()) {
printf("Package.json scripts doesn't exist or parseable\n");
return;
}

args.GetReturnValue().Set(
ToV8Value(realm->context(), package_json->scripts.value())
.ToLocalChecked());
}

void BindingData::GetPackageScopeConfig(
const FunctionCallbackInfo<Value>& args) {
CHECK_GE(args.Length(), 1);
Expand Down Expand Up @@ -424,6 +466,7 @@ void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
"getNearestParentPackageJSON",
GetNearestParentPackageJSON);
SetMethod(isolate, target, "getPackageScopeConfig", GetPackageScopeConfig);
SetMethod(isolate, target, "getPackageJSONScripts", GetPackageJSONScripts);
}

void BindingData::CreatePerContextProperties(Local<Object> target,
Expand All @@ -440,6 +483,7 @@ void BindingData::RegisterExternalReferences(
registry->Register(GetNearestParentPackageJSONType);
registry->Register(GetNearestParentPackageJSON);
registry->Register(GetPackageScopeConfig);
registry->Register(GetPackageJSONScripts);
}

} // namespace modules
Expand Down
3 changes: 3 additions & 0 deletions src/node_modules.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class BindingData : public SnapshotableObject {
std::string type = "none";
std::optional<std::string> exports;
std::optional<std::string> imports;
std::optional<std::string> scripts;
std::string raw_json;

v8::Local<v8::Array> Serialize(Realm* realm) const;
Expand Down Expand Up @@ -60,6 +61,8 @@ class BindingData : public SnapshotableObject {
const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetPackageScopeConfig(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetPackageJSONScripts(
const v8::FunctionCallbackInfo<v8::Value>& args);

static void CreatePerIsolateProperties(IsolateData* isolate_data,
v8::Local<v8::ObjectTemplate> ctor);
Expand Down
1 change: 1 addition & 0 deletions typings/internalBinding/modules.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ export interface ModulesBinding {
string, // raw content
]
getPackageScopeConfig(path: string): SerializedPackageConfig | undefined
getPackageJSONScripts(path: string): string | undefined
}

0 comments on commit 424a48c

Please sign in to comment.