(m7-js-lib)
You may paste this file directly into another project so that an LLM can correctly reason about and use the software. This document defines the public API contract only. It intentionally omits implementation details and source code.
Anything not explicitly specified here must be treated as undefined behavior.
This contract defines the public, stable interface for m7-js-lib, including:
- singleton runtime identity and lifecycle
index.jsandauto.jsentrypoint behavior- initialization and re-initialization guarantees
- post-init namespace availability and exported function names
- environment and error guarantees
- extension posture boundaries
This contract does not define:
- internal boot order details beyond public guarantees
- private helpers or non-exported symbols
- implementation strategies
- undocumented side effects
m7-js-lib is a singleton by intent.
- one
libobject exists per loaded module instance - re-initialization mutates/rebuilds the same object reference
- no multi-instance factory API is provided
Two entrypoint modes are defined:
src/index.js: side-effect free import; explicitinit()requiredsrc/auto.js: import-timeinit()convenience
The library is utility-oriented and normalization-first.
- APIs are generally permissive and coercion-oriented
- strict rejection is used only on explicit guard boundaries
m7-js-lib guarantees:
-
Stable singleton identity
init()never returns a new singleton object identity. -
Explicit lifecycle control in
index.jsImportingindex.jsalone does not initialize modules. -
Deterministic init guarding Re-entrant initialization is guarded and throws explicit errors.
-
Failure-safe rebuild semantics Partial init state is cleared on bootstrap failure.
-
Contracted convenience mode
auto.jsalways attemptsinit()at import time.
Exports:
default->lib- named ->
lib - named ->
init
Importing src/index.js has no runtime initialization side effect.
Exports:
default->lib- named ->
lib - named ->
init
Behavior:
- executes
init()at module import time - if initialization throws, import fails with the same error
import { lib, init } from "./src/index.js";
init();Accepted input:
optsobject form:{ force?: boolean }- non-object
optsare normalized to{ force: !!opts }
Behavior:
- If already initialized and
force !== true, returnslib. - If initialization is in progress and
force !== true, throws:"[lib.init] Initialization already in progress"
- If
force === truewhile initialization is in progress, throws:"[lib.init] Cannot force re-init while initialization is in progress"
- If
force === trueand initialized:- clears enumerable keys on
lib - resets init state, then rebuilds
- clears enumerable keys on
- On successful bootstrap:
- sets internal initialized state true
- sets
lib._initialized = true - returns
lib
- On bootstrap failure:
- clears partially-attached enumerable keys
- sets
lib._initialized = false - resets initialized state and rethrows original error
- Internal initializing guard is always cleared in
finally.
- exists as a non-enumerable property on exported
lib falsebefore successful inittrueafter successful init- reset to
falseduring failed/forced rebuild paths
No other internal metadata fields are guaranteed stable.
After successful init(), the following namespaces are available:
lib._bootlib._httplib.argslib.arraylib.boollib.domlib.funclib.hashlib.numberlib.requirelib.servicelib.strlib.utils
lib._boot
installresolveRoot
lib._http
getpostrequest
lib.args
parsesliceisArguments
lib.array
appendsubtracttrimistolenfilterStrings
lib.bool
intentTrueintentFalseisisIntenttobyIntenthasIntent(alias)ish(alias)yes(alias)no(alias)
lib.func
namewrapperpostWrappreWrapget
lib.hash
getsetlegacySetexpandtoishasKeysappendmergemergeManyflatteninflateexistsstripfiltergetUntilNotEmptydeepCopykeysemptyslice
lib.number
clamptoInt
lib.require
alllib(alias)service
lib.service
setgetstartstoplist
Additionally exposes:
services(registry object)
lib.str
islctostripCommentscountCharsinterp
lib.utils
isArraytoArrayisHashtoHashdeepCopyisScalartoStringbaseTypeisEmptylinkTypeclamptoNumbergetFunctionstripCommentslc
lib.dom
getsetisisDomgetElementbyIdremoveElementqsinsertAfterfilterAttributesattemptcreate(namespace)append(namespace)form(namespace)transform(namespace)
lib.dom.create
csslink(alias)jselement
lib.dom.append
beforeafterprependappendbeforeBeginafterBeginbeforeEndafterEndadjacentreplaceremoveemptyresolveTarget
lib.dom.form
submitcollect(alias)collectFormtoJsonmakeUrlmakeBodymakeHeadergetDomKVarrayToQSarrayToHash
lib.dom.transform
elementlist
This section defines practical usage semantics for the public functions. It is intended to be sufficient for correct consumer usage without source access.
Function index links in this file are convenience mirrors only: ./functions/INDEX.md.
Explicit lifecycle mode:
import { lib, init } from "./src/index.js";
init();Alias import is valid:
import { lib, init as initLib } from "./src/index.js";
initLib();Auto mode:
import lib from "./src/auto.js"; // init() already executedRule:
- when using
src/index.js, callinit()before consuming attached namespaces
Alias exports are behaviorally equivalent to their canonical targets.
Examples:
lib.require.lib === lib.require.alllib.bool.yes === lib.bool.intentTruelib.dom.create.link === lib.dom.create.csslib.utils.isArraydelegates tolib.array.is
Unless a function explicitly documents otherwise, path strings follow this contract:
- dot-delimited segments:
"a.b.c" - no bracket notation:
"a[0].b"is not contract-guaranteed - no escaped-dot key syntax is defined
- segments are treated as key tokens
Numeric segment note:
- numeric segments are treated as string keys by default
- numeric-index behavior is opt-in only where documented (for example
lib.hash.set(..., { arrayIndex: true }))
Multi-target string note:
- APIs that accept target/name lists as a single string (for example
lib.require.all,lib.require.service) split entries on whitespace - array input bypasses whitespace splitting and is used as provided
Primary usage:
const obj = {};
lib.hash.set(obj, "a.b.c", 1);
const v = lib.hash.get(obj, "a.b.c", null); // 1
const ok = lib.hash.exists(obj, "a.b.c"); // trueKey function semantics:
get(rec, path, def):- safe deep lookup
- returns
defwhen missing/unreadable
set(rec, path, value, opts):- creates missing containers as needed
- with
opts.arrayIndex === true, numeric segments may create/use arrays
legacySet(rec, path, value):- legacy DOM-safe setter variant
- returns
1on success,0on failure
to(value, hotkey?):- always returns a plain object
- wraps non-object values under
hotkeywhen provided
merge(left, right)/mergeMany(list):- deep merge helpers (non-destructive result)
flatten(rec)/inflate(rec):- convert between nested and dotted-key representations
slice(rec, list, opts):- selects paths into a new object
- defaults to all keys only when
listis omitted/falsy - whitespace-only list is treated as an explicit empty list
opts.setsupports flags:- truthy -> force include keys even if missing
"l"-> skip empty-string/null values (when not force set)"d"-> skip null values (when not force set)
Primary usage:
const list = lib.array.to("a b c", { split: /\s+/, trim: true }); // ["a","b","c"]Key function semantics:
to(value, opts):- total coercion helper returning an array
- falsy input yields
[] opts.splitsplits string inputopts.trimtrims strings and removes empties
trim(value):- returns new array with trimmed string members and no empty strings
subtract(list, exclude):- removes all excluded values
append(input, pre, post):- wraps each item with prefix/postfix
- returns
undefinedfor unsupported input types
len(value):- array length or
0
- array length or
filterStrings(value, opts):- returns sanitized non-empty string array
Primary usage:
lib.bool.yes("true"); // true
lib.bool.no("false"); // true
lib.bool.isIntent("0"); // trueKey function semantics:
intentTrue/yes: accepts explicit affirmative literals onlyintentFalse/no: accepts explicit negative literals onlyisIntent/hasIntent/ish: intent-aware validationto: strict boolean conversion (truestays true, everything else false)byIntent: true only for explicit affirmative intent
Primary usage:
lib.number.clamp("12", 0, 10, 0); // 10
lib.number.toInt("42.9", 0); // 42Key function semantics:
clamp(n, min, max, def):- finite numeric coercion + bounds clamp
- invalid input returns fallback
toInt(val, def):- strict integer conversion policy
- rejects malformed numeric strings
Primary usage:
lib.str.to(12); // "12"
lib.str.lc("HELLO"); // "hello"
lib.str.countChars("banana", ["a","n"]); // 5
lib.str.interp("Hello ${name}", { name: "Ada" }); // "Hello Ada"Key function semantics:
is(value): string primitive checkto(value, opts):- scalar-to-string coercion helper
- returns
undefinedfor unsupported values unless forced
lc(value, force): lowercase helperstripComments(text, opts): removes JS-style comments by modecountChars(str, chars): counts target charactersinterp(tpl, scheme, opts):- interpolates
${...}tokens using hash lookup or eval fallback - supports output shaping via
opts.tpl,opts.quote,opts.eval - supports raw value passthrough when
opts.literaland tpl is exactly one token
- interpolates
Primary usage:
const fn = lib.func.get("myNamespace.doThing");
const wrapped = lib.func.wrapper(fn, "tail");Key function semantics:
get(f, opts):- resolves callable from function ref or root-relative string path
- root resolution order:
opts.root, thenlib._env.root - if no root is resolved, returns
undefined(or dummy fallback), even whenfis already a function - for string paths, lookup is root-relative dot-path resolution
opts.bind === trueattempts to bind resolved function to its parent objectopts.dummyenables no-op fallback when unresolved
wrapper(fun, ...tailArgs):- resolves target using
lib.utils.getFunction - returns
undefinedif unresolved - otherwise returns function that appends tail arguments at call time
- resolves target using
postWrap(funs, ...tailArgs):- resolves and runs each function in sequence with runtime+tail args
- returns
undefinedimmediately if any function in chain cannot be resolved - returns last result
preWrap(funs, ...headArgs):- same as
postWrapbut prepends head args - returns
undefinedimmediately if any function in chain cannot be resolved
- same as
name():- best-effort caller-line extraction from stack
Primary usage:
lib.service.set("bus", eventBus);
lib.require.service("bus"); // [eventBus]
lib.require.all("hash.get array.to");lib.require semantics:
all(targets, opts):- validates dot-path targets on
lib targetsmay be:- whitespace-delimited string of paths (for example
"hash.get array.to") - array of explicit path strings
- whitespace-delimited string of paths (for example
- default return is array of resolved values
opts.returnMapreturns{ path: value }opts.allowFalsy(default true) allowsfalse,0, and""but still rejectsnull/undefinedopts.die(default true) controls throw vs partial result
- validates dot-path targets on
lib(...): alias ofall(...)service(names, opts):- validates services registered in
lib.service.services namesfollows same string/array normalization rules asall- same
returnMap/diebehavior asall
- validates services registered in
lib.service semantics:
set(name, svc)/get(name)/list()start(name, ...args):- calls
svc.start(...args)when available, else returns service value
- calls
stop(name, ...args):- calls
svc.stop(...args)when available, else returns service value
- calls
Primary usage:
const node = lib.dom.attempt("#app");
lib.dom.set(node, "text", "Hello");
const btn = lib.dom.create.element("button", { class: "btn" }, "Save");
lib.dom.append.append(btn, node);lib.dom semantics:
attempt(input, barf=false):- best-effort coercion to DOM element from element/id/event/query
- throws when unresolved and
barf === true
set(e, attr, val):- normalizes
attrto string - returns
undefinedwhen target is not a DOM element or normalized attr is empty - class operation attrs (case-insensitive):
setClass,addClass,removeClass,toggleClass - dataset paths supported:
"dataset"alone is not writable by contract"dataset.some.path"writes intoe.datasetpath and returns written value
- direct property write attrs (case-insensitive):
tagName,value,name,text,innerText,textContent,innerHTML,type,href,src,disabled,selected,checked - dotted non-dataset attrs delegate to legacy dotted setter behavior
- non-dotted attrs write via
setAttribute - return shape:
- class ops: implementation return from class API (
toggleClasstypically boolean; others typically undefined) - direct property write: assigned value
- other write paths: post-write
get(e, attr)result
- class ops: implementation return from class API (
- normalizes
get(e, attr):- returns
undefinedwhen target is not a DOM element - returns the element itself when
attris missing/falsy - dataset reads:
"dataset"->e.dataset"dataset.some.path"-> deep dataset value
- style reads:
"style"->e.style"style.display"->e.style.display- other
style.*paths ->undefined
- direct property reads (case-insensitive):
tagName,value,name,text,textContent,innerHTML,type - all other attrs read via
getAttribute
- returns
is/isDom: element detectiongetElement/byId/removeElement/insertAfter: direct element utilitiesqs(): query-string to object parsingfilterAttributes(e, regex, opts): attribute extraction/filtering helper- nested namespaces:
create,append,form,transform
lib.dom.create semantics:
element(tag, attrs, content)generic creatorjs(url, attrs)script element helpercss(url, attrs)stylesheet link helperlink(...)alias ofcss(...)
lib.dom.append semantics:
- insertion helpers:
before,after,prepend,append - position helpers:
beforeBegin,afterBegin,beforeEnd,afterEnd,adjacent - mutation helpers:
replace,remove,empty resolveTarget: coercion helper for append targets- return shapes:
before,after,prepend,append,adjacent,replace-> inserted element ornullbeforeBegin,afterBegin,beforeEnd,afterEnd-> inserted element ornullremove-> removed target element ornullempty-> target element (after child removal) ornullresolveTarget-> resolved element ornull
lib.dom.form semantics:
submit(triggerOrCollected, opts):- supports native form submit mode and request-envelope mode
- can accept either a DOM trigger element or pre-collected form payload
collect/collectForm:- extracts form payload into
{ url, method, parms, form, event }
- extracts form payload into
toJson:- converts collected payload to object form (inflated by default)
makeUrl,makeBody,makeHeader:- request-construction helpers used by submit flow
getDomKV,arrayToQS,arrayToHash:- lower-level form/value conversion helpers
lib.dom.transform semantics:
element(el, scheme, opts):- applies declarative
data-*bindings across an element subtree - supports map-driven transforms via
data-map-key
- applies declarative
list(target, template, data, opts):- clones template rows and applies
element(...)per row - supports append/replace list behavior via
opts.append
- clones template rows and applies
Primary usage:
lib._http.get("/ping", {
load: (req) => console.log(req.status),
error: (req) => console.error(req.status)
});Key function semantics:
get(url, opts):- async XHR request (default method
GET) - dispatches to
opts.loadoropts.erroron completion
- async XHR request (default method
request(url, opts):- extended form supporting headers/urlencoded/json parse mode
- when
opts.json === 1, parsed response is exposed asreq.jsonData
post(url, opts):- convenience wrapper setting method
POST
- convenience wrapper setting method
lib._boot usage:
resolveRoot(explicit):- root resolution order: explicit ->
globalThis->window->global
- root resolution order: explicit ->
install(opts):- writes normalized environment metadata to
lib._env - returns the installed
lib._envobject
- writes normalized environment metadata to
lib.args usage:
function f() {
return lib.args.parse(arguments, { enabled: true }, {
parms: "name count",
req: "name",
pop: 1
});
}parse(args, def, opts):- maps positional args to named keys
- optional trailing-object pop/merge behavior
- returns
undefinedwhen required keys are missing
slice(args, start, end):- converts/slices arguments-like input into real array
isArguments(item):- robust arguments-object check
lib.utils provides two categories:
- direct helpers (
isScalar,baseType,isEmpty,linkType,clamp,toNumber) - alias passthroughs to other namespaces (
isArray,toArray,toHash,toString, etc.)
Use lib.utils when you want a stable cross-module façade without importing individual helper namespaces directly.
Minimum runtime assumptions:
- ES module-capable JavaScript runtime
- root resolution capability via one of:
globalThis,window,global
Additional requirements by namespace:
- DOM operations (
lib.dom,lib.dom.create,lib.dom.append) require browser-like DOM APIs (document,Element, etc.) lib._httprequiresXMLHttpRequeston resolved runtime root
Public calls may throw in these cases:
init()lifecycle guard violations and bootstrap failureslib.require.all/lib.require.servicewhen required targets are missing anddiebehavior is enabled (default)lib._http.get/lib._http.requestwhenXMLHttpRequestis unavailable- DOM-API-dependent calls when required DOM globals are absent in the runtime
Most scalar/hash/array/boolean/string utility functions are designed to avoid throwing and instead normalize or return fallback values.
m7-js-lib does not guarantee:
- non-singleton instantiation support
- cross-bundle singleton unification when duplicate package copies are loaded
- stable internal/private implementation details
- behavior for undocumented options or unlisted internal helpers
Future versions may:
- add namespaces and functions
- add optional parameters to existing functions
- expand helper behavior where existing guarantees are preserved
Existing contract semantics defined above will not be weakened.
- Entrypoint contract -> ../entrypoints-contract.md
- API index -> ./INDEX.md
- Modules index -> ./modules/INDEX.md
- Function index -> ./functions/INDEX.md
Normalize early. Keep call sites linear. Preserve readability.