Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,46 @@ class PrependWebJSProcessor: CompilationProcessor {
}
}

let relativePath = item.relativeProjectPath
var relativePath = item.relativeProjectPath
// Strip TypeScript extensions (.tsx, .ts) from the path since compiled files are .js
// This ensures module.path matches what the module loader expects
if relativePath.hasSuffix(".tsx") {
relativePath = String(relativePath.dropLast(4))
} else if relativePath.hasSuffix(".ts") {
relativePath = String(relativePath.dropLast(3))
}

logger.debug("PrependWebJSProcessor: ========== Processing Web JS File ==========")
logger.debug("PrependWebJSProcessor: Output file path: \(finalFileOutput)")
logger.debug("PrependWebJSProcessor: relativeProjectPath (original): '\(item.relativeProjectPath)'")
logger.debug("PrependWebJSProcessor: relativeProjectPath (adjusted): '\(relativePath)'")
logger.debug("PrependWebJSProcessor: relativeProjectPath length: \(relativePath.count)")
logger.debug("PrependWebJSProcessor: sourceURL: \(item.sourceURL.absoluteString)")
logger.debug("PrependWebJSProcessor: bundleInfo.name: \(item.bundleInfo.name)")
logger.debug("PrependWebJSProcessor: outputURL.lastPathComponent: \(finalFile.outputURL.lastPathComponent)")

var newFile = finalFile.file
var contents: String? = try? newFile.readString()
let contentsLength = contents?.count ?? 0
logger.debug("PrependWebJSProcessor: File contents length: \(contentsLength)")

// Count how many require( calls are in the file
let requireCount = contents?.components(separatedBy: "require(").count ?? 1
logger.debug("PrependWebJSProcessor: Found \(requireCount - 1) 'require(' occurrences")

// Transform require( to customRequire( - this must happen for all web JS files
// Note: TypeScript with module: "commonjs" already transforms import() to Promise.resolve().then(() => require(...)),
// so we only need to transform require( to customRequire( and the import() transformation is handled automatically.
contents = contents?.replacingOccurrences(of: "require(", with: "customRequire(")
let prefix = "var customRequire = globalThis.moduleLoader.resolveRequire(\"\(relativePath)\");\n"

// Set up module.path for code that uses NavigationPage decorator
// The module variable is provided by webpack as a function parameter, so we just set the path property
// The module variable is declared in source code as: declare const module: { path: string; exports: unknown };
// Note: We use the adjusted relativePath (without .tsx/.ts extension) so module resolution works correctly
let moduleSetup = "module.path = \"\(relativePath)\";\n"
let prefix = "\(moduleSetup)var customRequire = globalThis.moduleLoader.resolveRequire(\"\(relativePath)\");\n"
logger.debug("PrependWebJSProcessor: Generated prefix (first 100 chars): \(String(prefix.prefix(100)))")
logger.debug("PrependWebJSProcessor: ==========================================")
if let data = (prefix + (contents ?? "" )).data(using: .utf8) {
newFile = .data(data)
}
Expand Down
17 changes: 16 additions & 1 deletion compiler/compiler/scripts/update_compiler.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ if [ -z "$bin_output_path" ]; then
usage
fi

