Skip to content

chore: nodejs binding #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 31, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
155 changes: 155 additions & 0 deletions .gnfiles/build/feature/javascript/javascript.gni
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#
# Copyright © 2024 Agora
# This file is part of TEN Framework, an open source project.
# Licensed under the Apache License, Version 2.0, with certain conditions.
# Refer to the "LICENSE" file in the root directory for more information.
#
template("npm_install") {
action(target_name) {
script = "//.gnfiles/build/scripts/npm_install.py"
args = [
"-project_dir",
rebase_path("//"),
"-package_json",
rebase_path(invoker.package_json),
"-output_dir",
rebase_path(invoker.output_dir),
"-platform",
target_os,
"-log_level",
"${log_level}",
]
sources = [ rebase_path(invoker.package_json) ]
outputs = [ invoker.output_dir + "/node_modules" ]
if (defined(invoker.package_lock_json) && invoker.package_lock_json != "") {
args += [
"-package_lock_json",
rebase_path(invoker.package_lock_json),
]
sources += [ rebase_path(invoker.package_lock_json) ]
outputs += [ invoker.output_dir + "/package-lock.json" ]
}
forward_variables_from(invoker,
[
"deps",
"public_deps",
"data_deps",
])
}
}

template("nodejs_library") {
_target_name = target_name
npm_install("${target_name}_ensure_npm") {
package_json = invoker.package_json
output_dir = invoker.output_dir
if (defined(invoker.package_lock_json) && invoker.package_lock_json != "") {
package_lock_json = invoker.package_lock_json
}
}

action(target_name) {
# Switch the following two lines to execute 'npm run build' or 'tsc' to
# complete the building. We use 'npm run build' now is because it allows
# the project to decide which build method is preferred.
# The parameters of these two Python scripts are exactly the same, so these
# two Python scripts could be exchanged seamlessly.
script = "//.gnfiles/build/scripts/npm_run_build.py"

args = [
"-project_dir",
rebase_path("//"),
"-log_level",
"${log_level}",
]
args += [
"-tsconfig_file",
rebase_path(invoker.tsconfig),
]
args += [
"-out_dir",
rebase_path(invoker.output_dir),
]
if (defined(invoker.references) && invoker.references != []) {
args += [
"-ref",
string_join(",", invoker.references),
]
}
args += [
"-platform",
target_os,
]
if (defined(invoker.remove_node_modules) &&
invoker.remove_node_modules == true) {
args += [
"-remove_node_modules",
"True",
]
}
if (defined(invoker.remove_tsbuildinfo) &&
invoker.remove_tsbuildinfo == true) {
args += [
"-remove_tsbuildinfo",
"True",
]
}
if (defined(invoker.remove_src) && invoker.remove_src == true) {
args += [
"-remove_src",
"True",
]
}
if (defined(invoker.library_path) && invoker.library_path != "") {
args += [
"-library_path",
invoker.library_path,
]
}

args += [ "-build_target" ]
if (defined(invoker.build_target) && invoker.build_target != "") {
args += [ invoker.build_target ]
} else {
args += [ "build" ]
}

if (defined(invoker.extra_args) && invoker.extra_args != []) {
foreach(arg, invoker.extra_args) {
args += [
"-extra_args",
"${arg}",
]
}
}

forward_variables_from(invoker,
[
"deps",
"public_deps",
"data_deps",
])
if (defined(deps)) {
deps += [ ":${_target_name}_ensure_npm" ]
} else {
deps = [ ":${_target_name}_ensure_npm" ]
}
sources = exec_script("//.gnfiles/build/scripts/glob_tsconfig_files.py",
[ rebase_path(invoker.tsconfig) ],
"list lines") + [ rebase_path(invoker.tsconfig) ]

tsc_output_dir_relative_path =
exec_script("//.gnfiles/build/scripts/get_tsc_output_dir.py",
[ rebase_path(invoker.tsconfig) ],
"trim string")

# print("The sources of $target_name are: $sources")
outputs = [
# "${invoker.output_dir}/build/.files",
"${invoker.output_dir}/${tsc_output_dir_relative_path}",
]
if (defined(invoker.library_path) && invoker.library_path != "") {
outputs += [ "${invoker.output_dir}/path.json" ]
}
}
}
58 changes: 58 additions & 0 deletions .gnfiles/build/scripts/get_tsc_output_dir.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# list source files and output files
# Usage:
# python glob_tsconfig_files.py tsconfig.json # prints sources
# python glob_tsconfig_files.py tsconfig.json out_dir # prints outputs

