shell-dsl 0.0.34 → 0.0.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +41 -5
  2. package/dist/cjs/package.json +1 -1
  3. package/dist/cjs/src/fs/memfs-adapter.cjs +56 -2
  4. package/dist/cjs/src/fs/memfs-adapter.cjs.map +3 -3
  5. package/dist/cjs/src/fs/real-fs.cjs +134 -3
  6. package/dist/cjs/src/fs/real-fs.cjs.map +3 -3
  7. package/dist/cjs/src/fs/special-files.cjs +3 -2
  8. package/dist/cjs/src/fs/special-files.cjs.map +3 -3
  9. package/dist/cjs/src/fs/web-fs.cjs +72 -3
  10. package/dist/cjs/src/fs/web-fs.cjs.map +3 -3
  11. package/dist/cjs/src/index.cjs +2 -7
  12. package/dist/cjs/src/index.cjs.map +3 -3
  13. package/dist/cjs/src/interpreter/interpreter.cjs +186 -68
  14. package/dist/cjs/src/interpreter/interpreter.cjs.map +3 -3
  15. package/dist/cjs/src/parser/ast.cjs +5 -25
  16. package/dist/cjs/src/parser/ast.cjs.map +3 -3
  17. package/dist/cjs/src/parser/index.cjs +2 -7
  18. package/dist/cjs/src/parser/index.cjs.map +3 -3
  19. package/dist/cjs/src/parser/parser.cjs +132 -82
  20. package/dist/cjs/src/parser/parser.cjs.map +3 -3
  21. package/dist/cjs/src/types.cjs.map +2 -2
  22. package/dist/cjs/src/vcs/content.cjs +106 -0
  23. package/dist/cjs/src/vcs/content.cjs.map +10 -0
  24. package/dist/cjs/src/vcs/diff.cjs +72 -28
  25. package/dist/cjs/src/vcs/diff.cjs.map +3 -3
  26. package/dist/cjs/src/vcs/index.cjs.map +1 -1
  27. package/dist/cjs/src/vcs/objects.cjs +141 -0
  28. package/dist/cjs/src/vcs/objects.cjs.map +10 -0
  29. package/dist/cjs/src/vcs/rules.cjs +6 -3
  30. package/dist/cjs/src/vcs/rules.cjs.map +3 -3
  31. package/dist/cjs/src/vcs/snapshot.cjs +89 -39
  32. package/dist/cjs/src/vcs/snapshot.cjs.map +3 -3
  33. package/dist/cjs/src/vcs/storage.cjs +44 -3
  34. package/dist/cjs/src/vcs/storage.cjs.map +3 -3
  35. package/dist/cjs/src/vcs/text-diff.cjs +219 -0
  36. package/dist/cjs/src/vcs/text-diff.cjs.map +10 -0
  37. package/dist/cjs/src/vcs/vcs.cjs +108 -61
  38. package/dist/cjs/src/vcs/vcs.cjs.map +3 -3
  39. package/dist/mjs/package.json +1 -1
  40. package/dist/mjs/src/fs/memfs-adapter.mjs +57 -2
  41. package/dist/mjs/src/fs/memfs-adapter.mjs.map +3 -3
  42. package/dist/mjs/src/fs/real-fs.mjs +135 -3
  43. package/dist/mjs/src/fs/real-fs.mjs.map +3 -3
  44. package/dist/mjs/src/fs/special-files.mjs +3 -2
  45. package/dist/mjs/src/fs/special-files.mjs.map +3 -3
  46. package/dist/mjs/src/fs/web-fs.mjs +72 -3
  47. package/dist/mjs/src/fs/web-fs.mjs.map +3 -3
  48. package/dist/mjs/src/index.mjs +4 -14
  49. package/dist/mjs/src/index.mjs.map +3 -3
  50. package/dist/mjs/src/interpreter/interpreter.mjs +186 -68
  51. package/dist/mjs/src/interpreter/interpreter.mjs.map +3 -3
  52. package/dist/mjs/src/parser/ast.mjs +5 -25
  53. package/dist/mjs/src/parser/ast.mjs.map +3 -3
  54. package/dist/mjs/src/parser/index.mjs +4 -14
  55. package/dist/mjs/src/parser/index.mjs.map +3 -3
  56. package/dist/mjs/src/parser/parser.mjs +132 -82
  57. package/dist/mjs/src/parser/parser.mjs.map +3 -3
  58. package/dist/mjs/src/types.mjs.map +2 -2
  59. package/dist/mjs/src/vcs/content.mjs +66 -0
  60. package/dist/mjs/src/vcs/content.mjs.map +10 -0
  61. package/dist/mjs/src/vcs/diff.mjs +72 -28
  62. package/dist/mjs/src/vcs/diff.mjs.map +3 -3
  63. package/dist/mjs/src/vcs/index.mjs.map +1 -1
  64. package/dist/mjs/src/vcs/objects.mjs +106 -0
  65. package/dist/mjs/src/vcs/objects.mjs.map +10 -0
  66. package/dist/mjs/src/vcs/rules.mjs +6 -3
  67. package/dist/mjs/src/vcs/rules.mjs.map +3 -3
  68. package/dist/mjs/src/vcs/snapshot.mjs +89 -39
  69. package/dist/mjs/src/vcs/snapshot.mjs.map +3 -3
  70. package/dist/mjs/src/vcs/storage.mjs +45 -3
  71. package/dist/mjs/src/vcs/storage.mjs.map +3 -3
  72. package/dist/mjs/src/vcs/text-diff.mjs +179 -0
  73. package/dist/mjs/src/vcs/text-diff.mjs.map +10 -0
  74. package/dist/mjs/src/vcs/vcs.mjs +115 -63
  75. package/dist/mjs/src/vcs/vcs.mjs.map +3 -3
  76. package/dist/types/src/fs/real-fs.d.ts +12 -1
  77. package/dist/types/src/index.d.ts +4 -4
  78. package/dist/types/src/interpreter/interpreter.d.ts +15 -1
  79. package/dist/types/src/parser/ast.d.ts +34 -38
  80. package/dist/types/src/parser/index.d.ts +2 -2
  81. package/dist/types/src/parser/parser.d.ts +4 -1
  82. package/dist/types/src/types.d.ts +10 -0
  83. package/dist/types/src/vcs/content.d.ts +6 -0
  84. package/dist/types/src/vcs/diff.d.ts +10 -7
  85. package/dist/types/src/vcs/index.d.ts +1 -1
  86. package/dist/types/src/vcs/objects.d.ts +22 -0
  87. package/dist/types/src/vcs/snapshot.d.ts +13 -8
  88. package/dist/types/src/vcs/storage.d.ts +7 -1
  89. package/dist/types/src/vcs/text-diff.d.ts +1 -0
  90. package/dist/types/src/vcs/types.d.ts +20 -5
  91. package/dist/types/src/vcs/vcs.d.ts +6 -0
  92. package/package.json +7 -2
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/fs/web-fs.ts"],
4
4
  "sourcesContent": [
5
- "import { FileSystem, type PathOps, type PermissionRules, type UnderlyingFS } from \"./real-fs.cjs\";\n\nconst DIRECTORY_MTIME = new Date(0);\nconst WEB_PATH_OPS: PathOps = {\n separator: \"/\",\n resolve(...paths: string[]): string {\n return normalizeWebPath(paths.join(\"/\"));\n },\n normalize: normalizeWebPath,\n join(...paths: string[]): string {\n const nonEmpty = paths.filter((segment) => segment.length > 0);\n if (nonEmpty.length === 0) {\n return \".\";\n }\n return normalizeWebPath(nonEmpty.join(\"/\"));\n },\n relative(from: string, to: string): string {\n const fromSegments = getPathSegments(from);\n const toSegments = getPathSegments(to);\n let shared = 0;\n\n while (\n shared < fromSegments.length &&\n shared < toSegments.length &&\n fromSegments[shared] === toSegments[shared]\n ) {\n shared++;\n }\n\n const up = new Array(fromSegments.length - shared).fill(\"..\");\n const down = toSegments.slice(shared);\n return [...up, ...down].join(\"/\");\n },\n isAbsolute(path: string): boolean {\n return path.startsWith(\"/\");\n },\n dirname(path: string): string {\n const normalized = normalizeWebPath(path);\n if (normalized === \"/\") {\n return \"/\";\n }\n\n const segments = getPathSegments(normalized);\n if (segments.length <= 1) {\n return \"/\";\n }\n\n return `/${segments.slice(0, -1).join(\"/\")}`;\n },\n basename(path: string): string {\n const normalized = normalizeWebPath(path);\n if (normalized === \"/\") {\n return \"\";\n }\n\n const segments = getPathSegments(normalized);\n return segments[segments.length - 1] ?? \"\";\n },\n};\n\nexport function createWebUnderlyingFS(root: FileSystemDirectoryHandle): UnderlyingFS {\n return {\n pathOps: WEB_PATH_OPS,\n promises: {\n async readFile(path: string): Promise<Buffer> {\n const { parentSegments, name } = splitParent(path);\n const parent = await walkDirectory(root, parentSegments, false);\n const fileHandle = await parent.getFileHandle(name, { create: false });\n const file = await fileHandle.getFile();\n return Buffer.from(await file.arrayBuffer());\n },\n\n async readdir(path: string): Promise<string[]> {\n const dir = await walkDirectory(root, getPathSegments(path), false);\n const entries: string[] = [];\n for await (const [name] of dir.entries()) {\n entries.push(name);\n }\n return entries;\n },\n\n async stat(path: string): Promise<{\n isFile(): boolean;\n isDirectory(): boolean;\n size: number;\n mtime: Date;\n }> {\n const segments = getPathSegments(path);\n\n if (segments.length === 0) {\n return createDirectoryStat();\n }\n\n const { parentSegments, name } = splitParent(path);\n const parent = await walkDirectory(root, parentSegments, false);\n\n try {\n const fileHandle = await parent.getFileHandle(name, { create: false });\n const file = await fileHandle.getFile();\n return {\n isFile: () => true,\n isDirectory: () => false,\n size: file.size,\n mtime: new Date(file.lastModified ?? 0),\n };\n } catch (error) {\n if (!isNotFoundOrTypeMismatch(error)) throw error;\n }\n\n try {\n await parent.getDirectoryHandle(name, { create: false });\n return createDirectoryStat();\n } catch (error) {\n if (!isNotFoundOrTypeMismatch(error)) throw error;\n throw error;\n }\n },\n\n async writeFile(path: string, data: Buffer | string): Promise<void> {\n const { parentSegments, name } = splitParent(path);\n const parent = await walkDirectory(root, parentSegments, false);\n const fileHandle = await parent.getFileHandle(name, { create: true });\n const writable = await fileHandle.createWritable();\n await writable.write(toWritableData(data));\n await writable.close();\n },\n\n async appendFile(path: string, data: Buffer | string): Promise<void> {\n const { parentSegments, name } = splitParent(path);\n const parent = await walkDirectory(root, parentSegments, false);\n const fileHandle = await parent.getFileHandle(name, { create: true });\n const file = await fileHandle.getFile();\n const writable = await fileHandle.createWritable({ keepExistingData: true });\n await writable.write({\n type: \"write\",\n position: file.size,\n data: toWritableData(data),\n });\n await writable.close();\n },\n\n async mkdir(path: string, opts?: { recursive?: boolean }): Promise<void> {\n const segments = getPathSegments(path);\n if (segments.length === 0) {\n return;\n }\n\n if (opts?.recursive) {\n await walkDirectory(root, segments, true);\n return;\n }\n\n const parent = await walkDirectory(root, segments.slice(0, -1), false);\n const name = segments[segments.length - 1]!;\n const exists = await entryExists(parent, name);\n if (exists) {\n throw new Error(`EEXIST: file already exists, mkdir '${normalizeWebPath(path)}'`);\n }\n await parent.getDirectoryHandle(name, { create: true });\n },\n\n async rm(path: string, opts?: { recursive?: boolean; force?: boolean }): Promise<void> {\n const segments = getPathSegments(path);\n if (segments.length === 0) {\n throw new Error(\"EPERM: operation not permitted, rm '/'\");\n }\n\n const parent = await walkDirectory(root, segments.slice(0, -1), false);\n const name = segments[segments.length - 1]!;\n try {\n await parent.removeEntry(name, { recursive: opts?.recursive });\n } catch (error) {\n if (opts?.force && isNotFoundError(error)) {\n return;\n }\n throw error;\n }\n },\n },\n };\n}\n\nexport class WebFileSystem extends FileSystem {\n constructor(root: FileSystemDirectoryHandle, permissions?: PermissionRules) {\n super(\"/\", permissions, createWebUnderlyingFS(root));\n }\n}\n\nfunction createDirectoryStat() {\n return {\n isFile: () => false,\n isDirectory: () => true,\n size: 0,\n mtime: DIRECTORY_MTIME,\n };\n}\n\nfunction normalizeWebPath(path: string): string {\n const normalized = path.replace(/\\\\/g, \"/\");\n const rawSegments = (normalized.startsWith(\"/\") ? normalized : `/${normalized}`)\n .split(\"/\")\n .filter(Boolean);\n\n const segments: string[] = [];\n for (const segment of rawSegments) {\n if (segment === \".\") continue;\n if (segment === \"..\") {\n segments.pop();\n continue;\n }\n segments.push(segment);\n }\n\n return `/${segments.join(\"/\")}`;\n}\n\nfunction getPathSegments(path: string): string[] {\n const normalized = normalizeWebPath(path);\n return normalized.split(\"/\").filter(Boolean);\n}\n\nfunction splitParent(path: string): { parentSegments: string[]; name: string } {\n const segments = getPathSegments(path);\n if (segments.length === 0) {\n throw new Error(`Invalid file path: \"${path}\"`);\n }\n return {\n parentSegments: segments.slice(0, -1),\n name: segments[segments.length - 1]!,\n };\n}\n\nasync function walkDirectory(\n root: FileSystemDirectoryHandle,\n segments: string[],\n create: boolean\n): Promise<FileSystemDirectoryHandle> {\n let current = root;\n for (const segment of segments) {\n current = await current.getDirectoryHandle(segment, { create });\n }\n return current;\n}\n\nasync function entryExists(dir: FileSystemDirectoryHandle, name: string): Promise<boolean> {\n try {\n await dir.getFileHandle(name, { create: false });\n return true;\n } catch (error) {\n if (isTypeMismatchError(error)) return true;\n if (!isNotFoundError(error)) throw error;\n }\n\n try {\n await dir.getDirectoryHandle(name, { create: false });\n return true;\n } catch (error) {\n if (isTypeMismatchError(error)) return true;\n if (!isNotFoundError(error)) throw error;\n return false;\n }\n}\n\nfunction isNotFoundOrTypeMismatch(error: unknown): boolean {\n return isNotFoundError(error) || isTypeMismatchError(error);\n}\n\nfunction isNotFoundError(error: unknown): boolean {\n return getErrorName(error) === \"NotFoundError\";\n}\n\nfunction isTypeMismatchError(error: unknown): boolean {\n return getErrorName(error) === \"TypeMismatchError\";\n}\n\nfunction getErrorName(error: unknown): string | undefined {\n if (!error || typeof error !== \"object\") return undefined;\n const named = error as { name?: unknown };\n return typeof named.name === \"string\" ? named.name : undefined;\n}\n\nfunction toWritableData(data: Buffer | string): string | ArrayBuffer {\n if (typeof data === \"string\") {\n return data;\n }\n const out = new Uint8Array(data.length);\n out.set(data);\n return out.buffer;\n}\n"
5
+ "import type { VirtualFSWritable } from \"../types.cjs\";\nimport { FileSystem, type PathOps, type PermissionRules, type UnderlyingFS } from \"./real-fs.cjs\";\n\nconst DIRECTORY_MTIME = new Date(0);\nconst WEB_PATH_OPS: PathOps = {\n separator: \"/\",\n resolve(...paths: string[]): string {\n return normalizeWebPath(paths.join(\"/\"));\n },\n normalize: normalizeWebPath,\n join(...paths: string[]): string {\n const nonEmpty = paths.filter((segment) => segment.length > 0);\n if (nonEmpty.length === 0) {\n return \".\";\n }\n return normalizeWebPath(nonEmpty.join(\"/\"));\n },\n relative(from: string, to: string): string {\n const fromSegments = getPathSegments(from);\n const toSegments = getPathSegments(to);\n let shared = 0;\n\n while (\n shared < fromSegments.length &&\n shared < toSegments.length &&\n fromSegments[shared] === toSegments[shared]\n ) {\n shared++;\n }\n\n const up = new Array(fromSegments.length - shared).fill(\"..\");\n const down = toSegments.slice(shared);\n return [...up, ...down].join(\"/\");\n },\n isAbsolute(path: string): boolean {\n return path.startsWith(\"/\");\n },\n dirname(path: string): string {\n const normalized = normalizeWebPath(path);\n if (normalized === \"/\") {\n return \"/\";\n }\n\n const segments = getPathSegments(normalized);\n if (segments.length <= 1) {\n return \"/\";\n }\n\n return `/${segments.slice(0, -1).join(\"/\")}`;\n },\n basename(path: string): string {\n const normalized = normalizeWebPath(path);\n if (normalized === \"/\") {\n return \"\";\n }\n\n const segments = getPathSegments(normalized);\n return segments[segments.length - 1] ?? \"\";\n },\n};\n\nexport function createWebUnderlyingFS(root: FileSystemDirectoryHandle): UnderlyingFS {\n return {\n pathOps: WEB_PATH_OPS,\n promises: {\n async readFile(path: string): Promise<Buffer> {\n const { parentSegments, name } = splitParent(path);\n const parent = await walkDirectory(root, parentSegments, false);\n const fileHandle = await parent.getFileHandle(name, { create: false });\n const file = await fileHandle.getFile();\n return Buffer.from(await file.arrayBuffer());\n },\n\n async readdir(path: string): Promise<string[]> {\n const dir = await walkDirectory(root, getPathSegments(path), false);\n const entries: string[] = [];\n for await (const [name] of dir.entries()) {\n entries.push(name);\n }\n return entries;\n },\n\n async stat(path: string): Promise<{\n isFile(): boolean;\n isDirectory(): boolean;\n size: number;\n mtime: Date;\n mtimeMs: number;\n }> {\n const segments = getPathSegments(path);\n\n if (segments.length === 0) {\n return createDirectoryStat();\n }\n\n const { parentSegments, name } = splitParent(path);\n const parent = await walkDirectory(root, parentSegments, false);\n\n try {\n const fileHandle = await parent.getFileHandle(name, { create: false });\n const file = await fileHandle.getFile();\n return {\n isFile: () => true,\n isDirectory: () => false,\n size: file.size,\n mtime: new Date(file.lastModified ?? 0),\n mtimeMs: file.lastModified ?? 0,\n };\n } catch (error) {\n if (!isNotFoundOrTypeMismatch(error)) throw error;\n }\n\n try {\n await parent.getDirectoryHandle(name, { create: false });\n return createDirectoryStat();\n } catch (error) {\n if (!isNotFoundOrTypeMismatch(error)) throw error;\n throw error;\n }\n },\n\n async writeFile(path: string, data: Buffer | string): Promise<void> {\n const { parentSegments, name } = splitParent(path);\n const parent = await walkDirectory(root, parentSegments, false);\n const fileHandle = await parent.getFileHandle(name, { create: true });\n const writable = await fileHandle.createWritable();\n await writable.write(toWritableData(data));\n await writable.close();\n },\n\n async appendFile(path: string, data: Buffer | string): Promise<void> {\n const { parentSegments, name } = splitParent(path);\n const parent = await walkDirectory(root, parentSegments, false);\n const fileHandle = await parent.getFileHandle(name, { create: true });\n const file = await fileHandle.getFile();\n const writable = await fileHandle.createWritable({ keepExistingData: true });\n await writable.write({\n type: \"write\",\n position: file.size,\n data: toWritableData(data),\n });\n await writable.close();\n },\n\n async mkdir(path: string, opts?: { recursive?: boolean }): Promise<void> {\n const segments = getPathSegments(path);\n if (segments.length === 0) {\n return;\n }\n\n if (opts?.recursive) {\n await walkDirectory(root, segments, true);\n return;\n }\n\n const parent = await walkDirectory(root, segments.slice(0, -1), false);\n const name = segments[segments.length - 1]!;\n const exists = await entryExists(parent, name);\n if (exists) {\n throw new Error(`EEXIST: file already exists, mkdir '${normalizeWebPath(path)}'`);\n }\n await parent.getDirectoryHandle(name, { create: true });\n },\n\n async rm(path: string, opts?: { recursive?: boolean; force?: boolean }): Promise<void> {\n const segments = getPathSegments(path);\n if (segments.length === 0) {\n throw new Error(\"EPERM: operation not permitted, rm '/'\");\n }\n\n const parent = await walkDirectory(root, segments.slice(0, -1), false);\n const name = segments[segments.length - 1]!;\n try {\n await parent.removeEntry(name, { recursive: opts?.recursive });\n } catch (error) {\n if (opts?.force && isNotFoundError(error)) {\n return;\n }\n throw error;\n }\n },\n },\n streams: {\n createReadStream(path: string): AsyncIterable<Uint8Array> {\n return {\n async *[Symbol.asyncIterator]() {\n const { parentSegments, name } = splitParent(path);\n const parent = await walkDirectory(root, parentSegments, false);\n const fileHandle = await parent.getFileHandle(name, { create: false });\n const file = await fileHandle.getFile();\n for await (const chunk of streamToAsyncIterable(file.stream())) {\n yield chunk;\n }\n },\n };\n },\n async createWriteStream(path: string, opts?: { append?: boolean }): Promise<VirtualFSWritable> {\n const { parentSegments, name } = splitParent(path);\n const parent = await walkDirectory(root, parentSegments, false);\n const fileHandle = await parent.getFileHandle(name, { create: true });\n const existingFile = opts?.append ? await fileHandle.getFile() : null;\n const writable = await fileHandle.createWritable({ keepExistingData: !!opts?.append });\n let position = opts?.append ? existingFile?.size ?? 0 : 0;\n let closed = false;\n\n return {\n async write(chunk: Uint8Array): Promise<void> {\n if (closed) {\n throw new Error(\"stream is closed\");\n }\n const bytes = new Uint8Array(chunk.byteLength);\n bytes.set(chunk, 0);\n await writable.write({\n type: \"write\",\n position,\n data: bytes,\n });\n position += bytes.byteLength;\n },\n async close(): Promise<void> {\n if (closed) return;\n closed = true;\n await writable.close();\n },\n async abort(_reason?: unknown): Promise<void> {\n if (closed) return;\n closed = true;\n await writable.abort?.();\n },\n };\n },\n },\n };\n}\n\nexport class WebFileSystem extends FileSystem {\n constructor(root: FileSystemDirectoryHandle, permissions?: PermissionRules) {\n super(\"/\", permissions, createWebUnderlyingFS(root));\n }\n}\n\nfunction createDirectoryStat() {\n return {\n isFile: () => false,\n isDirectory: () => true,\n size: 0,\n mtime: DIRECTORY_MTIME,\n mtimeMs: DIRECTORY_MTIME.getTime(),\n };\n}\n\nfunction normalizeWebPath(path: string): string {\n const normalized = path.replace(/\\\\/g, \"/\");\n const rawSegments = (normalized.startsWith(\"/\") ? normalized : `/${normalized}`)\n .split(\"/\")\n .filter(Boolean);\n\n const segments: string[] = [];\n for (const segment of rawSegments) {\n if (segment === \".\") continue;\n if (segment === \"..\") {\n segments.pop();\n continue;\n }\n segments.push(segment);\n }\n\n return `/${segments.join(\"/\")}`;\n}\n\nfunction getPathSegments(path: string): string[] {\n const normalized = normalizeWebPath(path);\n return normalized.split(\"/\").filter(Boolean);\n}\n\nfunction splitParent(path: string): { parentSegments: string[]; name: string } {\n const segments = getPathSegments(path);\n if (segments.length === 0) {\n throw new Error(`Invalid file path: \"${path}\"`);\n }\n return {\n parentSegments: segments.slice(0, -1),\n name: segments[segments.length - 1]!,\n };\n}\n\nasync function walkDirectory(\n root: FileSystemDirectoryHandle,\n segments: string[],\n create: boolean\n): Promise<FileSystemDirectoryHandle> {\n let current = root;\n for (const segment of segments) {\n current = await current.getDirectoryHandle(segment, { create });\n }\n return current;\n}\n\nasync function entryExists(dir: FileSystemDirectoryHandle, name: string): Promise<boolean> {\n try {\n await dir.getFileHandle(name, { create: false });\n return true;\n } catch (error) {\n if (isTypeMismatchError(error)) return true;\n if (!isNotFoundError(error)) throw error;\n }\n\n try {\n await dir.getDirectoryHandle(name, { create: false });\n return true;\n } catch (error) {\n if (isTypeMismatchError(error)) return true;\n if (!isNotFoundError(error)) throw error;\n return false;\n }\n}\n\nasync function* streamToAsyncIterable(\n stream: ReadableStream<Uint8Array>,\n): AsyncIterable<Uint8Array> {\n const reader = stream.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n return;\n }\n if (value) {\n yield value;\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction isNotFoundOrTypeMismatch(error: unknown): boolean {\n return isNotFoundError(error) || isTypeMismatchError(error);\n}\n\nfunction isNotFoundError(error: unknown): boolean {\n return getErrorName(error) === \"NotFoundError\";\n}\n\nfunction isTypeMismatchError(error: unknown): boolean {\n return getErrorName(error) === \"TypeMismatchError\";\n}\n\nfunction getErrorName(error: unknown): string | undefined {\n if (!error || typeof error !== \"object\") return undefined;\n const named = error as { name?: unknown };\n return typeof named.name === \"string\" ? named.name : undefined;\n}\n\nfunction toWritableData(data: Buffer | string): string | ArrayBuffer {\n if (typeof data === \"string\") {\n return data;\n }\n const out = new Uint8Array(data.length);\n out.set(data);\n return out.buffer;\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "63C0A71C805BC57D64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "87CE1021E696ED8364756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -42,22 +42,17 @@ __export(exports_src, {
42
42
  tokenToString: () => import_lexer.tokenToString,
43
43
  parse: () => import_parser.parse,
44
44
  lex: () => import_lexer.lex,
45
+ isWordNode: () => import_parser2.isWordNode,
45
46
  isWhileNode: () => import_parser2.isWhileNode,
46
- isVariableNode: () => import_parser2.isVariableNode,
47
47
  isUntilNode: () => import_parser2.isUntilNode,
48
- isSubstitutionNode: () => import_parser2.isSubstitutionNode,
49
48
  isSequenceNode: () => import_parser2.isSequenceNode,
50
49
  isRawValue: () => import_types.isRawValue,
51
50
  isPipelineNode: () => import_parser2.isPipelineNode,
52
51
  isOrNode: () => import_parser2.isOrNode,
53
- isLiteralNode: () => import_parser2.isLiteralNode,
54
52
  isIfNode: () => import_parser2.isIfNode,
55
- isGlobNode: () => import_parser2.isGlobNode,
56
53
  isForNode: () => import_parser2.isForNode,
57
- isConcatNode: () => import_parser2.isConcatNode,
58
54
  isCommandNode: () => import_parser2.isCommandNode,
59
55
  isCaseNode: () => import_parser2.isCaseNode,
60
- isArithmeticNode: () => import_parser2.isArithmeticNode,
61
56
  isAndNode: () => import_parser2.isAndNode,
62
57
  globVirtualFS: () => import_utils.globVirtualFS,
63
58
  escapeForInterpolation: () => import_utils.escapeForInterpolation,
@@ -103,4 +98,4 @@ var import_io2 = require("./io/index.cjs");
103
98
  var import_utils = require("./utils/index.cjs");
104
99
  var import_vcs = require("./vcs/index.cjs");
105
100
 
106
- //# debugId=27F0973A44539CA064756E2164756E21
101
+ //# debugId=188D4F3252D1BB8C64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "// Main class exports\nexport { ShellDSL, createShellDSL, type Program } from \"./shell-dsl.cjs\";\nexport { ShellPromise, type ShellPromiseOptions } from \"./shell-promise.cjs\";\n\n// Types\nexport type {\n VirtualFS,\n FileStat,\n Command,\n CommandContext,\n Stdin,\n Stdout,\n Stderr,\n OutputCollector,\n ExecResult,\n ShellConfig,\n RawValue,\n} from \"./types.cjs\";\nexport { isRawValue } from \"./types.cjs\";\n\n// Errors\nexport { ShellError, LexError, ParseError } from \"./errors.cjs\";\n\n// Lexer\nexport { Lexer, lex, tokenToString } from \"./lexer/index.cjs\";\nexport type { Token, RedirectMode } from \"./lexer/index.cjs\";\n\n// Parser\nexport { Parser, parse } from \"./parser/index.cjs\";\nexport type {\n ASTNode,\n Redirect,\n CommandNode,\n PipelineNode,\n AndNode,\n OrNode,\n SequenceNode,\n LiteralNode,\n VariableNode,\n SubstitutionNode,\n GlobNode,\n ConcatNode,\n IfNode,\n ForNode,\n WhileNode,\n UntilNode,\n CaseNode,\n CaseClause,\n ArithmeticNode,\n} from \"./parser/index.cjs\";\nexport {\n isCommandNode,\n isPipelineNode,\n isAndNode,\n isOrNode,\n isSequenceNode,\n isLiteralNode,\n isVariableNode,\n isSubstitutionNode,\n isGlobNode,\n isConcatNode,\n isIfNode,\n isForNode,\n isWhileNode,\n isUntilNode,\n isCaseNode,\n isArithmeticNode,\n} from \"./parser/index.cjs\";\n\n// Interpreter\nexport { Interpreter, type InterpreterOptions, BreakException, ContinueException } from \"./interpreter/index.cjs\";\n\n// Filesystem\nexport { createVirtualFS } from \"./fs/index.cjs\";\nexport {\n FileSystem,\n ReadOnlyFileSystem,\n WebFileSystem,\n createWebUnderlyingFS,\n type PathOps,\n type Permission,\n type PermissionRules,\n type UnderlyingFS,\n} from \"./fs/index.cjs\";\n\n// I/O\nexport { createStdin, StdinImpl } from \"./io/index.cjs\";\nexport { createStdout, createStderr, createPipe, OutputCollectorImpl, PipeBuffer } from \"./io/index.cjs\";\n\n// Utilities\nexport { escape, escapeForInterpolation, globVirtualFS } from \"./utils/index.cjs\";\nexport type { GlobVirtualFS, GlobOptions } from \"./utils/index.cjs\";\n\n// Version Control\nexport { VersionControlSystem } from \"./vcs/index.cjs\";\nexport type {\n VCSConfig,\n VCSAttributeRule,\n VCSResolvedAttributes,\n VCSDiffMode,\n Revision,\n DiffEntry,\n TreeManifest,\n TreeEntry,\n FileEntry,\n DirectoryEntry,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n} from \"./vcs/index.cjs\";\n"
5
+ "// Main class exports\nexport { ShellDSL, createShellDSL, type Program } from \"./shell-dsl.cjs\";\nexport { ShellPromise, type ShellPromiseOptions } from \"./shell-promise.cjs\";\n\n// Types\nexport type {\n VirtualFS,\n VirtualFSWritable,\n FileStat,\n Command,\n CommandContext,\n Stdin,\n Stdout,\n Stderr,\n OutputCollector,\n ExecResult,\n ShellConfig,\n RawValue,\n} from \"./types.cjs\";\nexport { isRawValue } from \"./types.cjs\";\n\n// Errors\nexport { ShellError, LexError, ParseError } from \"./errors.cjs\";\n\n// Lexer\nexport { Lexer, lex, tokenToString } from \"./lexer/index.cjs\";\nexport type { Token, RedirectMode } from \"./lexer/index.cjs\";\n\n// Parser\nexport { Parser, parse } from \"./parser/index.cjs\";\nexport type {\n ASTNode,\n Redirect,\n CommandNode,\n PipelineNode,\n AndNode,\n OrNode,\n SequenceNode,\n WordNode,\n WordPart,\n TextPart,\n VariablePart,\n SubstitutionPart,\n ArithmeticPart,\n IfNode,\n ForNode,\n WhileNode,\n UntilNode,\n CaseNode,\n CaseClause,\n} from \"./parser/index.cjs\";\nexport {\n isWordNode,\n isCommandNode,\n isPipelineNode,\n isAndNode,\n isOrNode,\n isSequenceNode,\n isIfNode,\n isForNode,\n isWhileNode,\n isUntilNode,\n isCaseNode,\n} from \"./parser/index.cjs\";\n\n// Interpreter\nexport { Interpreter, type InterpreterOptions, BreakException, ContinueException } from \"./interpreter/index.cjs\";\n\n// Filesystem\nexport { createVirtualFS } from \"./fs/index.cjs\";\nexport {\n FileSystem,\n ReadOnlyFileSystem,\n WebFileSystem,\n createWebUnderlyingFS,\n type PathOps,\n type Permission,\n type PermissionRules,\n type UnderlyingFS,\n} from \"./fs/index.cjs\";\n\n// I/O\nexport { createStdin, StdinImpl } from \"./io/index.cjs\";\nexport { createStdout, createStderr, createPipe, OutputCollectorImpl, PipeBuffer } from \"./io/index.cjs\";\n\n// Utilities\nexport { escape, escapeForInterpolation, globVirtualFS } from \"./utils/index.cjs\";\nexport type { GlobVirtualFS, GlobOptions } from \"./utils/index.cjs\";\n\n// Version Control\nexport { VersionControlSystem } from \"./vcs/index.cjs\";\nexport type {\n VCSConfig,\n VCSAttributeRule,\n VCSResolvedAttributes,\n VCSDiffMode,\n VCSPatchSuppressionReason,\n Revision,\n DiffEntry,\n TreeManifest,\n TreeEntry,\n FileEntry,\n DirectoryEntry,\n VCSIndexEntry,\n VCSIndexFile,\n CommitOptions,\n CheckoutOptions,\n LogOptions,\n LogEntry,\n BranchInfo,\n} from \"./vcs/index.cjs\";\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACuD,IAAvD;AACuD,IAAvD;AAgB2B,IAA3B;AAGiD,IAAjD;AAG0C,IAA1C;AAI8B,IAA9B;AAuCO,IAjBP;AAoBwF,IAAxF;AAGgC,IAAhC;AAUO,IATP;AAYuC,IAAvC;AACwF,IAAxF;AAG8D,IAA9D;AAIqC,IAArC;",
8
- "debugId": "27F0973A44539CA064756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACuD,IAAvD;AACuD,IAAvD;AAiB2B,IAA3B;AAGiD,IAAjD;AAG0C,IAA1C;AAI8B,IAA9B;AAkCO,IAZP;AAewF,IAAxF;AAGgC,IAAhC;AAUO,IATP;AAYuC,IAAvC;AACwF,IAAxF;AAG8D,IAA9D;AAIqC,IAArC;",
8
+ "debugId": "188D4F3252D1BB8C64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -48,6 +48,9 @@ var import_context = require("./context.cjs");
48
48
  var import_stdin = require("../io/stdin.cjs");
49
49
  var import_stdout = require("../io/stdout.cjs");
50
50
  var import_special_files = require("../fs/special-files.cjs");
51
+ var DEFAULT_IFS = `
52
+ `;
53
+ var GLOB_META_CHARS = /[*?[{]/;
51
54
 
52
55
  class BreakException extends Error {
53
56
  levels;
@@ -119,34 +122,23 @@ class Interpreter {
119
122
  case "case":
120
123
  return this.executeCase(node, stdinSource, stdout, stderr);
121
124
  default:
122
- throw new Error(`Cannot execute node type: ${node.type}`);
125
+ throw new Error("Cannot execute unknown node type");
123
126
  }
124
127
  }
125
128
  async executeCommand(node, stdinSource, stdout, stderr) {
126
- const localEnv = { ...this.env };
129
+ const assignmentEnv = { ...this.env };
127
130
  for (const assignment of node.assignments) {
128
- localEnv[assignment.name] = await this.evaluateNode(assignment.value);
129
- }
130
- const name = await this.evaluateNode(node.name);
131
- if (name === "" && node.assignments.length > 0) {
132
- for (const assignment of node.assignments) {
133
- this.env[assignment.name] = await this.evaluateNode(assignment.value);
134
- }
135
- return 0;
136
- }
137
- const args = [];
138
- for (const arg of node.args) {
139
- const evaluated = await this.evaluateNode(arg, localEnv);
140
- if (arg.type === "glob") {
141
- const matches = await this.fs.glob(evaluated, { cwd: this.cwd });
142
- if (matches.length > 0) {
143
- args.push(...matches);
144
- } else {
145
- args.push(evaluated);
131
+ assignmentEnv[assignment.name] = await this.expandWordScalar(assignment.value, assignmentEnv);
132
+ }
133
+ const expandedWords = await this.expandCommandWords(node, this.env);
134
+ const [name, ...args] = expandedWords;
135
+ if (name === undefined || name === "") {
136
+ if (node.assignments.length > 0) {
137
+ for (const assignment of node.assignments) {
138
+ this.env[assignment.name] = assignmentEnv[assignment.name] ?? "";
146
139
  }
147
- } else {
148
- args.push(evaluated);
149
140
  }
141
+ return 0;
150
142
  }
151
143
  let actualStdin = stdinSource;
152
144
  let actualStdout = stdout;
@@ -156,7 +148,7 @@ class Interpreter {
156
148
  const fileWritePromises = [];
157
149
  for (const redirect of node.redirects) {
158
150
  try {
159
- const result = await this.handleRedirect(redirect, actualStdin, actualStdout, actualStderr);
151
+ const result = await this.handleRedirect(redirect, actualStdin, actualStdout, actualStderr, this.env);
160
152
  actualStdin = result.stdin;
161
153
  actualStdout = result.stdout;
162
154
  actualStderr = result.stderr;
@@ -166,7 +158,7 @@ class Interpreter {
166
158
  fileWritePromises.push(result.fileWritePromise);
167
159
  }
168
160
  } catch (err) {
169
- const target = await this.evaluateNode(redirect.target);
161
+ const target = await this.expandWordScalar(redirect.target, this.env);
170
162
  const message = err instanceof Error ? err.message : String(err);
171
163
  await stderr.writeText(`sh: ${target}: ${message}
172
164
  `);
@@ -204,7 +196,7 @@ class Interpreter {
204
196
  stderr: subStderr,
205
197
  fs: this.fs,
206
198
  cwd: this.cwd,
207
- env: { ...localEnv },
199
+ env: { ...assignmentEnv },
208
200
  setCwd: (path) => this.setCwd(path),
209
201
  exec
210
202
  });
@@ -235,7 +227,7 @@ class Interpreter {
235
227
  stderr: actualStderr,
236
228
  fs: this.fs,
237
229
  cwd: this.cwd,
238
- env: localEnv,
230
+ env: assignmentEnv,
239
231
  setCwd: (path) => this.setCwd(path),
240
232
  exec
241
233
  });
@@ -262,15 +254,15 @@ class Interpreter {
262
254
  } catch (err) {
263
255
  const message = err instanceof Error ? err.message : String(err);
264
256
  const writeRedirects = node.redirects.filter((r) => r.mode !== "<" && r.mode !== "2>&1" && r.mode !== "1>&2");
265
- const target = writeRedirects.length > 0 ? await this.evaluateNode(writeRedirects[writeRedirects.length - 1].target) : "unknown";
257
+ const target = writeRedirects.length > 0 ? await this.expandWordScalar(writeRedirects[writeRedirects.length - 1].target, this.env) : "unknown";
266
258
  await stderr.writeText(`sh: ${target}: ${message}
267
259
  `);
268
260
  exitCode = 1;
269
261
  }
270
262
  return exitCode;
271
263
  }
272
- async handleRedirect(redirect, stdin, stdout, stderr) {
273
- const target = await this.evaluateNode(redirect.target);
264
+ async handleRedirect(redirect, stdin, stdout, stderr, env) {
265
+ const target = await this.expandWordScalar(redirect.target, env);
274
266
  if (target in this.redirectObjects) {
275
267
  return this.handleObjectRedirect(redirect.mode, this.redirectObjects[target], stdin, stdout, stderr);
276
268
  }
@@ -502,17 +494,7 @@ class Interpreter {
502
494
  async executeFor(node, stdinSource, stdout, stderr) {
503
495
  const expandedItems = [];
504
496
  for (const item of node.items) {
505
- const evaluated = await this.evaluateNode(item);
506
- if (item.type === "glob") {
507
- const matches = await this.fs.glob(evaluated, { cwd: this.cwd });
508
- if (matches.length > 0) {
509
- expandedItems.push(...matches);
510
- } else {
511
- expandedItems.push(evaluated);
512
- }
513
- } else {
514
- expandedItems.push(evaluated);
515
- }
497
+ expandedItems.push(...await this.expandWordForCommand(item, this.env));
516
498
  }
517
499
  if (expandedItems.length === 0) {
518
500
  return 0;
@@ -616,10 +598,10 @@ class Interpreter {
616
598
  return lastExitCode;
617
599
  }
618
600
  async executeCase(node, stdinSource, stdout, stderr) {
619
- const word = await this.evaluateNode(node.word);
601
+ const word = await this.expandWordScalar(node.word, this.env);
620
602
  for (const clause of node.clauses) {
621
603
  for (const patternNode of clause.patterns) {
622
- const pattern = await this.evaluateNode(patternNode);
604
+ const pattern = await this.expandWordScalar(patternNode, this.env);
623
605
  if (this.matchCasePattern(word, pattern)) {
624
606
  return this.executeNode(clause.body, stdinSource, stdout, stderr);
625
607
  }
@@ -660,34 +642,170 @@ class Interpreter {
660
642
  return word === pattern;
661
643
  }
662
644
  }
663
- async evaluateNode(node, localEnv) {
664
- const env = localEnv ?? this.env;
665
- switch (node.type) {
666
- case "literal":
667
- return node.value;
645
+ async expandCommandWords(node, env) {
646
+ const expanded = [];
647
+ for (const word of [node.name, ...node.args]) {
648
+ expanded.push(...await this.expandWordForCommand(word, env));
649
+ }
650
+ return expanded;
651
+ }
652
+ async expandWordForCommand(word, env) {
653
+ const fields = await this.expandWordFields(word, env);
654
+ const expanded = [];
655
+ for (const field of fields) {
656
+ expanded.push(...await this.expandPathname(field));
657
+ }
658
+ return expanded;
659
+ }
660
+ async expandWordScalar(word, env) {
661
+ let result = "";
662
+ for (const part of word.parts) {
663
+ result += await this.expandWordPart(part, env);
664
+ }
665
+ return result;
666
+ }
667
+ async expandWordFields(word, env) {
668
+ const fields = [this.createExpandedField()];
669
+ const ifs = this.getIFS(env);
670
+ for (const part of word.parts) {
671
+ if (part.type === "text") {
672
+ this.appendSegment(fields[fields.length - 1], part.value, part.quoted);
673
+ continue;
674
+ }
675
+ const value = await this.expandWordPart(part, env);
676
+ if (part.quoted) {
677
+ this.appendSegment(fields[fields.length - 1], value, true);
678
+ continue;
679
+ }
680
+ const splitFields = this.splitUnquotedExpansion(value, ifs);
681
+ if (splitFields.length === 0) {
682
+ continue;
683
+ }
684
+ this.appendSegment(fields[fields.length - 1], splitFields[0], false);
685
+ for (let i = 1;i < splitFields.length; i++) {
686
+ const field = this.createExpandedField();
687
+ this.appendSegment(field, splitFields[i], false);
688
+ fields.push(field);
689
+ }
690
+ }
691
+ return fields.filter((field) => field.segments.length > 0);
692
+ }
693
+ async expandWordPart(part, env) {
694
+ switch (part.type) {
695
+ case "text":
696
+ return part.value;
668
697
  case "variable":
669
- return env[node.name] ?? "";
670
- case "glob":
671
- return node.pattern;
672
- case "concat": {
673
- const parts = await Promise.all(node.parts.map((p) => this.evaluateNode(p, localEnv)));
674
- return parts.join("");
675
- }
676
- case "substitution": {
677
- const subStdout = import_stdout.createStdout();
678
- const subStderr = import_stdout.createStderr();
679
- await this.executeNode(node.command, null, subStdout, subStderr);
680
- subStdout.close();
681
- const output = await subStdout.collect();
682
- return output.toString("utf-8").replace(/\n+$/, "");
683
- }
684
- case "arithmetic": {
685
- const result = this.evaluateArithmetic(node.expression, env);
686
- return String(result);
687
- }
698
+ return env[part.name] ?? "";
699
+ case "substitution":
700
+ return this.executeSubstitution(part.command, env);
701
+ case "arithmetic":
702
+ return String(this.evaluateArithmetic(part.expression, env));
688
703
  default:
689
- throw new Error(`Cannot evaluate node type: ${node.type}`);
704
+ throw new Error("Cannot expand unknown word part");
705
+ }
706
+ }
707
+ async executeSubstitution(command, env) {
708
+ const interpreter = new Interpreter({
709
+ fs: this.fs,
710
+ cwd: this.cwd,
711
+ env,
712
+ commands: this.commands,
713
+ redirectObjects: this.redirectObjects,
714
+ isTTY: false
715
+ });
716
+ const result = await interpreter.execute(command);
717
+ return result.stdout.toString("utf-8").replace(/\n+$/, "");
718
+ }
719
+ getIFS(env) {
720
+ return env.IFS ?? DEFAULT_IFS;
721
+ }
722
+ splitUnquotedExpansion(value, ifs) {
723
+ if (value.length === 0) {
724
+ return [];
725
+ }
726
+ if (ifs === "") {
727
+ return [value];
690
728
  }
729
+ const ifsChars = new Set(ifs);
730
+ const isIfsWhitespace = (char) => ifsChars.has(char) && (char === " " || char === "\t" || char === `
731
+ `);
732
+ const isIfsNonWhitespace = (char) => ifsChars.has(char) && !isIfsWhitespace(char);
733
+ const fields = [];
734
+ let i = 0;
735
+ while (i < value.length && isIfsWhitespace(value[i])) {
736
+ i++;
737
+ }
738
+ let fieldStart = i;
739
+ let lastDelimiterWasNonWhitespace = false;
740
+ while (i < value.length) {
741
+ const char = value[i];
742
+ if (isIfsNonWhitespace(char)) {
743
+ fields.push(value.slice(fieldStart, i));
744
+ i++;
745
+ while (i < value.length && isIfsWhitespace(value[i])) {
746
+ i++;
747
+ }
748
+ fieldStart = i;
749
+ lastDelimiterWasNonWhitespace = true;
750
+ continue;
751
+ }
752
+ if (isIfsWhitespace(char)) {
753
+ fields.push(value.slice(fieldStart, i));
754
+ while (i < value.length && isIfsWhitespace(value[i])) {
755
+ i++;
756
+ }
757
+ if (i < value.length && isIfsNonWhitespace(value[i])) {
758
+ i++;
759
+ while (i < value.length && isIfsWhitespace(value[i])) {
760
+ i++;
761
+ }
762
+ lastDelimiterWasNonWhitespace = true;
763
+ } else {
764
+ lastDelimiterWasNonWhitespace = false;
765
+ }
766
+ fieldStart = i;
767
+ continue;
768
+ }
769
+ lastDelimiterWasNonWhitespace = false;
770
+ i++;
771
+ }
772
+ if (fieldStart < value.length) {
773
+ fields.push(value.slice(fieldStart));
774
+ } else if (lastDelimiterWasNonWhitespace) {
775
+ fields.push("");
776
+ }
777
+ return fields;
778
+ }
779
+ createExpandedField() {
780
+ return { segments: [] };
781
+ }
782
+ appendSegment(field, value, quoted) {
783
+ const lastSegment = field.segments[field.segments.length - 1];
784
+ if (lastSegment && lastSegment.quoted === quoted) {
785
+ lastSegment.value += value;
786
+ return;
787
+ }
788
+ field.segments.push({ value, quoted });
789
+ }
790
+ async expandPathname(field) {
791
+ if (!this.hasUnquotedGlobMeta(field)) {
792
+ return [this.fieldToString(field)];
793
+ }
794
+ const pattern = this.fieldToGlobPattern(field);
795
+ const matches = await this.fs.glob(pattern, { cwd: this.cwd });
796
+ return matches.length > 0 ? matches : [this.fieldToString(field)];
797
+ }
798
+ hasUnquotedGlobMeta(field) {
799
+ return field.segments.some((segment) => !segment.quoted && GLOB_META_CHARS.test(segment.value));
800
+ }
801
+ fieldToString(field) {
802
+ return field.segments.map((segment) => segment.value).join("");
803
+ }
804
+ fieldToGlobPattern(field) {
805
+ return field.segments.map((segment) => segment.quoted ? this.escapeLiteralGlobChars(segment.value) : segment.value).join("");
806
+ }
807
+ escapeLiteralGlobChars(value) {
808
+ return value.replaceAll("[", "[[]").replaceAll("]", "[]]").replaceAll("*", "[*]").replaceAll("?", "[?]").replaceAll("{", "[{]").replaceAll("}", "[}]");
691
809
  }
692
810
  evaluateArithmetic(expression, env) {
693
811
  let expandedExpr = expression;
@@ -867,4 +985,4 @@ class Interpreter {
867
985
  }
868
986
  }
869
987
 
870
- //# debugId=9752A1F1CEADD56864756E2164756E21
988
+ //# debugId=1238E19B5ED5404064756E2164756E21