diff --git a/appserver/appserver.ts b/appserver/appserver.ts index a15f3164..8b05006c 100644 --- a/appserver/appserver.ts +++ b/appserver/appserver.ts @@ -8,6 +8,8 @@ import { type Channel } from "./channel.ts"; import { type Module } from "./module.ts"; export class AppServer { + static default = Symbol("default"); + runMode: runModes.RunMode; events: typeof events; di: typeof di; @@ -34,6 +36,10 @@ export class AppServer { this.channels.set(name, channel); } - execute(_options: unknown) { + setAsDefaultAppServer() { + this.di.register(AppServer.default, this); } + + // execute(_options: unknown) { + // } } diff --git a/appserver/version-checker.ts b/appserver/version-checker.ts index 2171e8dc..c21181ef 100644 --- a/appserver/version-checker.ts +++ b/appserver/version-checker.ts @@ -3,27 +3,27 @@ import * as runtime from "../standards/runtime.ts"; import { semver } from "./deps.ts"; -export function compareSemanticVersions( +export const compareSemanticVersions = ( currentVersion: semver.SemVer, targetVersion: semver.SemVerRange | semver.SemVer, -) { +) => { if (semver.isSemVerRange(targetVersion)) { return semver.testRange(currentVersion, targetVersion); } return !semver.gte(currentVersion, targetVersion); -} +}; -export function compareTextVersions( +export const compareTextVersions = ( currentVersion: string, targetVersion: string, -) { +) => { const currentSemanticVersion = semver.parse(currentVersion); const targetSemanticVersion = semver.parseRange(targetVersion); return compareSemanticVersions(currentSemanticVersion, targetSemanticVersion); -} +}; -export function checkMinDenoVersion(minimumVersion: string) { +export const checkMinDenoVersion = (minimumVersion: string) => { return compareTextVersions(runtime.version.runtime, minimumVersion); -} +}; diff --git a/collector/collector.ts b/collector/collector.ts index fbbf662c..9c780241 100644 --- a/collector/collector.ts +++ b/collector/collector.ts @@ -39,7 +39,7 @@ export interface CollectExportsOptions { ignoreFilePattern?: RegExp; } -export async function collectExports(options: CollectExportsOptions) { +export const collectExports = async (options: CollectExportsOptions) => { const ignoreFilePattern = options.ignoreFilePattern ?? patterns.JS_TEST_FILE_PATTERN; @@ -76,4 +76,4 @@ export async function collectExports(options: CollectExportsOptions) { } return exports; -} +}; diff --git a/collector/manifest.ts b/collector/manifest.ts index 0b6e48a9..b62a495c 100644 --- a/collector/manifest.ts +++ b/collector/manifest.ts @@ -19,7 +19,7 @@ const PLACEHOLDER_SUFFIX = "__//!!##"; /** * Import specifiers must have forward slashes */ -function toImportSpecifier(file: string) { +const toImportSpecifier = (file: string) => { const specifier = posix.normalize(file).replace(/\\/g, "/"); if (!specifier.startsWith(".")) { @@ -27,14 +27,14 @@ function toImportSpecifier(file: string) { } return specifier; -} +}; // Create a valid JS identifier out of the project relative specifier. // Note that we only need to deal with strings that _must_ have been // valid file names in Windows, macOS and Linux and every identifier we // create here will be prefixed with at least one "$". This greatly // simplifies the invalid characters we have to account for. -export function specifierToIdentifier(specifier: string, used: Set) { +export const specifierToIdentifier = (specifier: string, used: Set) => { // specifier = specifier.replace(/^(?:\.\/pkg)\//, ""); const ext = path.extname(specifier); if (ext) { @@ -62,29 +62,32 @@ export function specifierToIdentifier(specifier: string, used: Set) { if (used.has(ident)) { let check = ident; let i = 1; + while (used.has(check)) { check = `${ident}_${i++}`; } + ident = check; } used.add(ident); + return ident; -} +}; -const getSortFn = function () { +const getSortFn = () => { const naturalCollator = new Intl.Collator(undefined, { numeric: true }); return naturalCollator.compare; }; -const placeholder = function (text: string) { +const placeholder = (text: string) => { return `${PLACEHOLDER_PREFIX}${text}${PLACEHOLDER_SUFFIX}`; }; -export async function writeManifestToString( +export const writeManifestToString = async ( collection: Array<[string, Array<[string, unknown]>]>, -) { +) => { const sortFn = getSortFn(); const used = new Set(); @@ -102,7 +105,7 @@ export async function writeManifestToString( `import * as ${IMPORT_PREFIX}${identifier} from "${specifier}";`, ); - const ref = function (target: unknown) { + const ref = (target: unknown) => { const name = (target as { name: string }).name; return placeholder(`${IMPORT_PREFIX}${identifier}.${name}`); @@ -132,9 +135,11 @@ export const manifest = ${manifestSerialized}; const manifestStr = await formatter.format(output); return manifestStr; -} +}; -export async function buildManifest(options: collector.CollectExportsOptions) { +export const buildManifest = async ( + options: collector.CollectExportsOptions, +) => { const collection = await collector.collectExports(options); const manifestStr = await writeManifestToString(collection); @@ -152,4 +157,4 @@ export async function buildManifest(options: collector.CollectExportsOptions) { `%cThe manifest file has been generated for ${exportCount} exports in ${exportModules.length} modules.`, "color: blue", ); -} +}; diff --git a/collector/validator-identifier/mod.ts b/collector/validator-identifier/mod.ts index 0e5ac0ec..a7bdc482 100644 --- a/collector/validator-identifier/mod.ts +++ b/collector/validator-identifier/mod.ts @@ -23,7 +23,7 @@ const nonASCIIidentifier = new RegExp( // This has a complexity linear to the value of the code. The // assumption is that looking up astral identifier characters is // rare. -function isInAstralSet(code: number, set: readonly number[]): boolean { +const isInAstralSet = (code: number, set: readonly number[]) => { let pos = 0x10000; for (let i = 0, length = set.length; i < length; i += 2) { @@ -39,7 +39,7 @@ function isInAstralSet(code: number, set: readonly number[]): boolean { } return false; -} +}; // These are a run-length and offset-encoded representation of the // >0xffff code points that are a valid part of identifiers. The @@ -902,53 +902,65 @@ const astralIdentifierCodes = [ // Test whether a given character code starts an identifier. -export function isIdentifierStart(code: number): boolean { +export const isIdentifierStart = (code: number) => { if (code < charCodes.uppercaseA) { return code === charCodes.dollarSign; } + if (code <= charCodes.uppercaseZ) { return true; } + if (code < charCodes.lowercaseA) { return code === charCodes.underscore; } + if (code <= charCodes.lowercaseZ) { return true; } + if (code <= 0xffff) { return ( code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code)) ); } + return isInAstralSet(code, astralIdentifierStartCodes); -} +}; // Test whether a given character is part of an identifier. -export function isIdentifierChar(code: number): boolean { +export const isIdentifierChar = (code: number) => { if (code < charCodes.digit0) { return code === charCodes.dollarSign; } + if (code < charCodes.colon) { return true; } + if (code < charCodes.uppercaseA) { return false; } + if (code <= charCodes.uppercaseZ) { return true; } + if (code < charCodes.lowercaseA) { return code === charCodes.underscore; } + if (code <= charCodes.lowercaseZ) { return true; } + if (code <= 0xffff) { return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code)); } + return ( isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes) ); -} +}; diff --git a/di/invoker.ts b/di/invoker.ts index c4979cd6..a9876cc0 100644 --- a/di/invoker.ts +++ b/di/invoker.ts @@ -7,7 +7,7 @@ import { type ServiceValue, } from "./primitives.ts"; -function getFunctionParametersFromString(fnSerialized: string) { +const getFunctionParametersFromString = (fnSerialized: string) => { const match = fnSerialized.match(/(?:function.*?\(|\()(.*?)(?:\)|=>)/); if (match && match[1]) { @@ -15,13 +15,13 @@ function getFunctionParametersFromString(fnSerialized: string) { } return []; -} +}; -function getFunctionParameters(fn: AnonymousFunction) { +const getFunctionParameters = (fn: AnonymousFunction) => { return getFunctionParametersFromString(fn.toString()); -} +}; -// function analyzeParameter(param: string) { +// const analyzeParameter = (param: string) => { // const decoratorMatch = param.match(/@(\w+)\(([^)]+)\)/); // const defaultValueMatch = param.match(/(.*?)=(.*)/); // const isRestOrSpread = param.startsWith("..."); @@ -53,7 +53,7 @@ function getFunctionParameters(fn: AnonymousFunction) { // decorators: decorators, // }; // } -// } +// }; export const invoke = < T extends AnonymousFunction, diff --git a/functions/fn.test.ts b/functions/fn.test.ts index ca8adc7e..550c8c1c 100644 --- a/functions/fn.test.ts +++ b/functions/fn.test.ts @@ -9,7 +9,7 @@ bdd.describe("cool/functions/fn", () => { const spyFn = mock.spy(); const fns = fn>( - function () { + () => { spyFn(); return Ok("Testing"); diff --git a/jsx-runtime.test/root.test.tsx b/jsx-runtime.test/root.test.tsx index fab26264..596cf05a 100644 --- a/jsx-runtime.test/root.test.tsx +++ b/jsx-runtime.test/root.test.tsx @@ -24,11 +24,11 @@ bdd.describe("cool/jsx-runtime", () => { const spyFn = mock.spy(); // deno-lint-ignore no-explicit-any - function hook(vnode: any) { + const hook = (vnode: any) => { if (vnode.props["lime-hack"]) { spyFn(); } - } + }; // @ts-ignore typescript don't recognize this jsxRuntimeInternal.options.tagHelperHook = hook; diff --git a/jsx-runtime.test/root.tsx b/jsx-runtime.test/root.tsx index 5733f172..302c1cd5 100644 --- a/jsx-runtime.test/root.tsx +++ b/jsx-runtime.test/root.tsx @@ -2,15 +2,15 @@ // @ts-nocheck: JSX.IntrinsicElements issue. -export function SubComponent() { +export const SubComponent = () => { return
sub component
; -} +}; export interface ComponentProps { foo: string; } -export function Component(props: ComponentProps) { +export const Component = (props: ComponentProps) => { return (
hello {props.foo} @@ -18,8 +18,8 @@ export function Component(props: ComponentProps) {
); -} +}; -export function Root() { +export const Root = () => { return ; -} +}; diff --git a/jsx-runtime/encoder.js b/jsx-runtime/encoder.js index cb7c09bb..abbf796d 100644 --- a/jsx-runtime/encoder.js +++ b/jsx-runtime/encoder.js @@ -9,9 +9,11 @@ const ENCODED_ENTITIES = /["&<]/; /** @param {string} str */ -export function encodeEntities(str) { +export const encodeEntities = (str) => { // Skip all work for strings with no entities needing encoding: - if (str.length === 0 || ENCODED_ENTITIES.test(str) === false) return str; + if (str.length === 0 || ENCODED_ENTITIES.test(str) === false) { + return str; + } let last = 0, i = 0, @@ -33,12 +35,21 @@ export function encodeEntities(str) { default: continue; } + // Append skipped/buffered characters and the encoded entity: - if (i !== last) out += str.slice(last, i); + if (i !== last) { + out += str.slice(last, i); + } + out += ch; + // Start the next seek/buffer after the entity's offset: last = i + 1; } - if (i !== last) out += str.slice(last, i); + + if (i !== last) { + out += str.slice(last, i); + } + return out; -} +}; diff --git a/jsx-runtime/index.js b/jsx-runtime/index.js index 489ea3ea..089a29f9 100644 --- a/jsx-runtime/index.js +++ b/jsx-runtime/index.js @@ -42,7 +42,7 @@ let vnodeId = 0; * @param {unknown} [__source] * @param {unknown} [__self] */ -function createVNode(type, props, key, _isStaticChildren, __source, __self) { +export const jsx = (type, props, key, _isStaticChildren, __source, __self) => { // We'll want to preserve `ref` in props to get rid of the need for // forwardRef components in the future, but that should happen via // a separate PR. @@ -93,7 +93,10 @@ function createVNode(type, props, key, _isStaticChildren, __source, __self) { } return vnode; -} +}; + +export const jsxs = jsx; +export const jsxDEV = jsx; /** * Create a template vnode. This function is not expected to be @@ -102,12 +105,13 @@ function createVNode(type, props, key, _isStaticChildren, __source, __self) { * @param {Array} exprs * @returns {VNode} */ -function jsxTemplate(templates, ...exprs) { +export const jsxTemplate = (templates, ...exprs) => { const vnode = createVNode(elements.Fragment, { tpl: templates, exprs }); // Bypass render to string top level Fragment optimization vnode.key = vnode._vnode; + return vnode; -} +}; const JS_TO_CSS = {}; const CSS_REGEX = /[A-Z]/g; @@ -120,7 +124,7 @@ const CSS_REGEX = /[A-Z]/g; * @param {*} value The attribute value * @returns {string} */ -function jsxAttr(name, value) { +export const jsxAttr = (name, value) => { if (options.attr) { const result = options.attr(name, value); @@ -174,7 +178,7 @@ function jsxAttr(name, value) { } return `${name}="${encodeEntities(value)}"`; -} +}; /** * Escape a dynamic child passed to `jsxTemplate`. This function @@ -183,7 +187,7 @@ function jsxAttr(name, value) { * @param {*} value * @returns {string | null | VNode | Array} */ -function jsxEscape(value) { +export const jsxEscape = (value) => { if ( value == null || typeof value === "boolean" || @@ -208,14 +212,4 @@ function jsxEscape(value) { } return encodeEntities("" + value); -} - -export { - createVNode as jsx, - createVNode as jsxDEV, - createVNode as jsxs, - jsxAttr, - jsxEscape, - // precompiled JSX transform - jsxTemplate, }; diff --git a/lime/mod.ts b/lime/mod.ts index 098fa551..80395add 100644 --- a/lime/mod.ts +++ b/lime/mod.ts @@ -1,33 +1,19 @@ // Copyright 2023-present Eser Ozvataf and other contributors. All rights reserved. Apache-2.0 license. -import * as appserver from "../appserver/mod.ts"; - -export class Lime extends appserver.AppServer { - constructor() { - super(); - } - - // deno-lint-ignore no-explicit-any - manifest(_manifest: any): Lime { - return this; - } - - // deno-lint-ignore no-explicit-any - config(_config: any): Lime { - return this; - } - - dev(): Lime { - return this; - } - - start(): void { - } -} - -export function lime() { - return new Lime(); -} +import * as primitives from "./primitives.ts"; +export * from "./primitives.ts"; + +/** + * Initializes a new Lime instance and sets it as the default instance. + * + * @returns {Lime} + */ +export const lime = () => { + const instance = new primitives.Lime(); + instance.setAsDefaultAppServer(); + + return instance; +}; /* lime() diff --git a/lime/primitives.ts b/lime/primitives.ts new file mode 100644 index 00000000..bb1be117 --- /dev/null +++ b/lime/primitives.ts @@ -0,0 +1,58 @@ +// Copyright 2023-present Eser Ozvataf and other contributors. All rights reserved. Apache-2.0 license. + +import * as runModes from "../standards/run-modes.ts"; +import * as appserver from "../appserver/mod.ts"; + +export type LimeExportedSymbol = unknown; + +export interface LimeManifest { + baseUrl: string; + exports: Array<[string, Array<[string, LimeExportedSymbol]>]>; +} + +export interface LimeOptions { + basePath: string; +} + +export interface LimeState { + manifest: LimeManifest | null; + options: LimeOptions; +} + +export class Lime extends appserver.AppServer { + state: LimeState; + + constructor(options: Partial = {}) { + super(); + + this.state = { + manifest: null, + options: { + basePath: ".", + ...options, + }, + }; + } + + setManifest(manifest: LimeManifest | null): Lime { + this.state.manifest = manifest; + + return this; + } + + setOptions(options: LimeOptions): Lime { + this.state.options = options; + + return this; + } + + dev(): Lime { + this.runMode = runModes.RunMode.Development; + + return this; + } + + start(): void { + // this.execute(_options); + } +} diff --git a/standards/run-modes.ts b/standards/run-modes.ts index a7c6975a..3415625a 100644 --- a/standards/run-modes.ts +++ b/standards/run-modes.ts @@ -6,14 +6,14 @@ export enum RunMode { Test = 2, } -export function inDevelopmentMode(mode: RunMode): boolean { +export const inDevelopmentMode = (mode: RunMode) => { return (mode & RunMode.Production) !== RunMode.Production; -} +}; -export function inProductionMode(mode: RunMode): boolean { +export const inProductionMode = (mode: RunMode) => { return (mode & RunMode.Production) === RunMode.Production; -} +}; -export function inTestMode(mode: RunMode): boolean { +export const inTestMode = (mode: RunMode) => { return (mode & RunMode.Test) === RunMode.Test; -} +}; diff --git a/standards/runtime.ts b/standards/runtime.ts index 38542ed4..00c6952a 100644 --- a/standards/runtime.ts +++ b/standards/runtime.ts @@ -117,10 +117,10 @@ export interface RuntimeConfig { }; } -export async function locateRuntimeConfig( +export const locateRuntimeConfig = async ( directory: string, searchParents = false, -): Promise { +): Promise => { let dir = directory; while (true) { @@ -146,27 +146,27 @@ export async function locateRuntimeConfig( } return undefined; -} +}; -export async function readRuntimeConfig( +export const readRuntimeConfig = async ( configPath: string, -): Promise<{ config: RuntimeConfig; path: string }> { +): Promise<{ config: RuntimeConfig; path: string }> => { const file = await Deno.readTextFile(configPath); return { config: JSONC.parse(file) as RuntimeConfig, path: configPath, }; -} +}; -// function isObject(value: unknown) { +// const isObject = (value: unknown) => { // return value !== null && typeof value === "object" && // !Array.isArray(value); -// } +// }; -export async function locateAndReadRuntimeConfig( +export const locateAndReadRuntimeConfig = async ( baseDir: string, -): Promise<{ config: RuntimeConfig; path: string | undefined }> { +): Promise<{ config: RuntimeConfig; path: string | undefined }> => { const configPath = await locateRuntimeConfig(baseDir, true); if (configPath === undefined) { @@ -192,4 +192,4 @@ export async function locateAndReadRuntimeConfig( // } return result; -} +};