-
Notifications
You must be signed in to change notification settings - Fork 0
tempo.config.ts pattern #48
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
Changes from 1 commit
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
36fb89f
tempo.config.ts pattern
magmacomputing bd3d880
PR 1st review
magmacomputing 7d28da9
package.json bin/tempo.js
magmacomputing 213cccc
Localized Modifiers
magmacomputing 158c125
post benchmark tests
magmacomputing 6ceb8ed
PR 2nd review
magmacomputing File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| #!/usr/bin/env node | ||
|
|
||
| import fs from 'node:fs'; | ||
| import path from 'node:path'; | ||
| import { fileURLToPath } from 'node:url'; | ||
|
|
||
| // CLI Arguments | ||
| const args = process.argv.slice(2); | ||
| const command = args[0]; | ||
|
|
||
| // The location of the templates relative to this bin script (bin/tempo.js -> template/) | ||
| const __filename = fileURLToPath(import.meta.url); | ||
| const __dirname = path.dirname(__filename); | ||
| const templateDir = path.join(__dirname, '..', 'template'); | ||
| const cwd = process.cwd(); | ||
|
|
||
| // Helper to copy a file safely | ||
| function safelyCopy(sourceFile, targetFile, successMessage) { | ||
| const sourcePath = path.join(templateDir, sourceFile); | ||
| const targetPath = path.join(cwd, targetFile); | ||
|
|
||
| if (fs.existsSync(targetPath)) { | ||
| console.error(`\x1b[31m[Tempo Scaffold] Aborted.\x1b[0m File already exists at: ${targetPath}`); | ||
| console.error(`We refused to overwrite your existing file. If you want to scaffold a new one, please delete the existing file first.`); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| if (!fs.existsSync(sourcePath)) { | ||
| console.error(`\x1b[31m[Tempo Scaffold] Error.\x1b[0m Could not find template file at: ${sourcePath}`); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| try { | ||
| fs.copyFileSync(sourcePath, targetPath); | ||
| console.log(`\x1b[32m[Tempo Scaffold] Success!\x1b[0m ${successMessage}`); | ||
| } catch (err) { | ||
| console.error(`\x1b[31m[Tempo Scaffold] Failed to copy file:\x1b[0m ${err.message}`); | ||
| process.exit(1); | ||
| } | ||
| } | ||
|
|
||
| // Route commands | ||
| if (command === 'scaffold:config') { | ||
| safelyCopy('tempo.config.sample.ts', 'tempo.config.ts', 'Created tempo.config.ts'); | ||
| } else if (command === 'scaffold:html') { | ||
| safelyCopy('index.sample.html', 'index.html', 'Created index.html boilerplate'); | ||
| } else if (command === 'scaffold:all') { | ||
| safelyCopy('tempo.config.sample.ts', 'tempo.config.ts', 'Created tempo.config.ts'); | ||
| safelyCopy('index.sample.html', 'index.html', 'Created index.html boilerplate'); | ||
| } else { | ||
| console.log(` | ||
| \x1b[36m@magmacomputing/tempo\x1b[0m CLI | ||
|
|
||
| Available Commands: | ||
| scaffold:config Copies a sample tempo.config.ts into your current directory. | ||
| scaffold:html Copies a working HTML sandbox (index.html) into your current directory. | ||
| scaffold:all Copies both files. | ||
|
|
||
| Usage: | ||
| npx @magmacomputing/tempo <command> | ||
| `); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import type { Options } from '../tempo.type.js'; | ||
|
|
||
| /** | ||
| * Identity function to provide TypeScript autocomplete for Tempo configurations. | ||
| */ | ||
| export function defineConfig(config: Options): Options { | ||
| return config; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| import { isFunction } from '#library/assertion.library.js'; | ||
| import type { Options } from '../tempo.type.js'; | ||
|
|
||
| // Minimal declaration so TS doesn't complain in browser environments without @types/node | ||
| declare const process: any; | ||
|
|
||
| /** | ||
| * Automatically discovers and loads a tempo.config.* file by traversing upwards | ||
| * from the current working directory until a package.json is found. | ||
| */ | ||
| export async function resolveConfig(options?: { cwd?: string, configFile?: string }): Promise<Options | undefined> { | ||
| // Skip discovery if not in a Node/Deno/Bun environment | ||
| if (typeof process === 'undefined' || !isFunction(process?.cwd)) | ||
| return undefined; | ||
|
|
||
| try { | ||
| // Use variables for dynamic imports to prevent bundlers from statically analyzing and failing | ||
| const modFs = 'node:fs'; | ||
| const modUrl = 'node:url'; | ||
| const modPath = 'node:path'; | ||
|
|
||
| const [fs, path] = await Promise.all([ | ||
| import(modFs), | ||
| import(modPath), | ||
| ]); | ||
|
|
||
| let currentDir = options?.cwd || process.cwd(); | ||
|
|
||
| const loadFile = async (configPath: string, ext: string) => { | ||
| if (ext === '.json') { | ||
| const content = fs.readFileSync(configPath, 'utf8'); | ||
| return JSON.parse(content) as Options; | ||
| } else { | ||
| // Use pathToFileURL to safely load absolute paths on Windows | ||
| const { pathToFileURL } = await import(modUrl); | ||
| const imported = await import(pathToFileURL(configPath).href); | ||
| return imported.default || imported; | ||
| } | ||
| }; | ||
|
|
||
| if (options?.configFile) { | ||
| const explicitPath = path.resolve(currentDir, options.configFile); | ||
| if (fs.existsSync(explicitPath)) { | ||
| try { | ||
| return await loadFile(explicitPath, path.extname(explicitPath)); | ||
| } catch (err) { | ||
| console.warn(`[Tempo] Failed to load explicit config file at ${explicitPath}:`, err); | ||
| return undefined; | ||
| } | ||
| } else { | ||
| console.warn(`[Tempo] Explicit config file not found at ${explicitPath}`); | ||
| return undefined; | ||
| } | ||
| } | ||
|
|
||
| const rootPath = path.parse(currentDir).root; | ||
|
|
||
| while (currentDir !== rootPath) { | ||
| const pkgJson = path.join(currentDir, 'package.json'); | ||
| const exts = ['.ts', '.js', '.mjs', '.cjs', '.json']; | ||
|
|
||
| for (const ext of exts) { | ||
| const configPath = path.join(currentDir, `tempo.config${ext}`); | ||
| if (fs.existsSync(configPath)) { | ||
| try { | ||
| return await loadFile(configPath, ext); | ||
| } catch (err) { | ||
| console.warn(`[Tempo] Found config file at ${configPath} but failed to load it:`, err); | ||
| return undefined; | ||
| } | ||
| } | ||
| } | ||
|
magmacomputing marked this conversation as resolved.
|
||
|
|
||
| if (fs.existsSync(pkgJson)) { | ||
| // Reached project root, stop searching | ||
| break; | ||
| } | ||
|
|
||
| currentDir = path.dirname(currentDir); | ||
| } | ||
| } catch (e) { | ||
| // Environment doesn't support node 'fs' or 'path', skip discovery | ||
| } | ||
|
|
||
| return undefined; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
|
|
||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| <title>Hello Tempo</title> | ||
| <!-- | ||
| This is the sanctioned browser import map for Tempo. | ||
| Note: For production, you may want to bundle these or serve them from your own infrastructure. | ||
| --> | ||
| <script type="importmap"> | ||
| { | ||
| "imports": { | ||
| "@js-temporal/polyfill": "https://cdn.jsdelivr.net/npm/@js-temporal/polyfill@0.5/dist/index.esm.js", | ||
| "@magmacomputing/tempo": "https://cdn.jsdelivr.net/npm/@magmacomputing/tempo@3/dist/tempo.bundle.esm.js", | ||
| "@magmacomputing/tempo/core": "./node_modules/@magmacomputing/tempo/dist/core.index.js", | ||
| "@magmacomputing/tempo/duration": "./node_modules/@magmacomputing/tempo/dist/module/module.duration.js", | ||
| "@magmacomputing/tempo/mutate": "./node_modules/@magmacomputing/tempo/dist/module/module.mutate.js", | ||
| "@magmacomputing/tempo/plugin": "./node_modules/@magmacomputing/tempo/dist/plugin/plugin.index.js", | ||
| "@magmacomputing/tempo/library": "./node_modules/@magmacomputing/tempo/dist/library.index.js", | ||
| "@magmacomputing/tempo/enums": "./node_modules/@magmacomputing/tempo/dist/support/support.enum.js", | ||
| "#tempo/license": "./node_modules/@magmacomputing/tempo/dist/plugin/license/license.validator.js" | ||
| } | ||
| } | ||
| </script> | ||
| </head> | ||
|
|
||
| <body style="font-family: sans-serif; padding: 2rem;"> | ||
| <h1>Tempo Hello World</h1> | ||
| <div id="output" style="padding: 1rem; background: #f0f0f0; border-radius: 8px;"> | ||
| Initializing Tempo... | ||
| </div> | ||
|
|
||
| <script type="module"> | ||
| import { Tempo } from '@magmacomputing/tempo'; | ||
|
|
||
| async function bootstrap() { | ||
| const output = document.getElementById('output'); | ||
| try { | ||
| // Initialize the Tempo engine. | ||
| // This will automatically look for 'tempo.config.ts' in modern environments, | ||
| // or you can pass config options directly to Tempo.init() instead. | ||
| await Tempo.bootstrap(); | ||
|
|
||
| const now = new Tempo(); | ||
| const formatted = now.format('{wkd}, {mon} {dd}, {yyyy} at {hh}:{mi}:{ss} {mer}'); | ||
|
|
||
| output.innerHTML = ` | ||
| <strong>Success!</strong> Tempo is initialized.<br><br> | ||
| Current Local Time: <span style="color: blue;">${formatted}</span> | ||
| `; | ||
| } catch (err) { | ||
| output.innerHTML = `<strong style="color: red;">Error initializing Tempo:</strong> ${err.message}`; | ||
| console.error(err); | ||
| } | ||
| } | ||
|
|
||
| bootstrap(); | ||
| </script> | ||
| </body> | ||
|
|
||
| </html> |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.