import json
import sys
import re
import glob
import os
import fnmatch


sys.dont_write_bytecode = True
# proper glob for python 2 & 3


def read_ts_config(file_name):
with open(file_name) as f:
ts_config = f.read()

# Remove comments and redundant commas before JSON parsing, because they
# are not valid JSON contents.

str_pattern = r'"(?:\\.|[^"])*"'

def keep_str_remove_comments(m):
if m.group(0).startswith("/"):
return ""
else:
return m.group(0)

ts_config = re.sub(
str_pattern + r"|/\*[.\n]+?\*/|//[^\n]*",
keep_str_remove_comments,
ts_config,
)

def keep_str_remove_redundant_commas(m):
if m.group(0).startswith(","):
return m.group(0)[1:]
else:
return m.group(0)

ts_config = re.sub(
str_pattern + r"|,(?:[\s\n]*[\]\}])",
keep_str_remove_redundant_commas,
ts_config,
)

config = json.loads(ts_config)
return config


if __name__ == "__main__":
# outputs depends on tsconfig.json, but not including this file
ts_config = read_ts_config(sys.argv[1])
print(ts_config["compilerOptions"]["outDir"])
123 changes: 123 additions & 0 deletions .gnfiles/build/scripts/glob_tsconfig_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# list source files and output files
# Usage:
# python glob_tsconfig_files.py tsconfig.json # prints sources
# python glob_tsconfig_files.py tsconfig.json out_dir # prints outputs

import json
import sys
import re
import glob
import os
import fnmatch


sys.dont_write_bytecode = True
# proper glob for python 2 & 3


def proper_glob(src_pattern):
if "**" in src_pattern:
srcs = []
folder, pattern = src_pattern.split("**")
if not folder:
folder = "."
pattern = pattern.strip("/")
for root, dirnames, filenames in os.walk(folder):
dirnames[:] = [d for d in dirnames if d != "node_modules"]
for filename in fnmatch.filter(filenames, pattern):
srcs.append(os.path.join(root, filename))
return srcs
else:
return glob.glob(src_pattern)


def read_ts_config(file_name):
with open(file_name) as f:
ts_config = f.read()

# Remove comments and redundant commas before JSON parsing, because they
# are not valid JSON contents.

str_pattern = r'"(?:\\.|[^"])*"'

def keep_str_remove_comments(m):
if m.group(0).startswith("/"):
return ""
else:
return m.group(0)

ts_config = re.sub(
str_pattern + r"|/\*[.\n]+?\*/|//[^\n]*",
keep_str_remove_comments,
ts_config,
)

def keep_str_remove_redundant_commas(m):
if m.group(0).startswith(","):
return m.group(0)[1:]
else:
return m.group(0)

ts_config = re.sub(
str_pattern + r"|,(?:[\s\n]*[\]\}])",
keep_str_remove_redundant_commas,
ts_config,
)

config = json.loads(ts_config)
return config


def glob_ts_sources(ts_config_file, ts_config, out_dir=None):
# Remember current working directory so that we can come back here.
dir = os.path.abspath(".")

try:
source_folder = os.path.dirname(os.path.abspath(ts_config_file))
os.chdir(source_folder)

srcs = []
if "include" in ts_config:
for src_pattern in ts_config["include"]:
srcs += proper_glob(src_pattern)
else:
srcs += proper_glob("**/*")

if "exclude" in ts_config:
for src_pattern in ts_config["exclude"]:
new_srcs = []
exclude_srcs = proper_glob(src_pattern)
for src in srcs:
if src not in exclude_srcs:
new_srcs.append(src)
srcs = new_srcs

results = []
for line in srcs:
if out_dir:
results.append(
out_dir.rstrip("/")
+ "/"
+ re.sub(r"\.ts$", ".js", line, re.IGNORECASE)
)
else:
results.append(os.path.join(source_folder, line))

return results
finally:
# Go back to the original working directory.
os.chdir(dir)


if __name__ == "__main__":
if len(sys.argv) > 2:
out_dir = sys.argv[2]
else:
out_dir = None
# outputs depends on tsconfig.json, but not including this file
if not out_dir:
print(sys.argv[1])
ts_config = read_ts_config(sys.argv[1])
sources = glob_ts_sources(sys.argv[1], ts_config, out_dir)
for source in sources:
print(source)
Loading
Loading