# Convert to absolute path before changing directories
# This ensures the path remains correct after we cd to $BASE_PATH
ORIGINAL_PWD=$(pwd)
if [[ "$bin_output_path" != /* ]]; then
# Relative path - make it absolute from the original working directory
bin_output_path="$ORIGINAL_PWD/$bin_output_path"
fi

# Main
cd "$BASE_PATH"
VARIANT="release"
Expand Down Expand Up @@ -142,4 +150,11 @@ source src/composer/jenkins/jenkins_helpers.sh
mkdir -p "$OUT_DIR"
rm -f "$OUT_DIR/valdi_compiler"
cp "$OUTPUT_FILE_PATH" "$OUT_DIR/valdi_compiler"
)

# Verify the copy succeeded
if [ ! -f "$OUT_DIR/valdi_compiler" ]; then
echo "Error: Failed to copy compiler binary to $OUT_DIR/valdi_compiler" >&2
exit 1
fi

echo "All done."
109 changes: 102 additions & 7 deletions npm_modules/cli/src/commands/projectsync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,44 @@ async function collectTsConfigDirs(
};

const tsConfigDirs = new Map<string, TsConfigDir>();
let consolidatedModulesPath: string | undefined;

// First pass: detect if consolidated setup exists by checking for modules/tsconfig.json
// Look for any target under a modules/ directory and check if modules/tsconfig.json exists
for (const projectSyncOutput of projectSyncOutputs) {
if (projectSyncOutput.target.repo) {
continue;
}

const targetPath = bazelLabelToAbsolutePath(workspaceInfo, projectSyncOutput.target);
const modulesMatch = targetPath.match(/(.+[/\\]modules)[/\\]/);
if (modulesMatch) {
const potentialModulesPath = modulesMatch[1]!;
const consolidatedTsConfigPath = path.join(potentialModulesPath, 'tsconfig.json');
if (fsSync.existsSync(consolidatedTsConfigPath)) {
consolidatedModulesPath = potentialModulesPath;
break;
}
}
}

// Second pass: group modules into consolidated dir if detected
for (const projectSyncOutput of projectSyncOutputs) {
if (projectSyncOutput.target.repo) {
// Ignore external repo deps
continue;
}

const tsConfigDirPath = bazelLabelToAbsolutePath(workspaceInfo, projectSyncOutput.target);
const targetPath = bazelLabelToAbsolutePath(workspaceInfo, projectSyncOutput.target);

// If using consolidated setup and target is under modules/, use consolidated dir
let tsConfigDirPath: string;
if (consolidatedModulesPath && targetPath.startsWith(consolidatedModulesPath + path.sep)) {
tsConfigDirPath = consolidatedModulesPath;
} else {
tsConfigDirPath = targetPath;
}

let tsConfigDir = tsConfigDirs.get(tsConfigDirPath);
if (!tsConfigDir) {
tsConfigDir = { dir: tsConfigDirPath, matchedTargets: [] };
Expand Down Expand Up @@ -239,9 +269,19 @@ function computeTsCompilerOptions(
compilerOptions = {};
}

// Preserve jsx and lib if they exist, or set defaults
if (!compilerOptions.jsx) {
compilerOptions.jsx = 'preserve';
}
if (!compilerOptions.lib) {
compilerOptions.lib = ['dom', 'ES2019'];
}

compilerOptions.paths = {};
const rootDirs: string[] = [];
let valdiCoreTarget: TargetDescription | undefined;
const seenDependencies = new Set<string>();

for (const matchedTarget of matchedTargets) {
const targetRootDirs = matchedTarget.target.paths.map(p => relativePathTo(tsConfigDir, path.dirname(p)));

Expand All @@ -254,24 +294,75 @@ function computeTsCompilerOptions(
const selfName = matchedTarget.target.label.name ?? '';
const selfInclude = `${selfName}/*`;

const selfImportPaths = matchedTarget.target.paths.map(p => `${relativePathTo(tsConfigDir, p)}/*`);
// For consolidated setup, paths should be relative to modules/ directory
// For individual module setup, paths are relative to module directory
const selfImportPaths: string[] = [];
for (const targetPath of matchedTarget.target.paths) {
const relativePath = relativePathTo(tsConfigDir, targetPath);
selfImportPaths.push(`${relativePath}/*`);

// Add projectsync-generated paths if they exist
const targetDir = path.dirname(targetPath);
const projectsyncGeneratedDir = path.join(targetDir, '.valdi_build/projectsync/generated_ts', selfName);
if (fsSync.existsSync(projectsyncGeneratedDir)) {
const relativeProjectsyncPath = relativePathTo(tsConfigDir, projectsyncGeneratedDir);
if (!selfImportPaths.includes(`${relativeProjectsyncPath}/*`)) {
selfImportPaths.push(`${relativeProjectsyncPath}/*`);
}
}
}

compilerOptions.paths[selfInclude] = selfImportPaths;

for (const dependency of matchedTarget.dependencies) {
if (!dependency.label.name || compilerOptions.paths[dependency.label.name]) {
// Already present
if (!dependency.label.name) {
continue;
}

const dependencyKey = `${dependency.label.name}/*`;

// For consolidated setup, merge paths from all modules
// For individual setup, skip if already present
if (seenDependencies.has(dependencyKey) && !compilerOptions.paths[dependencyKey]) {
continue;
}

if (dependency.label.name === 'valdi_core') {
valdiCoreTarget = dependency;
}

const importPaths = dependency.paths.map(p => `${relativePathTo(tsConfigDir, p)}/*`);
const importPaths: string[] = [];
for (const depPath of dependency.paths) {
const relativePath = relativePathTo(tsConfigDir, depPath);
importPaths.push(`${relativePath}/*`);

// Add projectsync-generated paths for external dependencies if they exist
const depDir = path.dirname(depPath);
const depName = dependency.label.name;
if (depName) {
const projectsyncGeneratedDir = path.join(depDir, '.valdi_build/projectsync/generated_ts', depName);
if (fsSync.existsSync(projectsyncGeneratedDir)) {
const relativeProjectsyncPath = relativePathTo(tsConfigDir, projectsyncGeneratedDir);
if (!importPaths.includes(`${relativeProjectsyncPath}/*`)) {
importPaths.push(`${relativeProjectsyncPath}/*`);
}
}
}
}

const key = `${dependency.label.name}/*`;
compilerOptions.paths[key] = importPaths;
if (compilerOptions.paths[dependencyKey]) {
// Merge with existing paths
const existing = compilerOptions.paths[dependencyKey];
if (Array.isArray(existing)) {
compilerOptions.paths[dependencyKey] = [...new Set([...existing, ...importPaths])];
} else {
compilerOptions.paths[dependencyKey] = importPaths;
}
} else {
compilerOptions.paths[dependencyKey] = importPaths;
}

seenDependencies.add(dependencyKey);
}
}

Expand All @@ -284,6 +375,10 @@ function computeTsCompilerOptions(

compilerOptions.types = baseTsFiles.map(p => relativePathTo(tsConfigDir, removeTsFileExtension(p)));

// Ensure rootDirs includes current directory for consolidated setup
if (!rootDirs.includes('.')) {
rootDirs.unshift('.');
}
compilerOptions.rootDirs = rootDirs;

return compilerOptions;
Expand Down
4 changes: 4 additions & 0 deletions src/valdi_modules/src/valdi/coreutils/web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@
"composite": true,
"allowJs": true
},
"exclude": [
"debug/**",
"release/**"
]
}
6 changes: 5 additions & 1 deletion src/valdi_modules/src/valdi/drawing/web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
"strict": true,
"skipLibCheck": true,
"composite": true,
"allowJs": true,
"allowJs": true
},
"exclude": [
"debug/**",
"release/**"
]
}
4 changes: 4 additions & 0 deletions src/valdi_modules/src/valdi/file_system/web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@
"composite": true,
"allowJs": true
},
"exclude": [
"debug/**",
"release/**"
]
}
4 changes: 4 additions & 0 deletions src/valdi_modules/src/valdi/persistence/web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@
"composite": true,
"allowJs": true
},
"exclude": [
"debug/**",
"release/**"
]
}
10 changes: 9 additions & 1 deletion src/valdi_modules/src/valdi/valdi_core/src/Device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
getWindowWidth,
getTimeZoneDstSecondsFromGMT as nativeGetTimeZoneDstSecondsFromGMT,
isDesktop,
isWeb,
observeDarkMode as nativeObserveDarkMode,
observeDisplaySizeChange as nativeObserveDisplaySizeChange,
observeDisplayInsetChange as nativeObserveDisplayInsetChange,
Expand Down Expand Up @@ -65,6 +66,7 @@ const cacheDeviceLocales = new DeviceCache<string[]>(getDeviceLocales ?? (() =>
const cacheLocaleUsesMetricSystem = new DeviceCache<boolean>(getLocaleUsesMetricSystem ?? (() => false));
const cacheTimeZoneName = new DeviceCache<string>(getTimeZoneName ?? (() => 'unknown'));
const cacheIsDesktop = new DeviceCache<boolean>(isDesktop ?? (() => false));
const cacheIsWeb = new DeviceCache<boolean>(isWeb ?? (() => false));
const cacheIsRTL = new DeviceCache<boolean>(computeIsRTL);

/**
Expand All @@ -82,7 +84,6 @@ function computeIsRTL(): boolean {
return RTL_LANGUAGES.includes(primaryLanguage);
}


/**
* Dark mode last cached value
*/
Expand Down Expand Up @@ -151,6 +152,13 @@ export namespace Device {
return cacheIsDesktop.get();
}

/**
* Check whether the Device is running on the Web platform.
*/
export function isWeb(): boolean {
return cacheIsWeb.get();
}

/**
* Get whether the system is Android or iOS
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ export function observeDisplayInsetChange(observe: () => void): DeviceCancelable
export function observeDisplaySizeChange(observe: () => void): DeviceCancelable;
export function observeDarkMode(observe: (isDarkMode: boolean) => void): DeviceCancelable;
export function isDesktop(): boolean;
export function isWeb(): boolean;
export const setBackButtonObserver: ((observer: (() => boolean) | undefined) => void) | undefined;
10 changes: 7 additions & 3 deletions src/valdi_modules/src/valdi/valdi_core/src/ModuleLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ function resolveAbsoluteImport(normalizedPathEntries: string[]): ResolvedPath {
}

function resolveAbsoluteImportFromPath(path: string): ResolvedPath {
return resolveAbsoluteImport(normalizePath(path.split('/')));
const normalized = normalizePath(path.split('/'));
const result = resolveAbsoluteImport(normalized);
return result;
}

function resolvePath(path: string, fromResolvedPath: ResolvedPath): ResolvedPath {
Expand All @@ -77,7 +79,8 @@ function resolvePath(path: string, fromResolvedPath: ResolvedPath): ResolvedPath
const combinedPath = fromResolvedPath.directoryPaths.slice();
combinedPath.push(...importPathEntries);
const normalized = normalizePath(combinedPath);
return resolveAbsoluteImport(normalized);
const result = resolveAbsoluteImport(normalized);
return result;
} else {
// Absolute import
const normalized = normalizePath(importPathEntries);
Expand Down Expand Up @@ -373,7 +376,8 @@ export class ModuleLoader implements IModuleLoader {
module = this.modules[resolvedPath.absolutePath]!;
}

return this.makeRequire(module);
const requireFunc = this.makeRequire(module);
return requireFunc;
}

getOrCreateSourceMap = (path: string, sourceMapFactory: SourceMapFactory): ISourceMap | undefined => {
Expand Down
4 changes: 4 additions & 0 deletions src/valdi_modules/src/valdi/valdi_core/web/DeviceBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ export function isDesktop(): boolean {
return !(isIOS || isAndroid);
}

export function isWeb(): boolean {
return isBrowser;
}

// On web there is no native back button; some apps emulate via history.
// Keep undefined to honor your API shape.
export const setBackButtonObserver: ((observer: (() => boolean) | undefined) => void) | undefined = undefined;
2 changes: 1 addition & 1 deletion src/valdi_modules/src/valdi/valdi_core/web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"skipLibCheck": true,
"composite": true,
"allowJs": true
},
}
}
4 changes: 4 additions & 0 deletions src/valdi_modules/src/valdi/valdi_http/web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@
"composite": true,
"allowJs": true
},
"exclude": [
"debug/**",
"release/**"
]
}
Loading
Loading