@hellpig/anarchy-legal 1.12.4 → 1.12.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"LegalDocumentType.js","sources":["../../src/Constants/LegalDocumentType.ts"],"sourcesContent":["import type { TLegalDocumentType } from '@Anarchy/Legal/Models';\n\nexport const LegalDocumentType: Readonly<Record<TLegalDocumentType, TLegalDocumentType>> = {\n DISCLAIMER: 'DISCLAIMER',\n EULA: 'EULA',\n EU_DECLARATION_OF_CONFORMITY: 'EU_DECLARATION_OF_CONFORMITY',\n INSTRUCTIONS: 'INSTRUCTIONS',\n PRIVACY: 'PRIVACY',\n SECURITY: 'SECURITY',\n SUPPORT: 'SUPPORT',\n TECHNICAL_DOCUMENTATION: 'TECHNICAL_DOCUMENTATION',\n VULN_HANDLING: 'VULN_HANDLING'\n};\n"],"names":[],"mappings":"AAEO,MAAM,oBAA8E;AAAA,EACzF,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,8BAA8B;AAAA,EAC9B,cAAc;AAAA,EACd,SAAS;AAAA,EACT,UAAU;AAAA,EACV,SAAS;AAAA,EACT,yBAAyB;AAAA,EACzB,eAAe;AACjB;"}
1
+ {"version":3,"file":"LegalDocumentType.js","sources":["../../src/Constants/LegalDocumentType.ts"],"sourcesContent":["import type { TLegalDocumentType } from '@hellpig/anarchy-legal/Models';\n\nexport const LegalDocumentType: Readonly<Record<TLegalDocumentType, TLegalDocumentType>> = {\n DISCLAIMER: 'DISCLAIMER',\n EULA: 'EULA',\n EU_DECLARATION_OF_CONFORMITY: 'EU_DECLARATION_OF_CONFORMITY',\n INSTRUCTIONS: 'INSTRUCTIONS',\n PRIVACY: 'PRIVACY',\n SECURITY: 'SECURITY',\n SUPPORT: 'SUPPORT',\n TECHNICAL_DOCUMENTATION: 'TECHNICAL_DOCUMENTATION',\n VULN_HANDLING: 'VULN_HANDLING'\n};\n"],"names":[],"mappings":"AAEO,MAAM,oBAA8E;AAAA,EACzF,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,8BAA8B;AAAA,EAC9B,cAAc;AAAA,EACd,SAAS;AAAA,EACT,UAAU;AAAA,EACV,SAAS;AAAA,EACT,yBAAyB;AAAA,EACzB,eAAe;AACjB;"}
@@ -1 +1 @@
1
- {"version":3,"file":"LegalFilesService.js","sources":["../../src/Services/LegalFilesService.ts"],"sourcesContent":["import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { TAnarchyLegalConfig, TLegalDocumentType, TLegalFilesService, TLegalFilesUtilsService, TRepoUtilsService, TTemplateGeneratorOptions, TWorkspaceInfo } from '@Anarchy/Legal'; // eslint-disable-next-line spellcheck/spell-checker\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\n\nimport { LegalDocumentType } from '../Constants/LegalDocumentType.ts';\nimport { LegalFilesUtilsService } from './LegalFilesUtilsService.ts';\nimport { RepoUtilsService } from './RepoUtilsService.ts';\n\nexport function LegalFilesService(): TLegalFilesService {\n let isDebug: boolean = false;\n const repoUtilsService: TRepoUtilsService = RepoUtilsService();\n const legalFilesUtilsService: TLegalFilesUtilsService = LegalFilesUtilsService(repoUtilsService);\n const { debugLog, findMonorepoRoot, resolveWorkspaceFromArg, loadWorkspaces } = repoUtilsService;\n const { assertTemplatesPresent, getConfiguredDocKeys, generateAll, readConfig } = legalFilesUtilsService;\n\n const options: TTemplateGeneratorOptions = {\n templateExtension: '.md',\n defaultTemplateBaseName: (docType: TLegalDocumentType): string => `${docType}_TEMPLATE`\n };\n\n async function generate(): Promise<void> {\n // eslint-disable-next-line spellcheck/spell-checker\n const argv = await yargs(hideBin(process.argv))\n // .scriptName('anarchy-legal:files')\n .usage('$0 --workspace <name|path> --out <dir> [--templates <dir>] [--types DISCLAIMER,EULA,...] [--debug]')\n .option('workspace', { type: 'string', demandOption: true, describe: 'Target workspace (name or path relative to monorepo root)' })\n .option('out', { type: 'string', demandOption: true, describe: 'Output directory for generated files (relative to current working dir allowed)' })\n .option('templates', { type: 'string', describe: 'Templates directory. Default: packages/anarchy-legal/templates' })\n .option('types', { type: 'string', describe: `Comma-separated list of doc types. Default: ${Object.values(LegalDocumentType).join(',')}` })\n .option('debug', { type: 'boolean', default: false })\n .help()\n .parseAsync();\n\n isDebug = Boolean(argv.debug);\n repoUtilsService.setDebugMode(isDebug);\n\n const scriptDir: string = path.dirname(fileURLToPath(import.meta.url));\n const startCandidates: string[] = [process.env.INIT_CWD, process.cwd(), scriptDir].filter(Boolean) as string[];\n\n // Find monorepo root\n const rootDir: string | undefined = await startCandidates.reduce<Promise<string | undefined>>(async (accP, c) => {\n const acc: string | undefined = await accP;\n if (acc) return acc;\n try {\n return await findMonorepoRoot(c);\n } catch (e) {\n debugLog(isDebug, 'no root from', c, ':', (e as Error).message);\n return undefined;\n }\n }, Promise.resolve(undefined));\n if (!rootDir) throw new Error(`Failed to find monorepo root from: ${startCandidates.join(', ')}`);\n\n // Load workspaces and resolve target\n const workspaces: ReadonlyMap<string, TWorkspaceInfo> = await loadWorkspaces(rootDir);\n const ws = await resolveWorkspaceFromArg(String(argv.workspace), workspaces, rootDir);\n debugLog(isDebug, 'target workspace:', ws.name, ws.dir);\n\n // Resolve templates dir\n const templatesDir: string = argv.templates ? (path.isAbsolute(argv.templates) ? argv.templates : path.resolve(process.cwd(), argv.templates)) : path.resolve(scriptDir, '../../src/Templates');\n debugLog(isDebug, 'templates dir:', templatesDir);\n\n // Resolve out dir\n const outDir: string = path.isAbsolute(argv.out as string) ? (argv.out as string) : path.resolve(process.cwd(), String(argv.out));\n debugLog(isDebug, 'out dir:', outDir);\n\n const config: TAnarchyLegalConfig = await readConfig(ws.dir);\n const configKeys: ReadonlyArray<string> = Array.from(getConfiguredDocKeys(config));\n\n if (!configKeys.length) {\n console.log('Nothing to generate: no doc types configured (or filtered out by --types).');\n return;\n }\n\n const cliKeys: ReadonlySet<string> = ((): Set<string> => {\n if (!argv.types) return new Set(configKeys);\n const parts: ReadonlyArray<string> = String(argv.types)\n .split(',')\n .map((s: string): string => s.trim())\n .filter(Boolean);\n const ok = new Set(configKeys);\n return new Set(parts.filter((p: string): boolean => ok.has(p)));\n })();\n\n if (!cliKeys.size) {\n console.log('Nothing to generate: all requested sections were filtered out or missing in config.');\n return;\n }\n\n assertTemplatesPresent(config, cliKeys);\n\n // Go\n await generateAll({ ws, outDir, templatesDir, keys: cliKeys, config }, options);\n }\n\n return { generate };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LegalFilesService.js","sources":["../../src/Services/LegalFilesService.ts"],"sourcesContent":["import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { TAnarchyLegalConfig, TLegalDocumentType, TLegalFilesService, TLegalFilesUtilsService, TRepoUtilsService, TTemplateGeneratorOptions, TWorkspaceInfo } from '@hellpig/anarchy-legal'; // eslint-disable-next-line spellcheck/spell-checker\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\n\nimport { LegalDocumentType } from '../Constants/LegalDocumentType.ts';\nimport { LegalFilesUtilsService } from './LegalFilesUtilsService.ts';\nimport { RepoUtilsService } from './RepoUtilsService.ts';\n\nexport function LegalFilesService(): TLegalFilesService {\n let isDebug: boolean = false;\n const repoUtilsService: TRepoUtilsService = RepoUtilsService();\n const legalFilesUtilsService: TLegalFilesUtilsService = LegalFilesUtilsService(repoUtilsService);\n const { debugLog, findMonorepoRoot, resolveWorkspaceFromArg, loadWorkspaces } = repoUtilsService;\n const { assertTemplatesPresent, getConfiguredDocKeys, generateAll, readConfig } = legalFilesUtilsService;\n\n const options: TTemplateGeneratorOptions = {\n templateExtension: '.md',\n defaultTemplateBaseName: (docType: TLegalDocumentType): string => `${docType}_TEMPLATE`\n };\n\n async function generate(): Promise<void> {\n // eslint-disable-next-line spellcheck/spell-checker\n const argv = await yargs(hideBin(process.argv))\n // .scriptName('anarchy-legal:files')\n .usage('$0 --workspace <name|path> --out <dir> [--templates <dir>] [--types DISCLAIMER,EULA,...] [--debug]')\n .option('workspace', { type: 'string', demandOption: true, describe: 'Target workspace (name or path relative to monorepo root)' })\n .option('out', { type: 'string', demandOption: true, describe: 'Output directory for generated files (relative to current working dir allowed)' })\n .option('templates', { type: 'string', describe: 'Templates directory. Default: packages/anarchy-legal/templates' })\n .option('types', { type: 'string', describe: `Comma-separated list of doc types. Default: ${Object.values(LegalDocumentType).join(',')}` })\n .option('debug', { type: 'boolean', default: false })\n .help()\n .parseAsync();\n\n isDebug = Boolean(argv.debug);\n repoUtilsService.setDebugMode(isDebug);\n\n const scriptDir: string = path.dirname(fileURLToPath(import.meta.url));\n const startCandidates: string[] = [process.env.INIT_CWD, process.cwd(), scriptDir].filter(Boolean) as string[];\n\n // Find monorepo root\n const rootDir: string | undefined = await startCandidates.reduce<Promise<string | undefined>>(async (accP, c) => {\n const acc: string | undefined = await accP;\n if (acc) return acc;\n try {\n return await findMonorepoRoot(c);\n } catch (e) {\n debugLog(isDebug, 'no root from', c, ':', (e as Error).message);\n return undefined;\n }\n }, Promise.resolve(undefined));\n if (!rootDir) throw new Error(`Failed to find monorepo root from: ${startCandidates.join(', ')}`);\n\n // Load workspaces and resolve target\n const workspaces: ReadonlyMap<string, TWorkspaceInfo> = await loadWorkspaces(rootDir);\n const ws = await resolveWorkspaceFromArg(String(argv.workspace), workspaces, rootDir);\n debugLog(isDebug, 'target workspace:', ws.name, ws.dir);\n\n // Resolve templates dir\n const templatesDir: string = argv.templates ? (path.isAbsolute(argv.templates) ? argv.templates : path.resolve(process.cwd(), argv.templates)) : path.resolve(scriptDir, '../../src/Templates');\n debugLog(isDebug, 'templates dir:', templatesDir);\n\n // Resolve out dir\n const outDir: string = path.isAbsolute(argv.out as string) ? (argv.out as string) : path.resolve(process.cwd(), String(argv.out));\n debugLog(isDebug, 'out dir:', outDir);\n\n const config: TAnarchyLegalConfig = await readConfig(ws.dir);\n const configKeys: ReadonlyArray<string> = Array.from(getConfiguredDocKeys(config));\n\n if (!configKeys.length) {\n console.log('Nothing to generate: no doc types configured (or filtered out by --types).');\n return;\n }\n\n const cliKeys: ReadonlySet<string> = ((): Set<string> => {\n if (!argv.types) return new Set(configKeys);\n const parts: ReadonlyArray<string> = String(argv.types)\n .split(',')\n .map((s: string): string => s.trim())\n .filter(Boolean);\n const ok = new Set(configKeys);\n return new Set(parts.filter((p: string): boolean => ok.has(p)));\n })();\n\n if (!cliKeys.size) {\n console.log('Nothing to generate: all requested sections were filtered out or missing in config.');\n return;\n }\n\n assertTemplatesPresent(config, cliKeys);\n\n // Go\n await generateAll({ ws, outDir, templatesDir, keys: cliKeys, config }, options);\n }\n\n return { generate };\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"LegalFilesUtilsService.js","sources":["../../src/Services/LegalFilesUtilsService.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport type {\n TAnarchyLegalConfig,\n TAnarchyLegalConfigEntry,\n TLegalDocumentType,\n TLegalFilesUtilsService,\n TRenderInput,\n TRepoUtilsService,\n TTemplateGeneratorOptions,\n TTemplateMessages\n} from '@Anarchy/Legal/Models';\nimport { UTCDate } from '@date-fns/utc';\nimport { isValid, parseISO } from 'date-fns';\nimport { format as dfFormat } from 'date-fns/format';\n// eslint-disable-next-line spellcheck/spell-checker\nimport { globby } from 'globby';\n\nimport { LegalDocumentType } from '../Constants/LegalDocumentType.ts';\n\nexport function LegalFilesUtilsService(repoUtilsService: TRepoUtilsService): TLegalFilesUtilsService {\n const { debugLog, isExist, isDebug } = repoUtilsService;\n\n async function readConfig(wsDir: string): Promise<TAnarchyLegalConfig> | never {\n const candidates: ReadonlyArray<string> = [path.join(wsDir, 'anarchy-legal.config.js'), path.join(wsDir, 'anarchy-legal.config.mjs'), path.join(wsDir, 'anarchy-legal.config.cjs')];\n\n const found: string | undefined = await candidates.reduce<Promise<string | undefined>>(async (prevPromise: Promise<string | undefined>, p: string): Promise<string | undefined> => {\n const prev: string | undefined = await prevPromise;\n if (prev) return prev;\n return (await isExist(p)) ? p : undefined;\n }, Promise.resolve(undefined));\n\n if (!found) {\n debugLog(isDebug(), 'config: <none> (no JS config found)');\n return {};\n }\n\n try {\n const mod = await import(pathToFileURL(found).href);\n // Support both ESM default export and CommonJS module.exports\n const exported = (mod && 'default' in mod ? (mod as any).default : mod) as unknown;\n\n if (!exported || typeof exported !== 'object' || Array.isArray(exported)) throw new Error('Invalid config export. Expected an object like { GENERIC: {...}, EULA: {...}, ... }.');\n\n // Very light validation and narrowing\n const obj = exported as Record<string, unknown>;\n\n const processConfigSection = (k: 'GENERIC' | string): [string, any] | undefined => {\n const v = obj[k];\n if (v === undefined) return undefined;\n if (!v || typeof v !== 'object' || Array.isArray(v)) {\n console.warn(`[warn] anarchy-legal.config: section \"${k}\" must be an object; got ${typeof v}. Skipped.`);\n return undefined;\n }\n const { template, messages, relativeOutput, outputName } = v as TAnarchyLegalConfigEntry;\n return [\n k,\n {\n ...(template ? { template } : {}),\n ...(messages ? { messages } : {}),\n ...(relativeOutput ? { relativeOutput } : {}),\n ...(outputName ? { outputName } : {})\n }\n ];\n };\n\n const processedEntries = Object.keys(obj)\n .map(processConfigSection)\n .filter((entry): entry is [string, any] => entry !== undefined);\n const config: TAnarchyLegalConfig = Object.fromEntries(processedEntries);\n\n debugLog(isDebug(), 'config file:', found, 'keys:', Object.keys(config));\n return config;\n } catch (e) {\n const msg: string = e instanceof Error ? e.message : String(e);\n throw new Error(`Failed to load config ${found}: ${msg}`);\n }\n }\n\n async function findTemplateFile(\n templatesDir: string,\n docType: TLegalDocumentType,\n { templateExtension, defaultTemplateBaseName }: TTemplateGeneratorOptions,\n desiredBase?: string\n ): Promise<string | undefined> {\n // 1) exact by desiredBase\n if (desiredBase) {\n const exact: string = path.join(templatesDir, `${desiredBase}${templateExtension}`);\n if (await isExist(exact)) return exact;\n }\n // 2) default <TYPE>_TEMPLATE.md\n const def: string = path.join(templatesDir, `${defaultTemplateBaseName(docType)}${templateExtension}`);\n if (await isExist(def)) return def;\n // 3) first match <TYPE>_*_TEMPLATE.md (alphabetically)\n const pattern: string = path.join(templatesDir, `${docType}_*${templateExtension}`);\n // eslint-disable-next-line spellcheck/spell-checker\n const found: string[] = await globby([pattern], { absolute: true });\n const [first] = found.toSorted();\n return first;\n }\n\n const PLACEHOLDER_RE = /{{\\s*([A-Z0-9_]+)\\s*}}/g;\n\n /** Parse date string with date-fns (supports \"now\", ISO, and Date constructor fallback) */\n /** Parse/format via date-fns.\n * Special case: when dateStr === \"now\", output uses UTC date/time (not local).\n */\n const formatWithDateFns = (dateStr: string, format: string): string => {\n const d: Date =\n dateStr.toLowerCase() === 'now'\n ? new UTCDate()\n : ((): Date => {\n const iso: Date = parseISO(dateStr);\n return isValid(iso) ? iso : new Date(dateStr);\n })();\n if (!isValid(d)) return ''; // invalid date → empty\n try {\n return dfFormat(d, format);\n } catch {\n return '';\n }\n };\n\n // Convert message value → string (for variable substitution)\n function materializeMessage(v: unknown): string {\n if (v === null || v === undefined) return '';\n if (typeof v === 'string') return v;\n if (typeof v === 'number') return Number.isFinite(v) ? String(v) : '';\n if (typeof v === 'boolean') return v ? 'true' : 'false'; // only for {{VAR}} replacement\n // date-object: { date: string; format: string } -> via date-fns\n if (typeof v === 'object' && 'date' in (v as any) && 'format' in (v as any)) {\n const { date, format } = v as { date: string; format: string };\n if (typeof date === 'string' && typeof format === 'string') return formatWithDateFns(date, format);\n }\n return '';\n }\n\n // Extract placeholders present in a template text\n function collectPlaceholders(tpl: string): ReadonlySet<string> {\n return new Set<string>([...tpl.matchAll(PLACEHOLDER_RE)].map((m) => m[1] as string));\n }\n\n // PACKAGE_* resolution from package.json\n function packagePlaceholder(key: string, pkg: Readonly<Record<string, unknown>>): string | undefined {\n // key is suffix after \"PACKAGE_\", e.g. NAME, VERSION, AUTHOR, AUTHORS, LICENSE, REPOSITORY, HOMEPAGE, BUGS_URL, DESCRIPTION\n const k: string = key.toUpperCase();\n\n const str = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined);\n const arrStr = (v: unknown): string | undefined => (Array.isArray(v) ? (v as unknown[]).map((x) => (typeof x === 'string' ? x : JSON.stringify(x))).join(', ') : undefined);\n\n function authorToString(a: unknown): string | undefined {\n if (!a) return undefined;\n if (typeof a === 'string') return a;\n if (typeof a === 'object') {\n const n: string = str((a as any).name) ?? '';\n const e: string | undefined = str((a as any).email);\n const w: string | undefined = str((a as any).url);\n return [n, e ? `<${e}>` : '', w ? `(${w})` : ''].filter(Boolean).join(' ').trim();\n }\n return undefined;\n }\n\n switch (k) {\n case 'NAME':\n return str(pkg.name);\n case 'VERSION':\n return str(pkg.version);\n case 'DESCRIPTION':\n return str(pkg.description);\n case 'HOMEPAGE':\n return str(pkg.homepage);\n case 'LICENSE':\n return str(pkg.license);\n case 'REPOSITORY': {\n const repo = (pkg as any).repository;\n if (typeof repo === 'string') return repo;\n const url: string | undefined = str(repo?.url);\n return url ?? undefined;\n }\n case 'BUGS_URL': {\n const bugs = (pkg as any).bugs;\n if (typeof bugs === 'string') return bugs;\n const url = str(bugs?.url);\n return url ?? undefined;\n }\n case 'AUTHOR':\n return authorToString((pkg as any).author);\n case 'AUTHORS':\n return arrStr((pkg as any).authors);\n case 'KEYWORDS':\n return arrStr((pkg as any).keywords);\n default: {\n // if someone uses {{PACKAGE_FOO_BAR}}, try a naive lower-cased lookup \"foo_bar\" then \"fooBar\"\n const direct: unknown = pkg[key.toLowerCase()];\n if (typeof direct === 'string') return direct;\n return undefined;\n }\n }\n }\n\n // Build final map for a given doc type\n function buildPlaceholderValues(\n _docType: TLegalDocumentType,\n tplText: string,\n pkg: Readonly<Record<string, unknown>>,\n generic: TTemplateMessages | undefined,\n specific: TTemplateMessages | undefined\n ): Readonly<Record<string, string>> {\n const names: ReadonlySet<string> = collectPlaceholders(tplText);\n\n const pkgValues: Record<string, string> = Array.from(names).reduce<Record<string, string>>((acc, name) => {\n if (!name.startsWith('PACKAGE_')) return acc;\n const suffix: string = name.slice('PACKAGE_'.length);\n const v: string | undefined = packagePlaceholder(suffix, pkg);\n return v !== undefined ? { ...acc, [name]: v } : acc;\n }, {});\n\n const genericValues: Record<string, string> = generic ? Object.fromEntries(Object.entries(generic).map(([k, v]) => [k, materializeMessage(v)])) : {};\n\n const specificValues: Record<string, string> = specific ? Object.fromEntries(Object.entries(specific).map(([k, v]) => [k, materializeMessage(v)])) : {};\n\n return { ...pkgValues, ...genericValues, ...specificValues };\n }\n\n // Build both: materialized values for {{VAR}} and raw map for section truthiness\n function buildContext(\n docType: TLegalDocumentType,\n tplText: string,\n pkg: Readonly<Record<string, unknown>>,\n generic: Readonly<Record<string, unknown>> | undefined,\n specific: Readonly<Record<string, unknown>> | undefined\n ): Readonly<{ values: Record<string, string>; raw: Record<string, unknown> }> {\n const values: Readonly<Record<string, string>> = buildPlaceholderValues(docType, tplText, pkg, generic as any, specific as any);\n\n const raw: Record<string, unknown> = {\n ...Object.fromEntries(Object.entries(values)),\n ...(generic || {}),\n ...(specific || {})\n };\n\n return { values, raw };\n }\n\n // Replace variables {{VAR}} with materialized values\n function renderVariables(tpl: string, values: Readonly<Record<string, string>>, onMissing?: (name: string) => void): string {\n const VAR_RE = /{{\\s*([A-Z0-9_]+)\\s*}}/g;\n return tpl.replace(VAR_RE, (_m, g1: string) => {\n const v: string = values[g1];\n if (v === undefined) {\n onMissing?.(g1);\n return '';\n }\n return v;\n });\n }\n\n // Evaluate sections recursively until nothing left\n function renderSections(input: string, truthyMap: Readonly<Record<string, unknown>>): string {\n const SECTION_RE = /{{\\s*([#^])\\s*([A-Z0-9_]+)\\s*}}([\\s\\S]*?){{\\s*\\/\\s*\\2\\s*}}/g;\n\n const processUntilConverged = (current: string): string => {\n const next = current.replace(SECTION_RE, (_m, sigil: '#' | '^', name: string, body: string) => {\n const condition: boolean = Boolean(truthyMap[name]);\n const pass: boolean = sigil === '#' ? condition : !condition;\n return pass ? renderSections(body, truthyMap) : '';\n });\n return next === current ? current : processUntilConverged(next);\n };\n\n return processUntilConverged(input);\n }\n\n async function generateForType(input: TRenderInput, key: string, options: TTemplateGeneratorOptions): Promise<void> {\n const genericConfig = input.config['GENERIC'];\n const specificConfig = input.config[key];\n\n if (!specificConfig?.template || specificConfig.template.trim() === '') throw new Error(`[${key}] missing \"template\" in anarchy-legal.config.js`);\n\n const desiredBase: string = specificConfig.template;\n\n const tplPath: string | undefined = await findTemplateFile(input.templatesDir, key, options, desiredBase);\n if (!tplPath) throw new Error(`[${key}] template \"${desiredBase}\" not found under templates dir: ${input.templatesDir}`);\n\n const tplText: string = await fs.readFile(tplPath, 'utf8');\n\n const { values, raw } = buildContext(key, tplText, input.ws.pkg, genericConfig?.messages, specificConfig?.messages);\n\n const afterSections: string = renderSections(tplText, raw);\n\n const namesAfter: ReadonlySet<string> = collectPlaceholders(afterSections);\n const missing: ReadonlyArray<string> = Array.from(namesAfter).filter((name: string): boolean => values[name] === undefined);\n if (missing.length) console.warn(`[warn] ${key}: ${missing.length} placeholders had no value: ${missing.slice(0, 10).join(', ')}${missing.length > 10 ? '…' : ''}`);\n\n const rendered: string = renderVariables(afterSections, values);\n\n const relOut: string | undefined = specificConfig.relativeOutput?.trim();\n if (relOut && path.isAbsolute(relOut)) console.warn(`[warn] ${key}: relativeOutput is absolute (\"${relOut}\"); it will be used as-is.`);\n const targetDir: string = relOut ? path.resolve(input.outDir, relOut) : input.outDir;\n\n const baseName: string = (specificConfig.outputName?.trim() || key).replace(/\\s+$/, '');\n\n const outName: string = `${baseName}.md`;\n const outPath: string = path.join(targetDir, outName);\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, rendered, 'utf8');\n console.log(`${baseName}.md written -> ${outPath}`);\n }\n\n async function generateAll(renderInput: TRenderInput & { keys: ReadonlySet<string> }, options: TTemplateGeneratorOptions): Promise<void> {\n // eslint-disable-next-line functional/no-loop-statements\n for (const k of renderInput.keys) {\n await generateForType(renderInput, k, options);\n }\n }\n\n // Return only those doc types that are explicitly present in the config object\n function getConfiguredDocTypes(config: TAnarchyLegalConfig): ReadonlySet<TLegalDocumentType> {\n const set = new Set<TLegalDocumentType>();\n Object.values(LegalDocumentType).forEach((docType: TLegalDocumentType) => {\n if (config[docType]) set.add(docType);\n });\n return set;\n }\n\n // Ensure every configured doc type has a non-empty \"template\" field\n function assertTemplatesPresent(config: TAnarchyLegalConfig, keys: ReadonlySet<string>): void | never {\n const missing = Array.from(keys).filter((k) => {\n const tpl = config[k]?.template;\n return typeof tpl !== 'string' || tpl.trim() === '';\n });\n\n if (missing.length) {\n throw new Error(`anarchy-legal.config.js: \"template\" is required for sections: ${missing.join(', ')}`);\n }\n }\n\n function getConfiguredDocKeys(config: TAnarchyLegalConfig): ReadonlySet<string> {\n return new Set(Object.keys(config || {}).filter((k) => k !== 'GENERIC'));\n }\n\n return {\n assertTemplatesPresent,\n generateAll,\n getConfiguredDocKeys,\n getConfiguredDocTypes,\n readConfig\n };\n}\n"],"names":["format","dfFormat"],"mappings":"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"}
1
+ {"version":3,"file":"LegalFilesUtilsService.js","sources":["../../src/Services/LegalFilesUtilsService.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { UTCDate } from '@date-fns/utc';\nimport type {\n TAnarchyLegalConfig,\n TAnarchyLegalConfigEntry,\n TLegalDocumentType,\n TLegalFilesUtilsService,\n TRenderInput,\n TRepoUtilsService,\n TTemplateGeneratorOptions,\n TTemplateMessages\n} from '@hellpig/anarchy-legal/Models';\nimport { isValid, parseISO } from 'date-fns';\nimport { format as dfFormat } from 'date-fns/format';\n// eslint-disable-next-line spellcheck/spell-checker\nimport { globby } from 'globby';\n\nimport { LegalDocumentType } from '../Constants/LegalDocumentType.ts';\n\nexport function LegalFilesUtilsService(repoUtilsService: TRepoUtilsService): TLegalFilesUtilsService {\n const { debugLog, isExist, isDebug } = repoUtilsService;\n\n async function readConfig(wsDir: string): Promise<TAnarchyLegalConfig> | never {\n const candidates: ReadonlyArray<string> = [path.join(wsDir, 'anarchy-legal.config.js'), path.join(wsDir, 'anarchy-legal.config.mjs'), path.join(wsDir, 'anarchy-legal.config.cjs')];\n\n const found: string | undefined = await candidates.reduce<Promise<string | undefined>>(async (prevPromise: Promise<string | undefined>, p: string): Promise<string | undefined> => {\n const prev: string | undefined = await prevPromise;\n if (prev) return prev;\n return (await isExist(p)) ? p : undefined;\n }, Promise.resolve(undefined));\n\n if (!found) {\n debugLog(isDebug(), 'config: <none> (no JS config found)');\n return {};\n }\n\n try {\n const mod = await import(pathToFileURL(found).href);\n // Support both ESM default export and CommonJS module.exports\n const exported = (mod && 'default' in mod ? (mod as any).default : mod) as unknown;\n\n if (!exported || typeof exported !== 'object' || Array.isArray(exported)) throw new Error('Invalid config export. Expected an object like { GENERIC: {...}, EULA: {...}, ... }.');\n\n // Very light validation and narrowing\n const obj = exported as Record<string, unknown>;\n\n const processConfigSection = (k: 'GENERIC' | string): [string, any] | undefined => {\n const v = obj[k];\n if (v === undefined) return undefined;\n if (!v || typeof v !== 'object' || Array.isArray(v)) {\n console.warn(`[warn] anarchy-legal.config: section \"${k}\" must be an object; got ${typeof v}. Skipped.`);\n return undefined;\n }\n const { template, messages, relativeOutput, outputName } = v as TAnarchyLegalConfigEntry;\n return [\n k,\n {\n ...(template ? { template } : {}),\n ...(messages ? { messages } : {}),\n ...(relativeOutput ? { relativeOutput } : {}),\n ...(outputName ? { outputName } : {})\n }\n ];\n };\n\n const processedEntries = Object.keys(obj)\n .map(processConfigSection)\n .filter((entry): entry is [string, any] => entry !== undefined);\n const config: TAnarchyLegalConfig = Object.fromEntries(processedEntries);\n\n debugLog(isDebug(), 'config file:', found, 'keys:', Object.keys(config));\n return config;\n } catch (e) {\n const msg: string = e instanceof Error ? e.message : String(e);\n throw new Error(`Failed to load config ${found}: ${msg}`);\n }\n }\n\n async function findTemplateFile(\n templatesDir: string,\n docType: TLegalDocumentType,\n { templateExtension, defaultTemplateBaseName }: TTemplateGeneratorOptions,\n desiredBase?: string\n ): Promise<string | undefined> {\n // 1) exact by desiredBase\n if (desiredBase) {\n const exact: string = path.join(templatesDir, `${desiredBase}${templateExtension}`);\n if (await isExist(exact)) return exact;\n }\n // 2) default <TYPE>_TEMPLATE.md\n const def: string = path.join(templatesDir, `${defaultTemplateBaseName(docType)}${templateExtension}`);\n if (await isExist(def)) return def;\n // 3) first match <TYPE>_*_TEMPLATE.md (alphabetically)\n const pattern: string = path.join(templatesDir, `${docType}_*${templateExtension}`);\n // eslint-disable-next-line spellcheck/spell-checker\n const found: string[] = await globby([pattern], { absolute: true });\n const [first] = found.toSorted();\n return first;\n }\n\n const PLACEHOLDER_RE = /{{\\s*([A-Z0-9_]+)\\s*}}/g;\n\n /** Parse date string with date-fns (supports \"now\", ISO, and Date constructor fallback) */\n /** Parse/format via date-fns.\n * Special case: when dateStr === \"now\", output uses UTC date/time (not local).\n */\n const formatWithDateFns = (dateStr: string, format: string): string => {\n const d: Date =\n dateStr.toLowerCase() === 'now'\n ? new UTCDate()\n : ((): Date => {\n const iso: Date = parseISO(dateStr);\n return isValid(iso) ? iso : new Date(dateStr);\n })();\n if (!isValid(d)) return ''; // invalid date → empty\n try {\n return dfFormat(d, format);\n } catch {\n return '';\n }\n };\n\n // Convert message value → string (for variable substitution)\n function materializeMessage(v: unknown): string {\n if (v === null || v === undefined) return '';\n if (typeof v === 'string') return v;\n if (typeof v === 'number') return Number.isFinite(v) ? String(v) : '';\n if (typeof v === 'boolean') return v ? 'true' : 'false'; // only for {{VAR}} replacement\n // date-object: { date: string; format: string } -> via date-fns\n if (typeof v === 'object' && 'date' in (v as any) && 'format' in (v as any)) {\n const { date, format } = v as { date: string; format: string };\n if (typeof date === 'string' && typeof format === 'string') return formatWithDateFns(date, format);\n }\n return '';\n }\n\n // Extract placeholders present in a template text\n function collectPlaceholders(tpl: string): ReadonlySet<string> {\n return new Set<string>([...tpl.matchAll(PLACEHOLDER_RE)].map((m) => m[1] as string));\n }\n\n // PACKAGE_* resolution from package.json\n function packagePlaceholder(key: string, pkg: Readonly<Record<string, unknown>>): string | undefined {\n // key is suffix after \"PACKAGE_\", e.g. NAME, VERSION, AUTHOR, AUTHORS, LICENSE, REPOSITORY, HOMEPAGE, BUGS_URL, DESCRIPTION\n const k: string = key.toUpperCase();\n\n const str = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined);\n const arrStr = (v: unknown): string | undefined => (Array.isArray(v) ? (v as unknown[]).map((x) => (typeof x === 'string' ? x : JSON.stringify(x))).join(', ') : undefined);\n\n function authorToString(a: unknown): string | undefined {\n if (!a) return undefined;\n if (typeof a === 'string') return a;\n if (typeof a === 'object') {\n const n: string = str((a as any).name) ?? '';\n const e: string | undefined = str((a as any).email);\n const w: string | undefined = str((a as any).url);\n return [n, e ? `<${e}>` : '', w ? `(${w})` : ''].filter(Boolean).join(' ').trim();\n }\n return undefined;\n }\n\n switch (k) {\n case 'NAME':\n return str(pkg.name);\n case 'VERSION':\n return str(pkg.version);\n case 'DESCRIPTION':\n return str(pkg.description);\n case 'HOMEPAGE':\n return str(pkg.homepage);\n case 'LICENSE':\n return str(pkg.license);\n case 'REPOSITORY': {\n const repo = (pkg as any).repository;\n if (typeof repo === 'string') return repo;\n const url: string | undefined = str(repo?.url);\n return url ?? undefined;\n }\n case 'BUGS_URL': {\n const bugs = (pkg as any).bugs;\n if (typeof bugs === 'string') return bugs;\n const url = str(bugs?.url);\n return url ?? undefined;\n }\n case 'AUTHOR':\n return authorToString((pkg as any).author);\n case 'AUTHORS':\n return arrStr((pkg as any).authors);\n case 'KEYWORDS':\n return arrStr((pkg as any).keywords);\n default: {\n // if someone uses {{PACKAGE_FOO_BAR}}, try a naive lower-cased lookup \"foo_bar\" then \"fooBar\"\n const direct: unknown = pkg[key.toLowerCase()];\n if (typeof direct === 'string') return direct;\n return undefined;\n }\n }\n }\n\n // Build final map for a given doc type\n function buildPlaceholderValues(\n _docType: TLegalDocumentType,\n tplText: string,\n pkg: Readonly<Record<string, unknown>>,\n generic: TTemplateMessages | undefined,\n specific: TTemplateMessages | undefined\n ): Readonly<Record<string, string>> {\n const names: ReadonlySet<string> = collectPlaceholders(tplText);\n\n const pkgValues: Record<string, string> = Array.from(names).reduce<Record<string, string>>((acc, name) => {\n if (!name.startsWith('PACKAGE_')) return acc;\n const suffix: string = name.slice('PACKAGE_'.length);\n const v: string | undefined = packagePlaceholder(suffix, pkg);\n return v !== undefined ? { ...acc, [name]: v } : acc;\n }, {});\n\n const genericValues: Record<string, string> = generic ? Object.fromEntries(Object.entries(generic).map(([k, v]) => [k, materializeMessage(v)])) : {};\n\n const specificValues: Record<string, string> = specific ? Object.fromEntries(Object.entries(specific).map(([k, v]) => [k, materializeMessage(v)])) : {};\n\n return { ...pkgValues, ...genericValues, ...specificValues };\n }\n\n // Build both: materialized values for {{VAR}} and raw map for section truthiness\n function buildContext(\n docType: TLegalDocumentType,\n tplText: string,\n pkg: Readonly<Record<string, unknown>>,\n generic: Readonly<Record<string, unknown>> | undefined,\n specific: Readonly<Record<string, unknown>> | undefined\n ): Readonly<{ values: Record<string, string>; raw: Record<string, unknown> }> {\n const values: Readonly<Record<string, string>> = buildPlaceholderValues(docType, tplText, pkg, generic as any, specific as any);\n\n const raw: Record<string, unknown> = {\n ...Object.fromEntries(Object.entries(values)),\n ...(generic || {}),\n ...(specific || {})\n };\n\n return { values, raw };\n }\n\n // Replace variables {{VAR}} with materialized values\n function renderVariables(tpl: string, values: Readonly<Record<string, string>>, onMissing?: (name: string) => void): string {\n const VAR_RE = /{{\\s*([A-Z0-9_]+)\\s*}}/g;\n return tpl.replace(VAR_RE, (_m, g1: string) => {\n const v: string = values[g1];\n if (v === undefined) {\n onMissing?.(g1);\n return '';\n }\n return v;\n });\n }\n\n // Evaluate sections recursively until nothing left\n function renderSections(input: string, truthyMap: Readonly<Record<string, unknown>>): string {\n const SECTION_RE = /{{\\s*([#^])\\s*([A-Z0-9_]+)\\s*}}([\\s\\S]*?){{\\s*\\/\\s*\\2\\s*}}/g;\n\n const processUntilConverged = (current: string): string => {\n const next = current.replace(SECTION_RE, (_m, sigil: '#' | '^', name: string, body: string) => {\n const condition: boolean = Boolean(truthyMap[name]);\n const pass: boolean = sigil === '#' ? condition : !condition;\n return pass ? renderSections(body, truthyMap) : '';\n });\n return next === current ? current : processUntilConverged(next);\n };\n\n return processUntilConverged(input);\n }\n\n async function generateForType(input: TRenderInput, key: string, options: TTemplateGeneratorOptions): Promise<void> {\n const genericConfig = input.config['GENERIC'];\n const specificConfig = input.config[key];\n\n if (!specificConfig?.template || specificConfig.template.trim() === '') throw new Error(`[${key}] missing \"template\" in anarchy-legal.config.js`);\n\n const desiredBase: string = specificConfig.template;\n\n const tplPath: string | undefined = await findTemplateFile(input.templatesDir, key, options, desiredBase);\n if (!tplPath) throw new Error(`[${key}] template \"${desiredBase}\" not found under templates dir: ${input.templatesDir}`);\n\n const tplText: string = await fs.readFile(tplPath, 'utf8');\n\n const { values, raw } = buildContext(key, tplText, input.ws.pkg, genericConfig?.messages, specificConfig?.messages);\n\n const afterSections: string = renderSections(tplText, raw);\n\n const namesAfter: ReadonlySet<string> = collectPlaceholders(afterSections);\n const missing: ReadonlyArray<string> = Array.from(namesAfter).filter((name: string): boolean => values[name] === undefined);\n if (missing.length) console.warn(`[warn] ${key}: ${missing.length} placeholders had no value: ${missing.slice(0, 10).join(', ')}${missing.length > 10 ? '…' : ''}`);\n\n const rendered: string = renderVariables(afterSections, values);\n\n const relOut: string | undefined = specificConfig.relativeOutput?.trim();\n if (relOut && path.isAbsolute(relOut)) console.warn(`[warn] ${key}: relativeOutput is absolute (\"${relOut}\"); it will be used as-is.`);\n const targetDir: string = relOut ? path.resolve(input.outDir, relOut) : input.outDir;\n\n const baseName: string = (specificConfig.outputName?.trim() || key).replace(/\\s+$/, '');\n\n const outName: string = `${baseName}.md`;\n const outPath: string = path.join(targetDir, outName);\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, rendered, 'utf8');\n console.log(`${baseName}.md written -> ${outPath}`);\n }\n\n async function generateAll(renderInput: TRenderInput & { keys: ReadonlySet<string> }, options: TTemplateGeneratorOptions): Promise<void> {\n // eslint-disable-next-line functional/no-loop-statements\n for (const k of renderInput.keys) {\n await generateForType(renderInput, k, options);\n }\n }\n\n // Return only those doc types that are explicitly present in the config object\n function getConfiguredDocTypes(config: TAnarchyLegalConfig): ReadonlySet<TLegalDocumentType> {\n const set = new Set<TLegalDocumentType>();\n Object.values(LegalDocumentType).forEach((docType: TLegalDocumentType) => {\n if (config[docType]) set.add(docType);\n });\n return set;\n }\n\n // Ensure every configured doc type has a non-empty \"template\" field\n function assertTemplatesPresent(config: TAnarchyLegalConfig, keys: ReadonlySet<string>): void | never {\n const missing = Array.from(keys).filter((k) => {\n const tpl = config[k]?.template;\n return typeof tpl !== 'string' || tpl.trim() === '';\n });\n\n if (missing.length) {\n throw new Error(`anarchy-legal.config.js: \"template\" is required for sections: ${missing.join(', ')}`);\n }\n }\n\n function getConfiguredDocKeys(config: TAnarchyLegalConfig): ReadonlySet<string> {\n return new Set(Object.keys(config || {}).filter((k) => k !== 'GENERIC'));\n }\n\n return {\n assertTemplatesPresent,\n generateAll,\n getConfiguredDocKeys,\n getConfiguredDocTypes,\n readConfig\n };\n}\n"],"names":["format","dfFormat"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"NoticeService.js","sources":["../../src/Services/NoticeService.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { TNoticeService, TNoticeUtilsService, TRepoUtilsService, TTemplateParsedEntry, TWorkspaceInfo } from '@Anarchy/Legal/Models';\n// eslint-disable-next-line spellcheck/spell-checker\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\n\nimport { NoticeUtilsService } from './NoticeUtilsService.ts';\nimport { RepoUtilsService } from './RepoUtilsService.ts';\n\nexport function NoticeService(): TNoticeService {\n let isDebug: boolean = false;\n const repoUtilsService: TRepoUtilsService = RepoUtilsService();\n const noticeUtilsService: TNoticeUtilsService = NoticeUtilsService();\n\n const { debugLog, findMonorepoRoot, isExist, loadWorkspaces, resolveWorkspaceFromArg } = repoUtilsService;\n const { collectAllHeadingIds, parseThirdPartyMarkdown, loadUpstreamNotice } = noticeUtilsService;\n\n function renderNotice(wsName: string, entries: ReadonlyArray<TTemplateParsedEntry>, includeUpstream: boolean, sourceName: string): string {\n const header: string = `# Third-Party Notices\n\n## Application: ${wsName}\n\n`;\n\n const subHeader: string = `This product includes third-party components. Their **licenses and attributions** are listed below.\nFor the **full license texts**, see \\`${sourceName}\\`.\n\nComponents listed: ${entries.length}\n\n## 1) Mandatory Attributions (verbatim)\n\nThe following notices are reproduced as provided by the respective licensors (e.g., **Apache-2.0 NOTICE**, **CC-BY credits**, **font attributions**):\n`;\n\n const noRecordsNote: string = '**Note:** No third-party components included.';\n\n const blocks: ReadonlyArray<ReadonlyArray<string>> = entries.map((v: TTemplateParsedEntry): ReadonlyArray<string> => {\n const licenses: string = v.licenses.length ? v.licenses.join(', ') + '\\n' : 'UNKNOWN';\n const repository: string = v.repository ? `**Repository:** ${v.repository}\\n\\n` : '';\n const url: string = v.url ? `**URL:** ${v.url}\\n\\n` : '';\n const inferredCopyright: string = v.inferredCopyright ? `**Attribution:** ${v.inferredCopyright}\\n` : '';\n\n const base: string = `\n## ${v.name}@${v.version}\n\n**License(s):** ${licenses}\n${repository}${url}${inferredCopyright}\n---\n`;\n const upstream: ReadonlyArray<string> = includeUpstream && v.upstreamNotice ? [`**Upstream NOTICE:**`, ...v.upstreamNotice.split(/\\r?\\n/).map((ln) => `> ${ln}`), ``] : [];\n return [base, ...upstream];\n });\n\n const footer: string = `\n ## 2) General OSS Acknowledgment\n\nThis product incorporates open-source software. **If any term of this file or the EULA conflicts with an OSS license for a specific component, the OSS license controls for that component.**\n`;\n\n return entries.length !== 0 ? [header, subHeader, ...blocks.flat(), footer].join('') : [header, noRecordsNote].join('');\n }\n\n async function generate(): Promise<void> {\n // eslint-disable-next-line spellcheck/spell-checker\n const argv = await yargs(hideBin(process.argv))\n .scriptName('anarchy-legal:notice')\n .usage('$0 --workspace <name|path> [--source <path>] [--source-name <file>] [--out <NOTICE.md>] [--include-upstream-notices] [--max-upstream-notice-kb <N>] [--audit] [--strict] [--debug]')\n .option('workspace', { type: 'string', demandOption: true, describe: 'Target workspace (name or path relative to monorepo root)' })\n .option('source', { type: 'string', describe: 'Path to the input attribution file (default is <workspace>/<source-name>)' })\n .option('source-name', { type: 'string', default: 'THIRD_PARTY_LICENSES.md', describe: 'File name inside the workspace to read from when --source is not provided' })\n .option('out', { type: 'string', describe: 'Path to output NOTICE.md. Default: <workspace>/NOTICE.md' })\n .option('include-upstream-notices', { type: 'boolean', default: false, describe: 'Also read upstream NOTICE files from dependency install paths (if present in source)' })\n .option('max-upstream-notice-kb', { type: 'number', default: 128, describe: 'Max size per upstream NOTICE to read (kilobytes)' })\n .option('audit', { type: 'boolean', default: false, describe: 'Print a diff between headings in source and parsed entries' })\n .option('strict', { type: 'boolean', default: false, describe: 'With --audit, exit with code 2 if mismatches found' })\n .option('debug', { type: 'boolean', default: false })\n .help()\n .parseAsync();\n\n isDebug = Boolean(argv.debug);\n repoUtilsService.setDebugMode(isDebug);\n\n // Locate monorepo root\n const scriptDir: string = path.dirname(fileURLToPath(import.meta.url));\n const startCandidates = [process.env.INIT_CWD, process.cwd(), scriptDir].filter(Boolean) as string[];\n const rootDir: string | undefined = await startCandidates.reduce<Promise<string | undefined>>(async (accP: Promise<string | undefined>, c: string): Promise<string | undefined> => {\n const acc: string | undefined = await accP;\n if (acc) return acc;\n try {\n return await findMonorepoRoot(c);\n } catch (e) {\n debugLog(isDebug, 'no root from', c, ':', (e as Error).message);\n return undefined;\n }\n }, Promise.resolve(undefined));\n if (!rootDir) throw new Error(`Failed to find monorepo root from: ${startCandidates.join(', ')}`);\n\n // Workspaces\n const workspaces: ReadonlyMap<string, TWorkspaceInfo> = await loadWorkspaces(rootDir);\n const ws: TWorkspaceInfo = await resolveWorkspaceFromArg(String(argv.workspace), workspaces, rootDir);\n debugLog(isDebug, 'target workspace:', ws.name, ws.dir);\n\n // Source & Out paths\n const sourceName: string = String(argv['source-name'] || 'THIRD_PARTY_LICENSES.md');\n const defaultSource: string = path.join(ws.dir, sourceName);\n const srcPath: string = argv.source ? (path.isAbsolute(argv.source) ? argv.source : path.resolve(process.cwd(), argv.source)) : defaultSource;\n const outPath: string = argv.out ? (path.isAbsolute(argv.out) ? argv.out : path.resolve(process.cwd(), argv.out)) : path.join(ws.dir, 'NOTICE.md');\n\n debugLog(isDebug, 'source:', srcPath);\n debugLog(isDebug, 'out:', outPath);\n\n if (!(await isExist(srcPath))) {\n console.error(`Source file not found: ${srcPath}`);\n process.exit(1);\n }\n\n const src: string = await fs.readFile(srcPath, 'utf8');\n\n // collect declared ids from headings for audit\n const declaredIds: ReadonlySet<string> = collectAllHeadingIds(src);\n\n const entries = parseThirdPartyMarkdown(src);\n debugLog(isDebug, 'parsed entries:', entries.length);\n\n // Optional upstream NOTICE load\n const finalEntries: ReadonlyArray<TTemplateParsedEntry> = await (async (): Promise<ReadonlyArray<TTemplateParsedEntry>> => {\n if (!argv['include-upstream-notices']) return entries;\n const maxBytes: number = Math.max(1, Math.floor(Number(argv['max-upstream-notice-kb']) || 128)) * 1024;\n const withUpstream = await Promise.all(\n entries.map(async (e: TTemplateParsedEntry) => {\n if (!e.path) return e;\n const u: string | undefined = await loadUpstreamNotice(e.path, maxBytes);\n return u ? { ...e, upstreamNotice: u } : e;\n })\n );\n const filledCount: number = withUpstream.filter((e): boolean => Boolean(e.upstreamNotice)).length;\n debugLog(isDebug, 'upstream notices loaded:', filledCount);\n return withUpstream;\n })();\n\n // Audit report\n if (argv.audit) {\n const parsedIds = new Set(finalEntries.map((e: TTemplateParsedEntry): string => e.id));\n const missing: ReadonlyArray<string> = Array.from(declaredIds)\n .filter((id: string): boolean => !parsedIds.has(id))\n .toSorted();\n\n console.log(`NOTICE audit:\n headings in source: ${declaredIds.size}\n parsed entries: ${parsedIds.size}\n missing in NOTICE: ${missing.length}`);\n\n if (missing.length) {\n console.log(missing.map((x: string): string => ` - ${x}`).join('\\n'));\n if (argv.strict) {\n console.error('Audit failed: some entries were not parsed into NOTICE.');\n process.exit(2);\n }\n } else {\n console.log('Audit OK: all entries accounted for.');\n }\n }\n\n const md: string = renderNotice(ws.name, entries, Boolean(argv['include-upstream-notices']), sourceName);\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, md, 'utf8');\n console.log(`NOTICE.md written -> ${outPath}`);\n }\n\n return { generate };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NoticeService.js","sources":["../../src/Services/NoticeService.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { TNoticeService, TNoticeUtilsService, TRepoUtilsService, TTemplateParsedEntry, TWorkspaceInfo } from '@hellpig/anarchy-legal/Models';\n// eslint-disable-next-line spellcheck/spell-checker\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\n\nimport { NoticeUtilsService } from './NoticeUtilsService.ts';\nimport { RepoUtilsService } from './RepoUtilsService.ts';\n\nexport function NoticeService(): TNoticeService {\n let isDebug: boolean = false;\n const repoUtilsService: TRepoUtilsService = RepoUtilsService();\n const noticeUtilsService: TNoticeUtilsService = NoticeUtilsService();\n\n const { debugLog, findMonorepoRoot, isExist, loadWorkspaces, resolveWorkspaceFromArg } = repoUtilsService;\n const { collectAllHeadingIds, parseThirdPartyMarkdown, loadUpstreamNotice } = noticeUtilsService;\n\n function renderNotice(wsName: string, entries: ReadonlyArray<TTemplateParsedEntry>, includeUpstream: boolean, sourceName: string): string {\n const header: string = `# Third-Party Notices\n\n## Application: ${wsName}\n\n`;\n\n const subHeader: string = `This product includes third-party components. Their **licenses and attributions** are listed below.\nFor the **full license texts**, see \\`${sourceName}\\`.\n\nComponents listed: ${entries.length}\n\n## 1) Mandatory Attributions (verbatim)\n\nThe following notices are reproduced as provided by the respective licensors (e.g., **Apache-2.0 NOTICE**, **CC-BY credits**, **font attributions**):\n`;\n\n const noRecordsNote: string = '**Note:** No third-party components included.';\n\n const blocks: ReadonlyArray<ReadonlyArray<string>> = entries.map((v: TTemplateParsedEntry): ReadonlyArray<string> => {\n const licenses: string = v.licenses.length ? v.licenses.join(', ') + '\\n' : 'UNKNOWN';\n const repository: string = v.repository ? `**Repository:** ${v.repository}\\n\\n` : '';\n const url: string = v.url ? `**URL:** ${v.url}\\n\\n` : '';\n const inferredCopyright: string = v.inferredCopyright ? `**Attribution:** ${v.inferredCopyright}\\n` : '';\n\n const base: string = `\n## ${v.name}@${v.version}\n\n**License(s):** ${licenses}\n${repository}${url}${inferredCopyright}\n---\n`;\n const upstream: ReadonlyArray<string> = includeUpstream && v.upstreamNotice ? [`**Upstream NOTICE:**`, ...v.upstreamNotice.split(/\\r?\\n/).map((ln) => `> ${ln}`), ``] : [];\n return [base, ...upstream];\n });\n\n const footer: string = `\n ## 2) General OSS Acknowledgment\n\nThis product incorporates open-source software. **If any term of this file or the EULA conflicts with an OSS license for a specific component, the OSS license controls for that component.**\n`;\n\n return entries.length !== 0 ? [header, subHeader, ...blocks.flat(), footer].join('') : [header, noRecordsNote].join('');\n }\n\n async function generate(): Promise<void> {\n // eslint-disable-next-line spellcheck/spell-checker\n const argv = await yargs(hideBin(process.argv))\n .scriptName('anarchy-legal:notice')\n .usage('$0 --workspace <name|path> [--source <path>] [--source-name <file>] [--out <NOTICE.md>] [--include-upstream-notices] [--max-upstream-notice-kb <N>] [--audit] [--strict] [--debug]')\n .option('workspace', { type: 'string', demandOption: true, describe: 'Target workspace (name or path relative to monorepo root)' })\n .option('source', { type: 'string', describe: 'Path to the input attribution file (default is <workspace>/<source-name>)' })\n .option('source-name', { type: 'string', default: 'THIRD_PARTY_LICENSES.md', describe: 'File name inside the workspace to read from when --source is not provided' })\n .option('out', { type: 'string', describe: 'Path to output NOTICE.md. Default: <workspace>/NOTICE.md' })\n .option('include-upstream-notices', { type: 'boolean', default: false, describe: 'Also read upstream NOTICE files from dependency install paths (if present in source)' })\n .option('max-upstream-notice-kb', { type: 'number', default: 128, describe: 'Max size per upstream NOTICE to read (kilobytes)' })\n .option('audit', { type: 'boolean', default: false, describe: 'Print a diff between headings in source and parsed entries' })\n .option('strict', { type: 'boolean', default: false, describe: 'With --audit, exit with code 2 if mismatches found' })\n .option('debug', { type: 'boolean', default: false })\n .help()\n .parseAsync();\n\n isDebug = Boolean(argv.debug);\n repoUtilsService.setDebugMode(isDebug);\n\n // Locate monorepo root\n const scriptDir: string = path.dirname(fileURLToPath(import.meta.url));\n const startCandidates = [process.env.INIT_CWD, process.cwd(), scriptDir].filter(Boolean) as string[];\n const rootDir: string | undefined = await startCandidates.reduce<Promise<string | undefined>>(async (accP: Promise<string | undefined>, c: string): Promise<string | undefined> => {\n const acc: string | undefined = await accP;\n if (acc) return acc;\n try {\n return await findMonorepoRoot(c);\n } catch (e) {\n debugLog(isDebug, 'no root from', c, ':', (e as Error).message);\n return undefined;\n }\n }, Promise.resolve(undefined));\n if (!rootDir) throw new Error(`Failed to find monorepo root from: ${startCandidates.join(', ')}`);\n\n // Workspaces\n const workspaces: ReadonlyMap<string, TWorkspaceInfo> = await loadWorkspaces(rootDir);\n const ws: TWorkspaceInfo = await resolveWorkspaceFromArg(String(argv.workspace), workspaces, rootDir);\n debugLog(isDebug, 'target workspace:', ws.name, ws.dir);\n\n // Source & Out paths\n const sourceName: string = String(argv['source-name'] || 'THIRD_PARTY_LICENSES.md');\n const defaultSource: string = path.join(ws.dir, sourceName);\n const srcPath: string = argv.source ? (path.isAbsolute(argv.source) ? argv.source : path.resolve(process.cwd(), argv.source)) : defaultSource;\n const outPath: string = argv.out ? (path.isAbsolute(argv.out) ? argv.out : path.resolve(process.cwd(), argv.out)) : path.join(ws.dir, 'NOTICE.md');\n\n debugLog(isDebug, 'source:', srcPath);\n debugLog(isDebug, 'out:', outPath);\n\n if (!(await isExist(srcPath))) {\n console.error(`Source file not found: ${srcPath}`);\n process.exit(1);\n }\n\n const src: string = await fs.readFile(srcPath, 'utf8');\n\n // collect declared ids from headings for audit\n const declaredIds: ReadonlySet<string> = collectAllHeadingIds(src);\n\n const entries = parseThirdPartyMarkdown(src);\n debugLog(isDebug, 'parsed entries:', entries.length);\n\n // Optional upstream NOTICE load\n const finalEntries: ReadonlyArray<TTemplateParsedEntry> = await (async (): Promise<ReadonlyArray<TTemplateParsedEntry>> => {\n if (!argv['include-upstream-notices']) return entries;\n const maxBytes: number = Math.max(1, Math.floor(Number(argv['max-upstream-notice-kb']) || 128)) * 1024;\n const withUpstream = await Promise.all(\n entries.map(async (e: TTemplateParsedEntry) => {\n if (!e.path) return e;\n const u: string | undefined = await loadUpstreamNotice(e.path, maxBytes);\n return u ? { ...e, upstreamNotice: u } : e;\n })\n );\n const filledCount: number = withUpstream.filter((e): boolean => Boolean(e.upstreamNotice)).length;\n debugLog(isDebug, 'upstream notices loaded:', filledCount);\n return withUpstream;\n })();\n\n // Audit report\n if (argv.audit) {\n const parsedIds = new Set(finalEntries.map((e: TTemplateParsedEntry): string => e.id));\n const missing: ReadonlyArray<string> = Array.from(declaredIds)\n .filter((id: string): boolean => !parsedIds.has(id))\n .toSorted();\n\n console.log(`NOTICE audit:\n headings in source: ${declaredIds.size}\n parsed entries: ${parsedIds.size}\n missing in NOTICE: ${missing.length}`);\n\n if (missing.length) {\n console.log(missing.map((x: string): string => ` - ${x}`).join('\\n'));\n if (argv.strict) {\n console.error('Audit failed: some entries were not parsed into NOTICE.');\n process.exit(2);\n }\n } else {\n console.log('Audit OK: all entries accounted for.');\n }\n }\n\n const md: string = renderNotice(ws.name, entries, Boolean(argv['include-upstream-notices']), sourceName);\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, md, 'utf8');\n console.log(`NOTICE.md written -> ${outPath}`);\n }\n\n return { generate };\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"NoticeUtilsService.js","sources":["../../src/Services/NoticeUtilsService.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type { TNoticeUtilsService, TTemplateParsedEntry } from '@Anarchy/Legal/Models';\n\nexport function NoticeUtilsService(): TNoticeUtilsService {\n function splitEntriesFromMarkdown(md: string): ReadonlyArray<string> {\n const parts: string[] = md.split(/\\r?\\n---\\r?\\n/g);\n return parts.filter((chunk) => /^##\\s+.+/m.test(chunk));\n }\n\n function parseHeaderLine(chunk: string): { name: string; version: string } | undefined {\n const m: RegExpExecArray | null = /^##\\s+(.+?)\\s*$/m.exec(chunk);\n if (!m) return undefined;\n const full: string = m[1].trim(); // e.g. \"@babel/core@7.27.1\"\n const at: number = full.lastIndexOf('@');\n if (at <= 0 || at === full.length - 1) return undefined;\n const name: string = full.slice(0, at).trim();\n const version: string = full.slice(at + 1).trim();\n if (!name || !version) return undefined;\n return { name, version };\n }\n\n function parseOneEntry(chunk: string): TTemplateParsedEntry | undefined {\n const header: { name: string; version: string } | undefined = parseHeaderLine(chunk);\n if (!header) return undefined;\n const { name, version } = header;\n const id = `${name}@${version}`;\n\n const field = (label: string): string | undefined => {\n const re = new RegExp(`^\\\\*\\\\*${label}:\\\\*\\\\*\\\\s*(.+)\\\\s*$`, 'mi');\n const m: RegExpExecArray | null = re.exec(chunk);\n return m ? m[1].trim() : undefined;\n };\n\n const licensesStr: string = field('License') ?? 'UNKNOWN';\n const licenses: string[] = licensesStr\n .split(',')\n .map((s: string): string => s.trim())\n .filter(Boolean);\n\n const repository: string | undefined = field('Repository');\n const url: string | undefined = field('URL');\n const publisher = field('Publisher')\n ?.replace(/\\s+<[^>]+>\\s*$/, '')\n .trim();\n const path: string | undefined = field('Path');\n\n // License text: tail after the first blank line following the header+KV area\n let licenseText: string | undefined = undefined;\n {\n const lines: string[] = chunk.split(/\\r?\\n/);\n const firstBlankAfterHeaderIdx: number = ((): number => {\n let seenHeader: boolean = false;\n return lines.findIndex((ln: string): boolean => {\n if (ln.startsWith('## ')) {\n seenHeader = true;\n return false;\n }\n return seenHeader && ln.trim() === '';\n });\n })();\n const startIdx: number = firstBlankAfterHeaderIdx >= 0 ? firstBlankAfterHeaderIdx + 1 : lines.length;\n const tail: string = lines.slice(startIdx).join('\\n').trim();\n if (tail && !/^_No license text file found;/m.test(tail)) licenseText = tail;\n }\n\n const inferredCopyright: string | undefined = ((): string | undefined => {\n if (licenseText) {\n const ln: string | undefined = licenseText.split(/\\r?\\n/).find((l: string): boolean => /^\\s*(?:copyright|\\(c\\)|©)\\s+/i.test(l));\n if (ln) return ln.trim();\n }\n return publisher?.trim();\n })();\n\n return {\n id,\n name,\n version,\n licenses,\n repository: repository ?? undefined,\n url: url ?? undefined,\n publisher: publisher ?? undefined,\n path: path ?? undefined,\n licenseText,\n inferredCopyright\n };\n }\n\n function parseThirdPartyMarkdown(md: string): ReadonlyArray<TTemplateParsedEntry> {\n const chunks: ReadonlyArray<string> = splitEntriesFromMarkdown(md);\n const entries: TTemplateParsedEntry[] = chunks.flatMap((ch) => {\n const e: TTemplateParsedEntry | undefined = parseOneEntry(ch);\n return e ? [e] : [];\n });\n return entries.toSorted((a, b) => (a.name === b.name ? a.version.localeCompare(b.version) : a.name.localeCompare(b.name)));\n }\n\n function collectAllHeadingIds(md: string): ReadonlySet<string> {\n const re = /^##\\s+(.+?)\\s*$/gm;\n return [...md.matchAll(re)].reduce<Set<string>>((ids: Set<string>, m: RegExpExecArray) => {\n const full: string = String(m[1]).trim();\n const at: number = full.lastIndexOf('@');\n if (at > 0 && at < full.length - 1) {\n ids.add(`${full.slice(0, at).trim()}@${full.slice(at + 1).trim()}`);\n }\n return ids;\n }, new Set<string>());\n }\n\n async function findUpstreamNoticeFile(dir: string): Promise<string | undefined> {\n try {\n const list: string[] = await fs.readdir(dir);\n const candidate = list.find((f) => /^(notice|notice\\.txt|notice\\.md)$/i.test(f));\n return candidate ? path.join(dir, candidate) : undefined;\n } catch {\n return undefined;\n }\n }\n\n async function loadUpstreamNotice(dir: string, maxBytes: number): Promise<string | undefined> {\n const p = await findUpstreamNoticeFile(dir);\n if (!p) return undefined;\n try {\n const stat = await fs.stat(p);\n const text: string = await fs.readFile(p, 'utf8');\n if (stat.size > maxBytes) {\n return `Upstream NOTICE is too large (${stat.size} bytes); truncated.\\n\\n` + text.slice(0, maxBytes);\n }\n return text;\n } catch {\n return undefined;\n }\n }\n\n return {\n collectAllHeadingIds,\n loadUpstreamNotice,\n parseThirdPartyMarkdown\n };\n}\n"],"names":["path"],"mappings":"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"}
1
+ {"version":3,"file":"NoticeUtilsService.js","sources":["../../src/Services/NoticeUtilsService.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type { TNoticeUtilsService, TTemplateParsedEntry } from '@hellpig/anarchy-legal/Models';\n\nexport function NoticeUtilsService(): TNoticeUtilsService {\n function splitEntriesFromMarkdown(md: string): ReadonlyArray<string> {\n const parts: string[] = md.split(/\\r?\\n---\\r?\\n/g);\n return parts.filter((chunk) => /^##\\s+.+/m.test(chunk));\n }\n\n function parseHeaderLine(chunk: string): { name: string; version: string } | undefined {\n const m: RegExpExecArray | null = /^##\\s+(.+?)\\s*$/m.exec(chunk);\n if (!m) return undefined;\n const full: string = m[1].trim(); // e.g. \"@babel/core@7.27.1\"\n const at: number = full.lastIndexOf('@');\n if (at <= 0 || at === full.length - 1) return undefined;\n const name: string = full.slice(0, at).trim();\n const version: string = full.slice(at + 1).trim();\n if (!name || !version) return undefined;\n return { name, version };\n }\n\n function parseOneEntry(chunk: string): TTemplateParsedEntry | undefined {\n const header: { name: string; version: string } | undefined = parseHeaderLine(chunk);\n if (!header) return undefined;\n const { name, version } = header;\n const id = `${name}@${version}`;\n\n const field = (label: string): string | undefined => {\n const re = new RegExp(`^\\\\*\\\\*${label}:\\\\*\\\\*\\\\s*(.+)\\\\s*$`, 'mi');\n const m: RegExpExecArray | null = re.exec(chunk);\n return m ? m[1].trim() : undefined;\n };\n\n const licensesStr: string = field('License') ?? 'UNKNOWN';\n const licenses: string[] = licensesStr\n .split(',')\n .map((s: string): string => s.trim())\n .filter(Boolean);\n\n const repository: string | undefined = field('Repository');\n const url: string | undefined = field('URL');\n const publisher = field('Publisher')\n ?.replace(/\\s+<[^>]+>\\s*$/, '')\n .trim();\n const path: string | undefined = field('Path');\n\n // License text: tail after the first blank line following the header+KV area\n let licenseText: string | undefined = undefined;\n {\n const lines: string[] = chunk.split(/\\r?\\n/);\n const firstBlankAfterHeaderIdx: number = ((): number => {\n let seenHeader: boolean = false;\n return lines.findIndex((ln: string): boolean => {\n if (ln.startsWith('## ')) {\n seenHeader = true;\n return false;\n }\n return seenHeader && ln.trim() === '';\n });\n })();\n const startIdx: number = firstBlankAfterHeaderIdx >= 0 ? firstBlankAfterHeaderIdx + 1 : lines.length;\n const tail: string = lines.slice(startIdx).join('\\n').trim();\n if (tail && !/^_No license text file found;/m.test(tail)) licenseText = tail;\n }\n\n const inferredCopyright: string | undefined = ((): string | undefined => {\n if (licenseText) {\n const ln: string | undefined = licenseText.split(/\\r?\\n/).find((l: string): boolean => /^\\s*(?:copyright|\\(c\\)|©)\\s+/i.test(l));\n if (ln) return ln.trim();\n }\n return publisher?.trim();\n })();\n\n return {\n id,\n name,\n version,\n licenses,\n repository: repository ?? undefined,\n url: url ?? undefined,\n publisher: publisher ?? undefined,\n path: path ?? undefined,\n licenseText,\n inferredCopyright\n };\n }\n\n function parseThirdPartyMarkdown(md: string): ReadonlyArray<TTemplateParsedEntry> {\n const chunks: ReadonlyArray<string> = splitEntriesFromMarkdown(md);\n const entries: TTemplateParsedEntry[] = chunks.flatMap((ch) => {\n const e: TTemplateParsedEntry | undefined = parseOneEntry(ch);\n return e ? [e] : [];\n });\n return entries.toSorted((a, b) => (a.name === b.name ? a.version.localeCompare(b.version) : a.name.localeCompare(b.name)));\n }\n\n function collectAllHeadingIds(md: string): ReadonlySet<string> {\n const re = /^##\\s+(.+?)\\s*$/gm;\n return [...md.matchAll(re)].reduce<Set<string>>((ids: Set<string>, m: RegExpExecArray) => {\n const full: string = String(m[1]).trim();\n const at: number = full.lastIndexOf('@');\n if (at > 0 && at < full.length - 1) {\n ids.add(`${full.slice(0, at).trim()}@${full.slice(at + 1).trim()}`);\n }\n return ids;\n }, new Set<string>());\n }\n\n async function findUpstreamNoticeFile(dir: string): Promise<string | undefined> {\n try {\n const list: string[] = await fs.readdir(dir);\n const candidate = list.find((f) => /^(notice|notice\\.txt|notice\\.md)$/i.test(f));\n return candidate ? path.join(dir, candidate) : undefined;\n } catch {\n return undefined;\n }\n }\n\n async function loadUpstreamNotice(dir: string, maxBytes: number): Promise<string | undefined> {\n const p = await findUpstreamNoticeFile(dir);\n if (!p) return undefined;\n try {\n const stat = await fs.stat(p);\n const text: string = await fs.readFile(p, 'utf8');\n if (stat.size > maxBytes) {\n return `Upstream NOTICE is too large (${stat.size} bytes); truncated.\\n\\n` + text.slice(0, maxBytes);\n }\n return text;\n } catch {\n return undefined;\n }\n }\n\n return {\n collectAllHeadingIds,\n loadUpstreamNotice,\n parseThirdPartyMarkdown\n };\n}\n"],"names":["path"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"RepoUtilsService.js","sources":["../../src/Services/RepoUtilsService.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\n\nimport type { TCollected, TDependencyNode, TLicenseEntry, TRepoUtilsService, TRootInfo, TWorkspaceInfo } from '@Anarchy/Legal/Models';\n// eslint-disable-next-line spellcheck/spell-checker\nimport { globby } from 'globby';\n\nexport function RepoUtilsService(): TRepoUtilsService {\n let isDebug: boolean = false;\n\n const setDebugMode = (debug: boolean): void => void (isDebug = debug);\n\n const readJson = async <T extends Record<string, unknown>>(p: string): Promise<T> => JSON.parse(await fs.readFile(p, 'utf8')) as T;\n\n const isExist = async (p: string): Promise<boolean> => {\n try {\n await fs.access(p);\n return true;\n } catch {\n return false;\n }\n };\n\n function debugLog(isDebug: boolean, ...args: ReadonlyArray<unknown>): void {\n if (isDebug) console.log('[debug]', ...args);\n }\n\n function hasWorkspacesField(pkg: any): boolean {\n const ws = pkg?.workspaces;\n if (!ws) return false;\n if (Array.isArray(ws)) return ws.length > 0;\n if (typeof ws === 'object' && Array.isArray(ws.packages)) return ws.packages.length > 0;\n return false;\n }\n\n async function loadWorkspaces(rootDir: string): Promise<ReadonlyMap<string, TWorkspaceInfo>> {\n const rootPkg = await readJson<any>(path.join(rootDir, 'package.json'));\n const patterns: string[] = Array.isArray(rootPkg.workspaces) ? rootPkg.workspaces : (rootPkg.workspaces?.packages ?? []);\n if (!patterns.length) throw new Error(`No workspaces patterns in ${path.join(rootDir, 'package.json')}`);\n // eslint-disable-next-line spellcheck/spell-checker\n const dirs: string[] = await globby(patterns, {\n cwd: rootDir,\n absolute: true,\n onlyDirectories: true,\n gitignore: true,\n ignore: ['**/node_modules/**', '**/dist/**', '**/dist-*/**', '**/.*/**']\n });\n const entries = (\n await Promise.all(\n dirs.map(async (dir): Promise<[string, TWorkspaceInfo] | undefined> => {\n const pkgPath: string = path.join(dir, 'package.json');\n if (!(await isExist(pkgPath))) return undefined;\n const pkg = await readJson<{\n name: string;\n version?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n }>(pkgPath);\n const name: string | undefined = typeof pkg.name === 'string' ? pkg.name : undefined;\n return name ? ([name, { name, dir, pkgPath, pkg }] as const) : undefined;\n })\n )\n ).filter(Boolean) as Array<[string, TWorkspaceInfo]>;\n return new Map(entries);\n }\n\n async function findMonorepoRoot(startDir: string): Promise<string> {\n const start: string = path.resolve(startDir);\n debugLog(isDebug, 'findMonorepoRoot: start at', start);\n\n const searchUp = async (dir: string, depth: number): Promise<string | undefined> => {\n if (depth > 50) return undefined;\n const pkgPath: string = path.join(dir, 'package.json');\n debugLog(isDebug, 'check', pkgPath);\n if (await isExist(pkgPath)) {\n try {\n const pkg = await readJson<any>(pkgPath);\n if (hasWorkspacesField(pkg)) {\n debugLog(isDebug, 'found workspaces at', pkgPath);\n return dir;\n }\n } catch (e) {\n debugLog(isDebug, ' ! failed to parse', pkgPath, '-', (e as Error).message);\n }\n }\n const parent: string = path.dirname(dir);\n if (parent === dir) return undefined;\n return searchUp(parent, depth + 1);\n };\n\n const found: string | undefined = await searchUp(start, 0);\n if (!found) throw new Error(`Monorepo root not found starting from \"${startDir}\". Provide --root explicitly pointing to a package.json with \"workspaces\".`);\n return found;\n }\n\n async function loadRoot(rootDir: string): Promise<TRootInfo> {\n const rootPkgPath: string = path.join(rootDir, 'package.json');\n if (!(await isExist(rootPkgPath))) throw new Error(`Root package.json not found at: ${rootPkgPath}`);\n\n const rootPkg: TRootInfo['rootPkg'] = await readJson<TRootInfo['rootPkg']>(rootPkgPath);\n const wsField = rootPkg.workspaces;\n if (!wsField) throw new Error(`\"workspaces\" not found in root package.json at ${rootPkgPath}`);\n\n const patterns: ReadonlyArray<string> = Array.isArray(wsField) ? wsField : ((wsField as any).packages ?? []);\n if (patterns.length === 0) throw new Error(`\"workspaces\" has no packages in ${rootPkgPath}`);\n\n debugLog(isDebug, 'workspaces patterns:', patterns);\n\n // eslint-disable-next-line spellcheck/spell-checker\n const dirs: ReadonlyArray<string> = await globby(patterns, {\n cwd: rootDir,\n onlyDirectories: true,\n absolute: true,\n expandDirectories: false,\n gitignore: true,\n ignore: ['**/node_modules/**', '**/dist/**', '**/dist-*/**', '**/.*/**']\n });\n\n debugLog(isDebug, 'workspace dirs found:', dirs.length);\n\n const entries: Array<[string, TWorkspaceInfo]> = (\n await Promise.all(\n dirs.map(async (dir: string): Promise<[string, TWorkspaceInfo] | undefined> => {\n const pkgPath: string = path.join(dir, 'package.json');\n if (!(await isExist(pkgPath))) return undefined;\n const pkg = await readJson<TWorkspaceInfo['pkg']>(pkgPath);\n if (!pkg.name) return undefined;\n return [\n pkg.name,\n {\n name: pkg.name,\n dir,\n pkgPath,\n pkg\n }\n ];\n })\n )\n ).filter(Boolean) as Array<[string, TWorkspaceInfo]>;\n\n debugLog(isDebug, 'workspace packages loaded:', entries.length);\n\n if (entries.length === 0) throw new Error(`No workspace package.json files found by patterns: ${patterns.join(', ')}`);\n\n return {\n rootDir,\n rootPkgPath,\n rootPkg,\n workspaces: new Map(entries)\n };\n }\n\n function buildWsGraph(ws: ReadonlyMap<string, TWorkspaceInfo>): ReadonlyMap<string, ReadonlySet<string>> {\n const names: Set<string> = new Set(ws.keys());\n const graph = Array.from(ws.entries()).reduce((acc, [name, info]) => {\n const deps: Record<string, string> = info.pkg.dependencies ?? {};\n const edges: Set<string> = new Set<string>(Object.keys(deps).filter((dependencyName) => names.has(dependencyName)));\n acc.set(name, edges);\n return acc;\n }, new Map<string, ReadonlySet<string>>());\n\n if (isDebug) {\n console.log('[debug] workspace graph:');\n graph.forEach((v: ReadonlySet<string>, k: string) => console.log(' ', k, '->', [...v].join(', ') || '∅'));\n }\n return graph;\n }\n\n function assertNoCycles(graph: ReadonlyMap<string, ReadonlySet<string>>, start: string): void {\n const temp: Set<string> = new Set<string>();\n const perm: Set<string> = new Set<string>();\n let pathStack: ReadonlyArray<string> = [];\n\n // eslint-disable-next-line spellcheck/spell-checker\n const dfs = (u: string): void => {\n if (perm.has(u)) return;\n if (temp.has(u)) {\n const idx: number = pathStack.lastIndexOf(u);\n const cyclePath: string = [...pathStack.slice(idx), u].join(' -> ');\n throw new Error(`Cycle detected between workspaces (prod deps): ${cyclePath}`);\n }\n temp.add(u);\n pathStack = [...pathStack];\n // eslint-disable-next-line spellcheck/spell-checker\n (graph.get(u) ?? new Set<string>()).forEach(dfs);\n pathStack = pathStack.slice(0, pathStack.length - 1);\n temp.delete(u);\n perm.add(u);\n };\n\n // eslint-disable-next-line spellcheck/spell-checker\n dfs(start);\n }\n\n function collectWorkspaceClosure(graph: ReadonlyMap<string, ReadonlySet<string>>, start: string): ReadonlySet<string> {\n const visited: Set<string> = new Set<string>();\n\n const visit = (u: string): void => {\n if (visited.has(u)) return;\n visited.add(u);\n (graph.get(u) ?? new Set<string>()).forEach(visit);\n };\n\n visit(start);\n return visited;\n }\n\n async function npmLsJson(rootDir: string, workspace: string): Promise<TDependencyNode | undefined> {\n return new Promise((resolve, reject): void => {\n const args: ReadonlyArray<string> = ['ls', '-w', workspace, '--json', '--omit=dev', '--all', '--long'];\n debugLog(isDebug, 'spawn:', 'npm', args.join(' '), 'cwd:', rootDir);\n const child = spawn('npm', args, { cwd: rootDir, stdio: ['ignore', 'pipe', 'pipe'] });\n let out: string = '';\n let err: string = '';\n child.stdout.on('data', (d) => (out += String(d)));\n child.stderr.on('data', (d) => (err += String(d)));\n child.on('close', (code: number | null): void => {\n if (code !== 0 && !out) return reject(new Error(`npm ls failed (code ${code}): ${err || 'unknown error'}`));\n\n try {\n const json = JSON.parse(out) as any;\n const normPath = (o: any): string | undefined =>\n // eslint-disable-next-line spellcheck/spell-checker\n typeof o?.path === 'string' ? o.path : typeof o?.realpath === 'string' ? o.realpath : typeof o?.location === 'string' ? (path.isAbsolute(o.location) ? o.location : undefined) : undefined;\n\n const toNode = (name: string, o: any): TDependencyNode => ({\n name,\n version: typeof o?.version === 'string' ? o.version : '0.0.0',\n path: normPath(o),\n license: o?.license,\n repository: o?.repository,\n dependencies: o?.dependencies ? Object.fromEntries(Object.entries(o.dependencies).map(([k, v]) => [k, toNode(k, v)])) : undefined\n });\n\n const rootNode: TDependencyNode = {\n name: json?.name ?? workspace,\n version: json?.version ?? '0.0.0',\n path: normPath(json),\n license: json?.license,\n repository: json?.repository,\n dependencies: json?.dependencies ? Object.fromEntries(Object.entries(json.dependencies).map(([k, v]) => [k, toNode(k, v)])) : undefined\n };\n debugLog(isDebug, 'npm ls parsed root:', rootNode.name, rootNode.version);\n return resolve(rootNode);\n } catch (e) {\n return reject(new Error(`Failed to parse npm ls JSON: ${(e as Error).message}\\nRaw: ${out.slice(0, 2000)}`));\n }\n });\n });\n }\n\n function collectExternalSeedNames(closure: ReadonlySet<string>, wsMap: ReadonlyMap<string, TWorkspaceInfo>, wsNames: ReadonlySet<string>): ReadonlySet<string> {\n const seeds: Set<string> = new Set<string>();\n [...closure].forEach((wsName: string): void => {\n const info: TWorkspaceInfo | undefined = wsMap.get(wsName);\n if (!info) return;\n const deps: Record<string, string> = info.pkg.dependencies ?? {};\n Object.keys(deps).forEach((dependencyName: string): void => {\n if (!wsNames.has(dependencyName)) seeds.add(dependencyName);\n });\n });\n return seeds;\n }\n\n function collectThirdPartyMap(root: TDependencyNode | undefined, wsNames: ReadonlySet<string>, seedNames: ReadonlySet<string>): ReadonlyMap<string, TCollected> {\n const acc: Map<string, TCollected> = new Map<string, TCollected>();\n if (!root || !root.dependencies) return acc;\n if (seedNames.size === 0) return acc;\n\n const visit = (node: TDependencyNode, inside: boolean): void => {\n const isWs: boolean = wsNames.has(node.name);\n const nowInside: boolean = inside || seedNames.has(node.name);\n\n if (nowInside && !isWs && node.version && node.version !== '0.0.0') {\n const id: string = `${node.name}@${node.version}`;\n const prev: TCollected | undefined = acc.get(id);\n const installPath: string | undefined = node.path;\n if (!prev) acc.set(id, { id, name: node.name, version: node.version, installPath });\n else if (!prev.installPath && installPath) acc.set(id, { ...prev, installPath });\n }\n if (node.dependencies) Object.values(node.dependencies).forEach((child) => visit(child, nowInside));\n };\n\n Object.values(root.dependencies).forEach((child: TDependencyNode) => visit(child, false));\n\n debugLog(isDebug, 'third-party collected (seed-filtered):', acc.size);\n return acc;\n }\n\n function resolvePackageDir(pkgName: string, fromDir: string): string | undefined {\n try {\n const req: NodeJS.Require = createRequire(path.join(fromDir, 'package.json'));\n const p: string = req.resolve(`${pkgName}/package.json`);\n return path.dirname(p);\n } catch {\n return undefined;\n }\n }\n\n function fillMissingInstallPaths(collected: Map<string, TCollected>, wsDir: string, rootDir: string): void {\n let filled: number = 0;\n Array.from(collected.entries()).forEach(([id, item]): void => {\n if (!item.installPath) {\n const p: string | undefined = resolvePackageDir(item.name, wsDir) ?? resolvePackageDir(item.name, rootDir);\n if (p) {\n collected.set(id, { ...item, installPath: p });\n filled++;\n }\n }\n });\n debugLog(isDebug, 'install paths filled via resolver:', filled);\n }\n\n async function findLicenseFile(dir: string): Promise<string | undefined> {\n try {\n const list: Array<string> = await fs.readdir(dir);\n const c: string | undefined = list.find((f: string) => {\n const base: string = f.toLowerCase();\n return /^(license|licence|copying|unlicense|notice)(\\..+)?$/.test(base);\n });\n return c ? path.join(dir, c) : undefined;\n } catch {\n return undefined;\n }\n }\n\n function parseSeeLicenseIn(licenseField: unknown): string | undefined {\n if (!licenseField) return undefined;\n const s = typeof licenseField === 'string' ? licenseField : typeof (licenseField as any)?.type === 'string' ? (licenseField as any).type : undefined;\n if (!s) return undefined;\n const m: RegExpExecArray | null = /see\\s+license\\s+in\\s+(.+)$/i.exec(s);\n return m?.[1]?.trim();\n }\n\n async function tryReadLicenseText(pkgDir: string, licenseField: unknown): Promise<string | undefined> {\n const see: string | undefined = parseSeeLicenseIn(licenseField);\n if (see) {\n const p: string = path.join(pkgDir, see);\n if (await isExist(p)) {\n try {\n return await fs.readFile(p, 'utf8');\n } catch {\n /* ignore */\n }\n }\n }\n const license: string | undefined = await findLicenseFile(pkgDir);\n if (license) {\n try {\n return await fs.readFile(license, 'utf8');\n } catch {\n /* ignore */\n }\n }\n return undefined;\n }\n\n const safeString = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined);\n\n function normalizeLicenseValue(licenseField: unknown): string | ReadonlyArray<string> {\n if (!licenseField) return 'UNKNOWN';\n if (typeof licenseField === 'string') return licenseField;\n if (Array.isArray(licenseField)) {\n const arr: any[] = (licenseField as any[]).map((x) => (typeof x === 'string' ? x : typeof (x as any)?.type === 'string' ? (x as any).type : 'UNKNOWN'));\n return arr.length > 0 ? arr : 'UNKNOWN';\n }\n if (typeof licenseField === 'object') {\n const t = (licenseField as any)?.type;\n if (typeof t === 'string') return t;\n }\n return 'UNKNOWN';\n }\n\n async function readPackageMeta(pkgDir: string): Promise<{\n licenseField?: unknown;\n repository?: string;\n publisher?: string;\n email?: string;\n url?: string;\n }> {\n try {\n const pkg = await readJson<any>(path.join(pkgDir, 'package.json'));\n const repo = typeof pkg.repository === 'string' ? pkg.repository : typeof pkg.repository?.url === 'string' ? pkg.repository.url : undefined;\n return {\n licenseField: pkg.license ?? pkg.licenses,\n repository: repo,\n publisher: safeString(pkg.author?.name) ?? safeString(pkg.author) ?? undefined,\n email: safeString(pkg.author?.email) ?? undefined,\n url: safeString(pkg.homepage) ?? undefined\n };\n } catch {\n return {};\n }\n }\n\n async function buildLicenseEntries(collected: ReadonlyMap<string, TCollected>): Promise<ReadonlyArray<TLicenseEntry>> {\n const list = await Promise.all(\n Array.from(collected.values()).map(async ({ id, name, version, installPath }) => {\n let licenseText: string | undefined;\n let licenseType: string | ReadonlyArray<string> | undefined = 'UNKNOWN';\n let repository: string | undefined;\n let publisher: string | undefined;\n let email: string | undefined;\n let url: string | undefined;\n\n if (installPath) {\n const meta = await readPackageMeta(installPath);\n licenseType = normalizeLicenseValue(meta.licenseField);\n repository = meta.repository;\n publisher = meta.publisher;\n email = meta.email;\n url = meta.url;\n\n licenseText = await tryReadLicenseText(installPath, meta.licenseField);\n }\n\n return {\n id,\n name,\n version,\n licenses: licenseType as any,\n licenseText,\n repository,\n publisher,\n email,\n url,\n path: installPath\n } satisfies TLicenseEntry;\n })\n );\n\n return [...list].sort((a, b): number => (a.name === b.name ? a.version.localeCompare(b.version) : a.name.localeCompare(b.name)));\n }\n\n async function buildWorkspaceLicenseEntries(names: ReadonlySet<string>, wsMap: ReadonlyMap<string, TWorkspaceInfo>, excludeName?: string): Promise<ReadonlyArray<TLicenseEntry>> {\n const filtered: any[] = [...names].filter((name) => !(excludeName && name === excludeName));\n const entries = await Promise.all(\n filtered\n .map((name: string) => wsMap.get(name))\n // eslint-disable-next-line functional/prefer-tacit\n .filter((info: TWorkspaceInfo | undefined): info is TWorkspaceInfo => Boolean(info))\n .map(async (info) => {\n const version: string = info.pkg.version ?? '0.0.0';\n const meta = await readPackageMeta(info.dir);\n const licenseType: string | ReadonlyArray<string> = normalizeLicenseValue(meta.licenseField);\n const licenseText: string | undefined = await tryReadLicenseText(info.dir, meta.licenseField);\n return {\n id: `${info.name}@${version}`,\n name: info.name,\n version,\n licenses: licenseType,\n licenseText,\n repository: meta.repository,\n publisher: meta.publisher,\n email: meta.email,\n url: meta.url,\n path: info.dir\n } satisfies TLicenseEntry;\n })\n );\n return [...entries].sort((a, b): number => (a.name === b.name ? a.version.localeCompare(b.version) : a.name.localeCompare(b.name)));\n }\n\n function renderMarkdown(workspaceLabel: string, items: ReadonlyArray<TLicenseEntry>, emptyNote?: string): string {\n const header: ReadonlyArray<string> = [`# Third-Party Licenses`, `## Application: ${workspaceLabel}`, `Production dependencies (including transition dependencies): ${items.length}`, ``];\n const note: ReadonlyArray<string> = items.length === 0 && emptyNote ? [`**Note:** ${emptyNote}`, ``] : [];\n\n const body: ReadonlyArray<string> = items.flatMap((it) => {\n const licenseStr: string = Array.isArray(it.licenses) ? it.licenses.join(', ') : String(it.licenses ?? 'UNKNOWN');\n return [\n `---`,\n ``,\n `## ${it.name}@${it.version}`,\n `**License:** ${licenseStr}\\n`,\n ...(it.repository ? [`**Repository:** ${it.repository}\\n`] : []),\n ...(it.url ? [`**URL:** ${it.url}\\n`] : []),\n ...(it.publisher ? [`**Publisher:** ${it.publisher}${it.email ? ` <${it.email}>` : ''}\\n`] : []),\n ``,\n ...(it.licenseText ? [it.licenseText.trim(), ``] : [`_No license text file found; relying on package metadata._`, ``])\n ];\n });\n\n return [...header, ...note, ...body].join('\\n');\n }\n\n async function resolveWorkspaceFromArg(arg: string, workspaces: ReadonlyMap<string, TWorkspaceInfo>, rootDir: string): Promise<TWorkspaceInfo> {\n const byName: TWorkspaceInfo | undefined = workspaces.get(arg);\n if (byName) return byName;\n\n // as path relative to monorepo root\n const asPath: string = path.isAbsolute(arg) ? arg : path.join(rootDir, arg);\n const norm: string = path.resolve(asPath);\n\n // match any known workspace by directory\n const found: TWorkspaceInfo | undefined = [...workspaces.values()].find((w: TWorkspaceInfo): boolean => path.resolve(w.dir) === norm);\n if (found) return found;\n\n // NEW: allow selecting the monorepo root itself\n const wantRoot: boolean = norm === path.resolve(rootDir) || arg === ':root' || arg === 'root' || arg === '.';\n\n if (wantRoot) {\n const pkgPath: string = path.join(rootDir, 'package.json');\n const pkg: Record<string, unknown> = await readJson(pkgPath);\n const name: string = typeof pkg.name === 'string' ? pkg.name : 'monorepo-root';\n return { name, dir: rootDir, pkgPath, pkg: pkg as any };\n }\n\n throw new Error(`Workspace \"${arg}\" not found by name or path. Tip: use \"--workspace .\" or \"--workspace :root\" to target the monorepo root.`);\n }\n\n return {\n assertNoCycles,\n buildLicenseEntries,\n buildWorkspaceLicenseEntries,\n buildWsGraph,\n collectExternalSeedNames,\n collectThirdPartyMap,\n collectWorkspaceClosure,\n debugLog,\n fillMissingInstallPaths,\n findMonorepoRoot,\n isDebug: (): boolean => isDebug,\n isExist,\n loadRoot,\n loadWorkspaces,\n npmLsJson,\n readJson,\n renderMarkdown,\n resolveWorkspaceFromArg,\n setDebugMode\n };\n}\n"],"names":["isDebug"],"mappings":"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"}
1
+ {"version":3,"file":"RepoUtilsService.js","sources":["../../src/Services/RepoUtilsService.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\n\nimport type { TCollected, TDependencyNode, TLicenseEntry, TRepoUtilsService, TRootInfo, TWorkspaceInfo } from '@hellpig/anarchy-legal/Models';\n// eslint-disable-next-line spellcheck/spell-checker\nimport { globby } from 'globby';\n\nexport function RepoUtilsService(): TRepoUtilsService {\n let isDebug: boolean = false;\n\n const setDebugMode = (debug: boolean): void => void (isDebug = debug);\n\n const readJson = async <T extends Record<string, unknown>>(p: string): Promise<T> => JSON.parse(await fs.readFile(p, 'utf8')) as T;\n\n const isExist = async (p: string): Promise<boolean> => {\n try {\n await fs.access(p);\n return true;\n } catch {\n return false;\n }\n };\n\n function debugLog(isDebug: boolean, ...args: ReadonlyArray<unknown>): void {\n if (isDebug) console.log('[debug]', ...args);\n }\n\n function hasWorkspacesField(pkg: any): boolean {\n const ws = pkg?.workspaces;\n if (!ws) return false;\n if (Array.isArray(ws)) return ws.length > 0;\n if (typeof ws === 'object' && Array.isArray(ws.packages)) return ws.packages.length > 0;\n return false;\n }\n\n async function loadWorkspaces(rootDir: string): Promise<ReadonlyMap<string, TWorkspaceInfo>> {\n const rootPkg = await readJson<any>(path.join(rootDir, 'package.json'));\n const patterns: string[] = Array.isArray(rootPkg.workspaces) ? rootPkg.workspaces : (rootPkg.workspaces?.packages ?? []);\n if (!patterns.length) throw new Error(`No workspaces patterns in ${path.join(rootDir, 'package.json')}`);\n // eslint-disable-next-line spellcheck/spell-checker\n const dirs: string[] = await globby(patterns, {\n cwd: rootDir,\n absolute: true,\n onlyDirectories: true,\n gitignore: true,\n ignore: ['**/node_modules/**', '**/dist/**', '**/dist-*/**', '**/.*/**']\n });\n const entries = (\n await Promise.all(\n dirs.map(async (dir): Promise<[string, TWorkspaceInfo] | undefined> => {\n const pkgPath: string = path.join(dir, 'package.json');\n if (!(await isExist(pkgPath))) return undefined;\n const pkg = await readJson<{\n name: string;\n version?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n }>(pkgPath);\n const name: string | undefined = typeof pkg.name === 'string' ? pkg.name : undefined;\n return name ? ([name, { name, dir, pkgPath, pkg }] as const) : undefined;\n })\n )\n ).filter(Boolean) as Array<[string, TWorkspaceInfo]>;\n return new Map(entries);\n }\n\n async function findMonorepoRoot(startDir: string): Promise<string> {\n const start: string = path.resolve(startDir);\n debugLog(isDebug, 'findMonorepoRoot: start at', start);\n\n const searchUp = async (dir: string, depth: number): Promise<string | undefined> => {\n if (depth > 50) return undefined;\n const pkgPath: string = path.join(dir, 'package.json');\n debugLog(isDebug, 'check', pkgPath);\n if (await isExist(pkgPath)) {\n try {\n const pkg = await readJson<any>(pkgPath);\n if (hasWorkspacesField(pkg)) {\n debugLog(isDebug, 'found workspaces at', pkgPath);\n return dir;\n }\n } catch (e) {\n debugLog(isDebug, ' ! failed to parse', pkgPath, '-', (e as Error).message);\n }\n }\n const parent: string = path.dirname(dir);\n if (parent === dir) return undefined;\n return searchUp(parent, depth + 1);\n };\n\n const found: string | undefined = await searchUp(start, 0);\n if (!found) throw new Error(`Monorepo root not found starting from \"${startDir}\". Provide --root explicitly pointing to a package.json with \"workspaces\".`);\n return found;\n }\n\n async function loadRoot(rootDir: string): Promise<TRootInfo> {\n const rootPkgPath: string = path.join(rootDir, 'package.json');\n if (!(await isExist(rootPkgPath))) throw new Error(`Root package.json not found at: ${rootPkgPath}`);\n\n const rootPkg: TRootInfo['rootPkg'] = await readJson<TRootInfo['rootPkg']>(rootPkgPath);\n const wsField = rootPkg.workspaces;\n if (!wsField) throw new Error(`\"workspaces\" not found in root package.json at ${rootPkgPath}`);\n\n const patterns: ReadonlyArray<string> = Array.isArray(wsField) ? wsField : ((wsField as any).packages ?? []);\n if (patterns.length === 0) throw new Error(`\"workspaces\" has no packages in ${rootPkgPath}`);\n\n debugLog(isDebug, 'workspaces patterns:', patterns);\n\n // eslint-disable-next-line spellcheck/spell-checker\n const dirs: ReadonlyArray<string> = await globby(patterns, {\n cwd: rootDir,\n onlyDirectories: true,\n absolute: true,\n expandDirectories: false,\n gitignore: true,\n ignore: ['**/node_modules/**', '**/dist/**', '**/dist-*/**', '**/.*/**']\n });\n\n debugLog(isDebug, 'workspace dirs found:', dirs.length);\n\n const entries: Array<[string, TWorkspaceInfo]> = (\n await Promise.all(\n dirs.map(async (dir: string): Promise<[string, TWorkspaceInfo] | undefined> => {\n const pkgPath: string = path.join(dir, 'package.json');\n if (!(await isExist(pkgPath))) return undefined;\n const pkg = await readJson<TWorkspaceInfo['pkg']>(pkgPath);\n if (!pkg.name) return undefined;\n return [\n pkg.name,\n {\n name: pkg.name,\n dir,\n pkgPath,\n pkg\n }\n ];\n })\n )\n ).filter(Boolean) as Array<[string, TWorkspaceInfo]>;\n\n debugLog(isDebug, 'workspace packages loaded:', entries.length);\n\n if (entries.length === 0) throw new Error(`No workspace package.json files found by patterns: ${patterns.join(', ')}`);\n\n return {\n rootDir,\n rootPkgPath,\n rootPkg,\n workspaces: new Map(entries)\n };\n }\n\n function buildWsGraph(ws: ReadonlyMap<string, TWorkspaceInfo>): ReadonlyMap<string, ReadonlySet<string>> {\n const names: Set<string> = new Set(ws.keys());\n const graph = Array.from(ws.entries()).reduce((acc, [name, info]) => {\n const deps: Record<string, string> = info.pkg.dependencies ?? {};\n const edges: Set<string> = new Set<string>(Object.keys(deps).filter((dependencyName) => names.has(dependencyName)));\n acc.set(name, edges);\n return acc;\n }, new Map<string, ReadonlySet<string>>());\n\n if (isDebug) {\n console.log('[debug] workspace graph:');\n graph.forEach((v: ReadonlySet<string>, k: string) => console.log(' ', k, '->', [...v].join(', ') || '∅'));\n }\n return graph;\n }\n\n function assertNoCycles(graph: ReadonlyMap<string, ReadonlySet<string>>, start: string): void {\n const temp: Set<string> = new Set<string>();\n const perm: Set<string> = new Set<string>();\n let pathStack: ReadonlyArray<string> = [];\n\n // eslint-disable-next-line spellcheck/spell-checker\n const dfs = (u: string): void => {\n if (perm.has(u)) return;\n if (temp.has(u)) {\n const idx: number = pathStack.lastIndexOf(u);\n const cyclePath: string = [...pathStack.slice(idx), u].join(' -> ');\n throw new Error(`Cycle detected between workspaces (prod deps): ${cyclePath}`);\n }\n temp.add(u);\n pathStack = [...pathStack];\n // eslint-disable-next-line spellcheck/spell-checker\n (graph.get(u) ?? new Set<string>()).forEach(dfs);\n pathStack = pathStack.slice(0, pathStack.length - 1);\n temp.delete(u);\n perm.add(u);\n };\n\n // eslint-disable-next-line spellcheck/spell-checker\n dfs(start);\n }\n\n function collectWorkspaceClosure(graph: ReadonlyMap<string, ReadonlySet<string>>, start: string): ReadonlySet<string> {\n const visited: Set<string> = new Set<string>();\n\n const visit = (u: string): void => {\n if (visited.has(u)) return;\n visited.add(u);\n (graph.get(u) ?? new Set<string>()).forEach(visit);\n };\n\n visit(start);\n return visited;\n }\n\n async function npmLsJson(rootDir: string, workspace: string): Promise<TDependencyNode | undefined> {\n return new Promise((resolve, reject): void => {\n const args: ReadonlyArray<string> = ['ls', '-w', workspace, '--json', '--omit=dev', '--all', '--long'];\n debugLog(isDebug, 'spawn:', 'npm', args.join(' '), 'cwd:', rootDir);\n const child = spawn('npm', args, { cwd: rootDir, stdio: ['ignore', 'pipe', 'pipe'] });\n let out: string = '';\n let err: string = '';\n child.stdout.on('data', (d) => (out += String(d)));\n child.stderr.on('data', (d) => (err += String(d)));\n child.on('close', (code: number | null): void => {\n if (code !== 0 && !out) return reject(new Error(`npm ls failed (code ${code}): ${err || 'unknown error'}`));\n\n try {\n const json = JSON.parse(out) as any;\n const normPath = (o: any): string | undefined =>\n // eslint-disable-next-line spellcheck/spell-checker\n typeof o?.path === 'string' ? o.path : typeof o?.realpath === 'string' ? o.realpath : typeof o?.location === 'string' ? (path.isAbsolute(o.location) ? o.location : undefined) : undefined;\n\n const toNode = (name: string, o: any): TDependencyNode => ({\n name,\n version: typeof o?.version === 'string' ? o.version : '0.0.0',\n path: normPath(o),\n license: o?.license,\n repository: o?.repository,\n dependencies: o?.dependencies ? Object.fromEntries(Object.entries(o.dependencies).map(([k, v]) => [k, toNode(k, v)])) : undefined\n });\n\n const rootNode: TDependencyNode = {\n name: json?.name ?? workspace,\n version: json?.version ?? '0.0.0',\n path: normPath(json),\n license: json?.license,\n repository: json?.repository,\n dependencies: json?.dependencies ? Object.fromEntries(Object.entries(json.dependencies).map(([k, v]) => [k, toNode(k, v)])) : undefined\n };\n debugLog(isDebug, 'npm ls parsed root:', rootNode.name, rootNode.version);\n return resolve(rootNode);\n } catch (e) {\n return reject(new Error(`Failed to parse npm ls JSON: ${(e as Error).message}\\nRaw: ${out.slice(0, 2000)}`));\n }\n });\n });\n }\n\n function collectExternalSeedNames(closure: ReadonlySet<string>, wsMap: ReadonlyMap<string, TWorkspaceInfo>, wsNames: ReadonlySet<string>): ReadonlySet<string> {\n const seeds: Set<string> = new Set<string>();\n [...closure].forEach((wsName: string): void => {\n const info: TWorkspaceInfo | undefined = wsMap.get(wsName);\n if (!info) return;\n const deps: Record<string, string> = info.pkg.dependencies ?? {};\n Object.keys(deps).forEach((dependencyName: string): void => {\n if (!wsNames.has(dependencyName)) seeds.add(dependencyName);\n });\n });\n return seeds;\n }\n\n function collectThirdPartyMap(root: TDependencyNode | undefined, wsNames: ReadonlySet<string>, seedNames: ReadonlySet<string>): ReadonlyMap<string, TCollected> {\n const acc: Map<string, TCollected> = new Map<string, TCollected>();\n if (!root || !root.dependencies) return acc;\n if (seedNames.size === 0) return acc;\n\n const visit = (node: TDependencyNode, inside: boolean): void => {\n const isWs: boolean = wsNames.has(node.name);\n const nowInside: boolean = inside || seedNames.has(node.name);\n\n if (nowInside && !isWs && node.version && node.version !== '0.0.0') {\n const id: string = `${node.name}@${node.version}`;\n const prev: TCollected | undefined = acc.get(id);\n const installPath: string | undefined = node.path;\n if (!prev) acc.set(id, { id, name: node.name, version: node.version, installPath });\n else if (!prev.installPath && installPath) acc.set(id, { ...prev, installPath });\n }\n if (node.dependencies) Object.values(node.dependencies).forEach((child) => visit(child, nowInside));\n };\n\n Object.values(root.dependencies).forEach((child: TDependencyNode) => visit(child, false));\n\n debugLog(isDebug, 'third-party collected (seed-filtered):', acc.size);\n return acc;\n }\n\n function resolvePackageDir(pkgName: string, fromDir: string): string | undefined {\n try {\n const req: NodeJS.Require = createRequire(path.join(fromDir, 'package.json'));\n const p: string = req.resolve(`${pkgName}/package.json`);\n return path.dirname(p);\n } catch {\n return undefined;\n }\n }\n\n function fillMissingInstallPaths(collected: Map<string, TCollected>, wsDir: string, rootDir: string): void {\n let filled: number = 0;\n Array.from(collected.entries()).forEach(([id, item]): void => {\n if (!item.installPath) {\n const p: string | undefined = resolvePackageDir(item.name, wsDir) ?? resolvePackageDir(item.name, rootDir);\n if (p) {\n collected.set(id, { ...item, installPath: p });\n filled++;\n }\n }\n });\n debugLog(isDebug, 'install paths filled via resolver:', filled);\n }\n\n async function findLicenseFile(dir: string): Promise<string | undefined> {\n try {\n const list: Array<string> = await fs.readdir(dir);\n const c: string | undefined = list.find((f: string) => {\n const base: string = f.toLowerCase();\n return /^(license|licence|copying|unlicense|notice)(\\..+)?$/.test(base);\n });\n return c ? path.join(dir, c) : undefined;\n } catch {\n return undefined;\n }\n }\n\n function parseSeeLicenseIn(licenseField: unknown): string | undefined {\n if (!licenseField) return undefined;\n const s = typeof licenseField === 'string' ? licenseField : typeof (licenseField as any)?.type === 'string' ? (licenseField as any).type : undefined;\n if (!s) return undefined;\n const m: RegExpExecArray | null = /see\\s+license\\s+in\\s+(.+)$/i.exec(s);\n return m?.[1]?.trim();\n }\n\n async function tryReadLicenseText(pkgDir: string, licenseField: unknown): Promise<string | undefined> {\n const see: string | undefined = parseSeeLicenseIn(licenseField);\n if (see) {\n const p: string = path.join(pkgDir, see);\n if (await isExist(p)) {\n try {\n return await fs.readFile(p, 'utf8');\n } catch {\n /* ignore */\n }\n }\n }\n const license: string | undefined = await findLicenseFile(pkgDir);\n if (license) {\n try {\n return await fs.readFile(license, 'utf8');\n } catch {\n /* ignore */\n }\n }\n return undefined;\n }\n\n const safeString = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined);\n\n function normalizeLicenseValue(licenseField: unknown): string | ReadonlyArray<string> {\n if (!licenseField) return 'UNKNOWN';\n if (typeof licenseField === 'string') return licenseField;\n if (Array.isArray(licenseField)) {\n const arr: any[] = (licenseField as any[]).map((x) => (typeof x === 'string' ? x : typeof (x as any)?.type === 'string' ? (x as any).type : 'UNKNOWN'));\n return arr.length > 0 ? arr : 'UNKNOWN';\n }\n if (typeof licenseField === 'object') {\n const t = (licenseField as any)?.type;\n if (typeof t === 'string') return t;\n }\n return 'UNKNOWN';\n }\n\n async function readPackageMeta(pkgDir: string): Promise<{\n licenseField?: unknown;\n repository?: string;\n publisher?: string;\n email?: string;\n url?: string;\n }> {\n try {\n const pkg = await readJson<any>(path.join(pkgDir, 'package.json'));\n const repo = typeof pkg.repository === 'string' ? pkg.repository : typeof pkg.repository?.url === 'string' ? pkg.repository.url : undefined;\n return {\n licenseField: pkg.license ?? pkg.licenses,\n repository: repo,\n publisher: safeString(pkg.author?.name) ?? safeString(pkg.author) ?? undefined,\n email: safeString(pkg.author?.email) ?? undefined,\n url: safeString(pkg.homepage) ?? undefined\n };\n } catch {\n return {};\n }\n }\n\n async function buildLicenseEntries(collected: ReadonlyMap<string, TCollected>): Promise<ReadonlyArray<TLicenseEntry>> {\n const list = await Promise.all(\n Array.from(collected.values()).map(async ({ id, name, version, installPath }) => {\n let licenseText: string | undefined;\n let licenseType: string | ReadonlyArray<string> | undefined = 'UNKNOWN';\n let repository: string | undefined;\n let publisher: string | undefined;\n let email: string | undefined;\n let url: string | undefined;\n\n if (installPath) {\n const meta = await readPackageMeta(installPath);\n licenseType = normalizeLicenseValue(meta.licenseField);\n repository = meta.repository;\n publisher = meta.publisher;\n email = meta.email;\n url = meta.url;\n\n licenseText = await tryReadLicenseText(installPath, meta.licenseField);\n }\n\n return {\n id,\n name,\n version,\n licenses: licenseType as any,\n licenseText,\n repository,\n publisher,\n email,\n url,\n path: installPath\n } satisfies TLicenseEntry;\n })\n );\n\n return [...list].sort((a, b): number => (a.name === b.name ? a.version.localeCompare(b.version) : a.name.localeCompare(b.name)));\n }\n\n async function buildWorkspaceLicenseEntries(names: ReadonlySet<string>, wsMap: ReadonlyMap<string, TWorkspaceInfo>, excludeName?: string): Promise<ReadonlyArray<TLicenseEntry>> {\n const filtered: any[] = [...names].filter((name) => !(excludeName && name === excludeName));\n const entries = await Promise.all(\n filtered\n .map((name: string) => wsMap.get(name))\n // eslint-disable-next-line functional/prefer-tacit\n .filter((info: TWorkspaceInfo | undefined): info is TWorkspaceInfo => Boolean(info))\n .map(async (info) => {\n const version: string = info.pkg.version ?? '0.0.0';\n const meta = await readPackageMeta(info.dir);\n const licenseType: string | ReadonlyArray<string> = normalizeLicenseValue(meta.licenseField);\n const licenseText: string | undefined = await tryReadLicenseText(info.dir, meta.licenseField);\n return {\n id: `${info.name}@${version}`,\n name: info.name,\n version,\n licenses: licenseType,\n licenseText,\n repository: meta.repository,\n publisher: meta.publisher,\n email: meta.email,\n url: meta.url,\n path: info.dir\n } satisfies TLicenseEntry;\n })\n );\n return [...entries].sort((a, b): number => (a.name === b.name ? a.version.localeCompare(b.version) : a.name.localeCompare(b.name)));\n }\n\n function renderMarkdown(workspaceLabel: string, items: ReadonlyArray<TLicenseEntry>, emptyNote?: string): string {\n const header: ReadonlyArray<string> = [`# Third-Party Licenses`, `## Application: ${workspaceLabel}`, `Production dependencies (including transition dependencies): ${items.length}`, ``];\n const note: ReadonlyArray<string> = items.length === 0 && emptyNote ? [`**Note:** ${emptyNote}`, ``] : [];\n\n const body: ReadonlyArray<string> = items.flatMap((it) => {\n const licenseStr: string = Array.isArray(it.licenses) ? it.licenses.join(', ') : String(it.licenses ?? 'UNKNOWN');\n return [\n `---`,\n ``,\n `## ${it.name}@${it.version}`,\n `**License:** ${licenseStr}\\n`,\n ...(it.repository ? [`**Repository:** ${it.repository}\\n`] : []),\n ...(it.url ? [`**URL:** ${it.url}\\n`] : []),\n ...(it.publisher ? [`**Publisher:** ${it.publisher}${it.email ? ` <${it.email}>` : ''}\\n`] : []),\n ``,\n ...(it.licenseText ? [it.licenseText.trim(), ``] : [`_No license text file found; relying on package metadata._`, ``])\n ];\n });\n\n return [...header, ...note, ...body].join('\\n');\n }\n\n async function resolveWorkspaceFromArg(arg: string, workspaces: ReadonlyMap<string, TWorkspaceInfo>, rootDir: string): Promise<TWorkspaceInfo> {\n const byName: TWorkspaceInfo | undefined = workspaces.get(arg);\n if (byName) return byName;\n\n // as path relative to monorepo root\n const asPath: string = path.isAbsolute(arg) ? arg : path.join(rootDir, arg);\n const norm: string = path.resolve(asPath);\n\n // match any known workspace by directory\n const found: TWorkspaceInfo | undefined = [...workspaces.values()].find((w: TWorkspaceInfo): boolean => path.resolve(w.dir) === norm);\n if (found) return found;\n\n // NEW: allow selecting the monorepo root itself\n const wantRoot: boolean = norm === path.resolve(rootDir) || arg === ':root' || arg === 'root' || arg === '.';\n\n if (wantRoot) {\n const pkgPath: string = path.join(rootDir, 'package.json');\n const pkg: Record<string, unknown> = await readJson(pkgPath);\n const name: string = typeof pkg.name === 'string' ? pkg.name : 'monorepo-root';\n return { name, dir: rootDir, pkgPath, pkg: pkg as any };\n }\n\n throw new Error(`Workspace \"${arg}\" not found by name or path. Tip: use \"--workspace .\" or \"--workspace :root\" to target the monorepo root.`);\n }\n\n return {\n assertNoCycles,\n buildLicenseEntries,\n buildWorkspaceLicenseEntries,\n buildWsGraph,\n collectExternalSeedNames,\n collectThirdPartyMap,\n collectWorkspaceClosure,\n debugLog,\n fillMissingInstallPaths,\n findMonorepoRoot,\n isDebug: (): boolean => isDebug,\n isExist,\n loadRoot,\n loadWorkspaces,\n npmLsJson,\n readJson,\n renderMarkdown,\n resolveWorkspaceFromArg,\n setDebugMode\n };\n}\n"],"names":["isDebug"],"mappings":";;;;;AASO,SAAS,mBAAsC;AACpD,MAAI,UAAmB;AAEvB,QAAM,eAAe,CAAC,UAAyB,MAAM,UAAU;AAE/D,QAAM,WAAW,OAA0C,MAA0B,KAAK,MAAM,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAE5H,QAAM,UAAU,OAAO,MAAgC;AACrD,QAAI;AACF,YAAM,GAAG,OAAO,CAAC;AACjB,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,WAAS,SAASA,aAAqB,MAAoC;AACzE,QAAIA,SAAS,SAAQ,IAAI,WAAW,GAAG,IAAI;AAAA,EAC7C;AAEA,WAAS,mBAAmB,KAAmB;AAC7C,UAAM,KAAK,KAAK;AAChB,QAAI,CAAC,GAAI,QAAO;AAChB,QAAI,MAAM,QAAQ,EAAE,EAAG,QAAO,GAAG,SAAS;AAC1C,QAAI,OAAO,OAAO,YAAY,MAAM,QAAQ,GAAG,QAAQ,EAAG,QAAO,GAAG,SAAS,SAAS;AACtF,WAAO;AAAA,EACT;AAEA,iBAAe,eAAe,SAA+D;AAC3F,UAAM,UAAU,MAAM,SAAc,KAAK,KAAK,SAAS,cAAc,CAAC;AACtE,UAAM,WAAqB,MAAM,QAAQ,QAAQ,UAAU,IAAI,QAAQ,aAAc,QAAQ,YAAY,YAAY,CAAA;AACrH,QAAI,CAAC,SAAS,OAAQ,OAAM,IAAI,MAAM,6BAA6B,KAAK,KAAK,SAAS,cAAc,CAAC,EAAE;AAEvG,UAAM,OAAiB,MAAM,OAAO,UAAU;AAAA,MAC5C,KAAK;AAAA,MACL,UAAU;AAAA,MACV,iBAAiB;AAAA,MACjB,WAAW;AAAA,MACX,QAAQ,CAAC,sBAAsB,cAAc,gBAAgB,UAAU;AAAA,IAAA,CACxE;AACD,UAAM,WACJ,MAAM,QAAQ;AAAA,MACZ,KAAK,IAAI,OAAO,QAAuD;AACrE,cAAM,UAAkB,KAAK,KAAK,KAAK,cAAc;AACrD,YAAI,CAAE,MAAM,QAAQ,OAAO,EAAI,QAAO;AACtC,cAAM,MAAM,MAAM,SAMf,OAAO;AACV,cAAM,OAA2B,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;AAC3E,eAAO,OAAQ,CAAC,MAAM,EAAE,MAAM,KAAK,SAAS,IAAA,CAAK,IAAc;AAAA,MACjE,CAAC;AAAA,IAAA,GAEH,OAAO,OAAO;AAChB,WAAO,IAAI,IAAI,OAAO;AAAA,EACxB;AAEA,iBAAe,iBAAiB,UAAmC;AACjE,UAAM,QAAgB,KAAK,QAAQ,QAAQ;AAC3C,aAAS,SAAS,8BAA8B,KAAK;AAErD,UAAM,WAAW,OAAO,KAAa,UAA+C;AAClF,UAAI,QAAQ,GAAI,QAAO;AACvB,YAAM,UAAkB,KAAK,KAAK,KAAK,cAAc;AACrD,eAAS,SAAS,SAAS,OAAO;AAClC,UAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,YAAI;AACF,gBAAM,MAAM,MAAM,SAAc,OAAO;AACvC,cAAI,mBAAmB,GAAG,GAAG;AAC3B,qBAAS,SAAS,uBAAuB,OAAO;AAChD,mBAAO;AAAA,UACT;AAAA,QACF,SAAS,GAAG;AACV,mBAAS,SAAS,uBAAuB,SAAS,KAAM,EAAY,OAAO;AAAA,QAC7E;AAAA,MACF;AACA,YAAM,SAAiB,KAAK,QAAQ,GAAG;AACvC,UAAI,WAAW,IAAK,QAAO;AAC3B,aAAO,SAAS,QAAQ,QAAQ,CAAC;AAAA,IACnC;AAEA,UAAM,QAA4B,MAAM,SAAS,OAAO,CAAC;AACzD,QAAI,CAAC,MAAO,OAAM,IAAI,MAAM,0CAA0C,QAAQ,4EAA4E;AAC1J,WAAO;AAAA,EACT;AAEA,iBAAe,SAAS,SAAqC;AAC3D,UAAM,cAAsB,KAAK,KAAK,SAAS,cAAc;AAC7D,QAAI,CAAE,MAAM,QAAQ,WAAW,SAAU,IAAI,MAAM,mCAAmC,WAAW,EAAE;AAEnG,UAAM,UAAgC,MAAM,SAA+B,WAAW;AACtF,UAAM,UAAU,QAAQ;AACxB,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,kDAAkD,WAAW,EAAE;AAE7F,UAAM,WAAkC,MAAM,QAAQ,OAAO,IAAI,UAAY,QAAgB,YAAY,CAAA;AACzG,QAAI,SAAS,WAAW,EAAG,OAAM,IAAI,MAAM,mCAAmC,WAAW,EAAE;AAE3F,aAAS,SAAS,wBAAwB,QAAQ;AAGlD,UAAM,OAA8B,MAAM,OAAO,UAAU;AAAA,MACzD,KAAK;AAAA,MACL,iBAAiB;AAAA,MACjB,UAAU;AAAA,MACV,mBAAmB;AAAA,MACnB,WAAW;AAAA,MACX,QAAQ,CAAC,sBAAsB,cAAc,gBAAgB,UAAU;AAAA,IAAA,CACxE;AAED,aAAS,SAAS,yBAAyB,KAAK,MAAM;AAEtD,UAAM,WACJ,MAAM,QAAQ;AAAA,MACZ,KAAK,IAAI,OAAO,QAA+D;AAC7E,cAAM,UAAkB,KAAK,KAAK,KAAK,cAAc;AACrD,YAAI,CAAE,MAAM,QAAQ,OAAO,EAAI,QAAO;AACtC,cAAM,MAAM,MAAM,SAAgC,OAAO;AACzD,YAAI,CAAC,IAAI,KAAM,QAAO;AACtB,eAAO;AAAA,UACL,IAAI;AAAA,UACJ;AAAA,YACE,MAAM,IAAI;AAAA,YACV;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAAA,QACF;AAAA,MAEJ,CAAC;AAAA,IAAA,GAEH,OAAO,OAAO;AAEhB,aAAS,SAAS,8BAA8B,QAAQ,MAAM;AAE9D,QAAI,QAAQ,WAAW,EAAG,OAAM,IAAI,MAAM,sDAAsD,SAAS,KAAK,IAAI,CAAC,EAAE;AAErH,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,IAAI,IAAI,OAAO;AAAA,IAAA;AAAA,EAE/B;AAEA,WAAS,aAAa,IAAmF;AACvG,UAAM,QAAqB,IAAI,IAAI,GAAG,MAAM;AAC5C,UAAM,QAAQ,MAAM,KAAK,GAAG,QAAA,CAAS,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,IAAI,MAAM;AACnE,YAAM,OAA+B,KAAK,IAAI,gBAAgB,CAAA;AAC9D,YAAM,QAAqB,IAAI,IAAY,OAAO,KAAK,IAAI,EAAE,OAAO,CAAC,mBAAmB,MAAM,IAAI,cAAc,CAAC,CAAC;AAClH,UAAI,IAAI,MAAM,KAAK;AACnB,aAAO;AAAA,IACT,GAAG,oBAAI,KAAkC;AAEzC,QAAI,SAAS;AACX,cAAQ,IAAI,0BAA0B;AACtC,YAAM,QAAQ,CAAC,GAAwB,MAAc,QAAQ,IAAI,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,KAAK,GAAG,CAAC;AAAA,IAC3G;AACA,WAAO;AAAA,EACT;AAEA,WAAS,eAAe,OAAiD,OAAqB;AAC5F,UAAM,2BAAwB,IAAA;AAC9B,UAAM,2BAAwB,IAAA;AAC9B,QAAI,YAAmC,CAAA;AAGvC,UAAM,MAAM,CAAC,MAAoB;AAC/B,UAAI,KAAK,IAAI,CAAC,EAAG;AACjB,UAAI,KAAK,IAAI,CAAC,GAAG;AACf,cAAM,MAAc,UAAU,YAAY,CAAC;AAC3C,cAAM,YAAoB,CAAC,GAAG,UAAU,MAAM,GAAG,GAAG,CAAC,EAAE,KAAK,MAAM;AAClE,cAAM,IAAI,MAAM,kDAAkD,SAAS,EAAE;AAAA,MAC/E;AACA,WAAK,IAAI,CAAC;AACV,kBAAY,CAAC,GAAG,SAAS;AAEzB,OAAC,MAAM,IAAI,CAAC,yBAAS,IAAA,GAAe,QAAQ,GAAG;AAC/C,kBAAY,UAAU,MAAM,GAAG,UAAU,SAAS,CAAC;AACnD,WAAK,OAAO,CAAC;AACb,WAAK,IAAI,CAAC;AAAA,IACZ;AAGA,QAAI,KAAK;AAAA,EACX;AAEA,WAAS,wBAAwB,OAAiD,OAAoC;AACpH,UAAM,8BAA2B,IAAA;AAEjC,UAAM,QAAQ,CAAC,MAAoB;AACjC,UAAI,QAAQ,IAAI,CAAC,EAAG;AACpB,cAAQ,IAAI,CAAC;AACb,OAAC,MAAM,IAAI,CAAC,yBAAS,IAAA,GAAe,QAAQ,KAAK;AAAA,IACnD;AAEA,UAAM,KAAK;AACX,WAAO;AAAA,EACT;AAEA,iBAAe,UAAU,SAAiB,WAAyD;AACjG,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAiB;AAC5C,YAAM,OAA8B,CAAC,MAAM,MAAM,WAAW,UAAU,cAAc,SAAS,QAAQ;AACrG,eAAS,SAAS,UAAU,OAAO,KAAK,KAAK,GAAG,GAAG,QAAQ,OAAO;AAClE,YAAM,QAAQ,MAAM,OAAO,MAAM,EAAE,KAAK,SAAS,OAAO,CAAC,UAAU,QAAQ,MAAM,GAAG;AACpF,UAAI,MAAc;AAClB,UAAI,MAAc;AAClB,YAAM,OAAO,GAAG,QAAQ,CAAC,MAAO,OAAO,OAAO,CAAC,CAAE;AACjD,YAAM,OAAO,GAAG,QAAQ,CAAC,MAAO,OAAO,OAAO,CAAC,CAAE;AACjD,YAAM,GAAG,SAAS,CAAC,SAA8B;AAC/C,YAAI,SAAS,KAAK,CAAC,YAAY,OAAO,IAAI,MAAM,uBAAuB,IAAI,MAAM,OAAO,eAAe,EAAE,CAAC;AAE1G,YAAI;AACF,gBAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,gBAAM,WAAW,CAAC;AAAA;AAAA,YAEhB,OAAO,GAAG,SAAS,WAAW,EAAE,OAAO,OAAO,GAAG,aAAa,WAAW,EAAE,WAAW,OAAO,GAAG,aAAa,WAAY,KAAK,WAAW,EAAE,QAAQ,IAAI,EAAE,WAAW,SAAa;AAAA;AAEnL,gBAAM,SAAS,CAAC,MAAc,OAA6B;AAAA,YACzD;AAAA,YACA,SAAS,OAAO,GAAG,YAAY,WAAW,EAAE,UAAU;AAAA,YACtD,MAAM,SAAS,CAAC;AAAA,YAChB,SAAS,GAAG;AAAA,YACZ,YAAY,GAAG;AAAA,YACf,cAAc,GAAG,eAAe,OAAO,YAAY,OAAO,QAAQ,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;AAAA,UAAA;AAG1H,gBAAM,WAA4B;AAAA,YAChC,MAAM,MAAM,QAAQ;AAAA,YACpB,SAAS,MAAM,WAAW;AAAA,YAC1B,MAAM,SAAS,IAAI;AAAA,YACnB,SAAS,MAAM;AAAA,YACf,YAAY,MAAM;AAAA,YAClB,cAAc,MAAM,eAAe,OAAO,YAAY,OAAO,QAAQ,KAAK,YAAY,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;AAAA,UAAA;AAEhI,mBAAS,SAAS,uBAAuB,SAAS,MAAM,SAAS,OAAO;AACxE,iBAAO,QAAQ,QAAQ;AAAA,QACzB,SAAS,GAAG;AACV,iBAAO,OAAO,IAAI,MAAM,gCAAiC,EAAY,OAAO;AAAA,OAAU,IAAI,MAAM,GAAG,GAAI,CAAC,EAAE,CAAC;AAAA,QAC7G;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAEA,WAAS,yBAAyB,SAA8B,OAA4C,SAAmD;AAC7J,UAAM,4BAAyB,IAAA;AAC/B,KAAC,GAAG,OAAO,EAAE,QAAQ,CAAC,WAAyB;AAC7C,YAAM,OAAmC,MAAM,IAAI,MAAM;AACzD,UAAI,CAAC,KAAM;AACX,YAAM,OAA+B,KAAK,IAAI,gBAAgB,CAAA;AAC9D,aAAO,KAAK,IAAI,EAAE,QAAQ,CAAC,mBAAiC;AAC1D,YAAI,CAAC,QAAQ,IAAI,cAAc,EAAG,OAAM,IAAI,cAAc;AAAA,MAC5D,CAAC;AAAA,IACH,CAAC;AACD,WAAO;AAAA,EACT;AAEA,WAAS,qBAAqB,MAAmC,SAA8B,WAAiE;AAC9J,UAAM,0BAAmC,IAAA;AACzC,QAAI,CAAC,QAAQ,CAAC,KAAK,aAAc,QAAO;AACxC,QAAI,UAAU,SAAS,EAAG,QAAO;AAEjC,UAAM,QAAQ,CAAC,MAAuB,WAA0B;AAC9D,YAAM,OAAgB,QAAQ,IAAI,KAAK,IAAI;AAC3C,YAAM,YAAqB,UAAU,UAAU,IAAI,KAAK,IAAI;AAE5D,UAAI,aAAa,CAAC,QAAQ,KAAK,WAAW,KAAK,YAAY,SAAS;AAClE,cAAM,KAAa,GAAG,KAAK,IAAI,IAAI,KAAK,OAAO;AAC/C,cAAM,OAA+B,IAAI,IAAI,EAAE;AAC/C,cAAM,cAAkC,KAAK;AAC7C,YAAI,CAAC,KAAM,KAAI,IAAI,IAAI,EAAE,IAAI,MAAM,KAAK,MAAM,SAAS,KAAK,SAAS,aAAa;AAAA,iBACzE,CAAC,KAAK,eAAe,YAAa,KAAI,IAAI,IAAI,EAAE,GAAG,MAAM,aAAa;AAAA,MACjF;AACA,UAAI,KAAK,aAAc,QAAO,OAAO,KAAK,YAAY,EAAE,QAAQ,CAAC,UAAU,MAAM,OAAO,SAAS,CAAC;AAAA,IACpG;AAEA,WAAO,OAAO,KAAK,YAAY,EAAE,QAAQ,CAAC,UAA2B,MAAM,OAAO,KAAK,CAAC;AAExF,aAAS,SAAS,0CAA0C,IAAI,IAAI;AACpE,WAAO;AAAA,EACT;AAEA,WAAS,kBAAkB,SAAiB,SAAqC;AAC/E,QAAI;AACF,YAAM,MAAsB,cAAc,KAAK,KAAK,SAAS,cAAc,CAAC;AAC5E,YAAM,IAAY,IAAI,QAAQ,GAAG,OAAO,eAAe;AACvD,aAAO,KAAK,QAAQ,CAAC;AAAA,IACvB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,WAAS,wBAAwB,WAAoC,OAAe,SAAuB;AACzG,QAAI,SAAiB;AACrB,UAAM,KAAK,UAAU,QAAA,CAAS,EAAE,QAAQ,CAAC,CAAC,IAAI,IAAI,MAAY;AAC5D,UAAI,CAAC,KAAK,aAAa;AACrB,cAAM,IAAwB,kBAAkB,KAAK,MAAM,KAAK,KAAK,kBAAkB,KAAK,MAAM,OAAO;AACzG,YAAI,GAAG;AACL,oBAAU,IAAI,IAAI,EAAE,GAAG,MAAM,aAAa,GAAG;AAC7C;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AACD,aAAS,SAAS,sCAAsC,MAAM;AAAA,EAChE;AAEA,iBAAe,gBAAgB,KAA0C;AACvE,QAAI;AACF,YAAM,OAAsB,MAAM,GAAG,QAAQ,GAAG;AAChD,YAAM,IAAwB,KAAK,KAAK,CAAC,MAAc;AACrD,cAAM,OAAe,EAAE,YAAA;AACvB,eAAO,sDAAsD,KAAK,IAAI;AAAA,MACxE,CAAC;AACD,aAAO,IAAI,KAAK,KAAK,KAAK,CAAC,IAAI;AAAA,IACjC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,WAAS,kBAAkB,cAA2C;AACpE,QAAI,CAAC,aAAc,QAAO;AAC1B,UAAM,IAAI,OAAO,iBAAiB,WAAW,eAAe,OAAQ,cAAsB,SAAS,WAAY,aAAqB,OAAO;AAC3I,QAAI,CAAC,EAAG,QAAO;AACf,UAAM,IAA4B,8BAA8B,KAAK,CAAC;AACtE,WAAO,IAAI,CAAC,GAAG,KAAA;AAAA,EACjB;AAEA,iBAAe,mBAAmB,QAAgB,cAAoD;AACpG,UAAM,MAA0B,kBAAkB,YAAY;AAC9D,QAAI,KAAK;AACP,YAAM,IAAY,KAAK,KAAK,QAAQ,GAAG;AACvC,UAAI,MAAM,QAAQ,CAAC,GAAG;AACpB,YAAI;AACF,iBAAO,MAAM,GAAG,SAAS,GAAG,MAAM;AAAA,QACpC,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AACA,UAAM,UAA8B,MAAM,gBAAgB,MAAM;AAChE,QAAI,SAAS;AACX,UAAI;AACF,eAAO,MAAM,GAAG,SAAS,SAAS,MAAM;AAAA,MAC1C,QAAQ;AAAA,MAER;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,CAAC,MAAoC,OAAO,MAAM,WAAW,IAAI;AAEpF,WAAS,sBAAsB,cAAuD;AACpF,QAAI,CAAC,aAAc,QAAO;AAC1B,QAAI,OAAO,iBAAiB,SAAU,QAAO;AAC7C,QAAI,MAAM,QAAQ,YAAY,GAAG;AAC/B,YAAM,MAAc,aAAuB,IAAI,CAAC,MAAO,OAAO,MAAM,WAAW,IAAI,OAAQ,GAAW,SAAS,WAAY,EAAU,OAAO,SAAU;AACtJ,aAAO,IAAI,SAAS,IAAI,MAAM;AAAA,IAChC;AACA,QAAI,OAAO,iBAAiB,UAAU;AACpC,YAAM,IAAK,cAAsB;AACjC,UAAI,OAAO,MAAM,SAAU,QAAO;AAAA,IACpC;AACA,WAAO;AAAA,EACT;AAEA,iBAAe,gBAAgB,QAM5B;AACD,QAAI;AACF,YAAM,MAAM,MAAM,SAAc,KAAK,KAAK,QAAQ,cAAc,CAAC;AACjE,YAAM,OAAO,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa,OAAO,IAAI,YAAY,QAAQ,WAAW,IAAI,WAAW,MAAM;AAClI,aAAO;AAAA,QACL,cAAc,IAAI,WAAW,IAAI;AAAA,QACjC,YAAY;AAAA,QACZ,WAAW,WAAW,IAAI,QAAQ,IAAI,KAAK,WAAW,IAAI,MAAM,KAAK;AAAA,QACrE,OAAO,WAAW,IAAI,QAAQ,KAAK,KAAK;AAAA,QACxC,KAAK,WAAW,IAAI,QAAQ,KAAK;AAAA,MAAA;AAAA,IAErC,QAAQ;AACN,aAAO,CAAA;AAAA,IACT;AAAA,EACF;AAEA,iBAAe,oBAAoB,WAAmF;AACpH,UAAM,OAAO,MAAM,QAAQ;AAAA,MACzB,MAAM,KAAK,UAAU,OAAA,CAAQ,EAAE,IAAI,OAAO,EAAE,IAAI,MAAM,SAAS,kBAAkB;AAC/E,YAAI;AACJ,YAAI,cAA0D;AAC9D,YAAI;AACJ,YAAI;AACJ,YAAI;AACJ,YAAI;AAEJ,YAAI,aAAa;AACf,gBAAM,OAAO,MAAM,gBAAgB,WAAW;AAC9C,wBAAc,sBAAsB,KAAK,YAAY;AACrD,uBAAa,KAAK;AAClB,sBAAY,KAAK;AACjB,kBAAQ,KAAK;AACb,gBAAM,KAAK;AAEX,wBAAc,MAAM,mBAAmB,aAAa,KAAK,YAAY;AAAA,QACvE;AAEA,eAAO;AAAA,UACL;AAAA,UACA;AAAA,UACA;AAAA,UACA,UAAU;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,MAAM;AAAA,QAAA;AAAA,MAEV,CAAC;AAAA,IAAA;AAGH,WAAO,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,MAAe,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,cAAc,EAAE,OAAO,IAAI,EAAE,KAAK,cAAc,EAAE,IAAI,CAAE;AAAA,EACjI;AAEA,iBAAe,6BAA6B,OAA4B,OAA4C,aAA6D;AAC/K,UAAM,WAAkB,CAAC,GAAG,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,eAAe,SAAS,YAAY;AAC1F,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC5B,SACG,IAAI,CAAC,SAAiB,MAAM,IAAI,IAAI,CAAC,EAErC,OAAO,CAAC,SAA6D,QAAQ,IAAI,CAAC,EAClF,IAAI,OAAO,SAAS;AACnB,cAAM,UAAkB,KAAK,IAAI,WAAW;AAC5C,cAAM,OAAO,MAAM,gBAAgB,KAAK,GAAG;AAC3C,cAAM,cAA8C,sBAAsB,KAAK,YAAY;AAC3F,cAAM,cAAkC,MAAM,mBAAmB,KAAK,KAAK,KAAK,YAAY;AAC5F,eAAO;AAAA,UACL,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO;AAAA,UAC3B,MAAM,KAAK;AAAA,UACX;AAAA,UACA,UAAU;AAAA,UACV;AAAA,UACA,YAAY,KAAK;AAAA,UACjB,WAAW,KAAK;AAAA,UAChB,OAAO,KAAK;AAAA,UACZ,KAAK,KAAK;AAAA,UACV,MAAM,KAAK;AAAA,QAAA;AAAA,MAEf,CAAC;AAAA,IAAA;AAEL,WAAO,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,GAAG,MAAe,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,cAAc,EAAE,OAAO,IAAI,EAAE,KAAK,cAAc,EAAE,IAAI,CAAE;AAAA,EACpI;AAEA,WAAS,eAAe,gBAAwB,OAAqC,WAA4B;AAC/G,UAAM,SAAgC,CAAC,0BAA0B,mBAAmB,cAAc,IAAI,gEAAgE,MAAM,MAAM,IAAI,EAAE;AACxL,UAAM,OAA8B,MAAM,WAAW,KAAK,YAAY,CAAC,aAAa,SAAS,IAAI,EAAE,IAAI,CAAA;AAEvG,UAAM,OAA8B,MAAM,QAAQ,CAAC,OAAO;AACxD,YAAM,aAAqB,MAAM,QAAQ,GAAG,QAAQ,IAAI,GAAG,SAAS,KAAK,IAAI,IAAI,OAAO,GAAG,YAAY,SAAS;AAChH,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,MAAM,GAAG,IAAI,IAAI,GAAG,OAAO;AAAA,QAC3B,gBAAgB,UAAU;AAAA;AAAA,QAC1B,GAAI,GAAG,aAAa,CAAC,mBAAmB,GAAG,UAAU;AAAA,CAAI,IAAI,CAAA;AAAA,QAC7D,GAAI,GAAG,MAAM,CAAC,YAAY,GAAG,GAAG;AAAA,CAAI,IAAI,CAAA;AAAA,QACxC,GAAI,GAAG,YAAY,CAAC,kBAAkB,GAAG,SAAS,GAAG,GAAG,QAAQ,KAAK,GAAG,KAAK,MAAM,EAAE;AAAA,CAAI,IAAI,CAAA;AAAA,QAC7F;AAAA,QACA,GAAI,GAAG,cAAc,CAAC,GAAG,YAAY,QAAQ,EAAE,IAAI,CAAC,8DAA8D,EAAE;AAAA,MAAA;AAAA,IAExH,CAAC;AAED,WAAO,CAAC,GAAG,QAAQ,GAAG,MAAM,GAAG,IAAI,EAAE,KAAK,IAAI;AAAA,EAChD;AAEA,iBAAe,wBAAwB,KAAa,YAAiD,SAA0C;AAC7I,UAAM,SAAqC,WAAW,IAAI,GAAG;AAC7D,QAAI,OAAQ,QAAO;AAGnB,UAAM,SAAiB,KAAK,WAAW,GAAG,IAAI,MAAM,KAAK,KAAK,SAAS,GAAG;AAC1E,UAAM,OAAe,KAAK,QAAQ,MAAM;AAGxC,UAAM,QAAoC,CAAC,GAAG,WAAW,QAAQ,EAAE,KAAK,CAAC,MAA+B,KAAK,QAAQ,EAAE,GAAG,MAAM,IAAI;AACpI,QAAI,MAAO,QAAO;AAGlB,UAAM,WAAoB,SAAS,KAAK,QAAQ,OAAO,KAAK,QAAQ,WAAW,QAAQ,UAAU,QAAQ;AAEzG,QAAI,UAAU;AACZ,YAAM,UAAkB,KAAK,KAAK,SAAS,cAAc;AACzD,YAAM,MAA+B,MAAM,SAAS,OAAO;AAC3D,YAAM,OAAe,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;AAC/D,aAAO,EAAE,MAAM,KAAK,SAAS,SAAS,IAAA;AAAA,IACxC;AAEA,UAAM,IAAI,MAAM,cAAc,GAAG,2GAA2G;AAAA,EAC9I;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,MAAe;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;"}
@@ -1 +1 @@
1
- {"version":3,"file":"ThirdPartyLicensesService.js","sources":["../../src/Services/ThirdPartyLicensesService.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { TCollected, TDependencyNode, TLicenseEntry, TRepoUtilsService, TRootInfo, TThirdPartyGeneratorArgs, TThirdPartyLicensesService } from '@Anarchy/Legal/Models';\n// eslint-disable-next-line spellcheck/spell-checker\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\n\nimport { RepoUtilsService } from './RepoUtilsService.ts';\n\nexport function ThirdPartyLicensesService(): TThirdPartyLicensesService {\n let isDebug: boolean = false;\n const repoUtilsService: TRepoUtilsService = RepoUtilsService();\n\n const {\n assertNoCycles,\n buildLicenseEntries,\n buildWorkspaceLicenseEntries,\n buildWsGraph,\n collectExternalSeedNames,\n collectThirdPartyMap,\n collectWorkspaceClosure,\n debugLog,\n fillMissingInstallPaths,\n findMonorepoRoot,\n loadRoot,\n npmLsJson,\n renderMarkdown,\n resolveWorkspaceFromArg\n } = repoUtilsService;\n\n function getStartCandidates(argv: TThirdPartyGeneratorArgs): ReadonlyArray<string> {\n const scriptDir: string = path.dirname(fileURLToPath(import.meta.url));\n return [argv.root as string | undefined, process.env.INIT_CWD, process.cwd(), scriptDir].filter(Boolean) as string[];\n }\n\n function getMonorepoRoot(startCandidates: ReadonlyArray<string>): Promise<string | undefined> {\n return startCandidates.reduce<Promise<string | undefined>>(async (prev, c) => {\n const acc: string | undefined = await prev;\n if (acc) return acc;\n try {\n const found: string = await findMonorepoRoot(c);\n debugLog(isDebug, 'monorepo root picked:', found, '(from', c + ')');\n return found;\n } catch (e) {\n debugLog(isDebug, 'no root from', c, ':', (e as Error).message);\n return undefined;\n }\n }, Promise.resolve<string | undefined>(undefined));\n }\n\n async function getWorkspaceEntries(argv: TThirdPartyGeneratorArgs, wsName: string, closure: ReadonlySet<string>, root: TRootInfo): Promise<ReadonlyArray<TLicenseEntry>> {\n let wsEntries: ReadonlyArray<TLicenseEntry> = [];\n if (argv['include-workspaces'] !== false) {\n wsEntries = await buildWorkspaceLicenseEntries(\n closure,\n root.workspaces,\n argv['include-workspace-self'] ? undefined : wsName // exclude self\n );\n }\n return wsEntries;\n }\n\n function getEmptyNote(sorted: ReadonlyArray<TLicenseEntry>, seedNames: ReadonlySet<string>): string | undefined {\n if (sorted.length !== 0) return undefined;\n const noSeeds: boolean = seedNames.size === 0;\n return noSeeds\n ? 'This workspace declares no production dependencies and has no reachable internal workspaces. Therefore, there are no third-party licenses to list.'\n : 'There are no third-party production dependencies reachable from this workspace. Therefore, there are no third-party licenses to list.';\n }\n\n async function writeResultFile(outPath: string, wsName: string, sorted: ReadonlyArray<TLicenseEntry>, emptyNote: string | undefined): Promise<void> {\n const resultFile: string = renderMarkdown(wsName, sorted, emptyNote);\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, resultFile, 'utf8');\n console.log(`The result file written to: ${outPath}`);\n }\n\n async function generate(): Promise<void> {\n // eslint-disable-next-line spellcheck/spell-checker\n const argv: TThirdPartyGeneratorArgs = await yargs(hideBin(process.argv))\n // .scriptName('anarchy-legal')\n .usage('$0 --workspace <name|path> --out <file> [--root <dir>] [--debug] [--no-include-workspaces]')\n .option('root', {\n type: 'string',\n describe: 'Starting directory to search for monorepo root. If omitted, uses INIT_CWD, then process.cwd(), then script dir.'\n })\n .option('workspace', {\n type: 'string',\n demandOption: true,\n describe: 'Target workspace (name from package.json or folder path relative to monorepo root)'\n })\n .option('out', {\n type: 'string',\n demandOption: true,\n describe: 'Output path for the result file (relative to current working dir)'\n })\n .option('debug', {\n type: 'boolean',\n default: false,\n describe: 'Print verbose diagnostic information'\n })\n .option('include-workspaces', {\n type: 'boolean',\n default: true,\n describe: 'Also include licenses of reachable internal workspaces (excluding self by default)'\n })\n .option('include-workspace-self', {\n type: 'boolean',\n default: false,\n describe: 'Also include license of the target workspace itself'\n })\n .help()\n .parseAsync();\n\n isDebug = Boolean(argv.debug);\n repoUtilsService.setDebugMode(isDebug);\n\n // 1) Determine start points\n const startCandidates: ReadonlyArray<string> = getStartCandidates(argv);\n debugLog(isDebug, 'start candidates:', startCandidates);\n\n // 2) Find monorepo root\n const monorepoRoot: string | undefined = await getMonorepoRoot(startCandidates);\n if (!monorepoRoot) throw new Error(`Failed to locate monorepo root from candidates: ${startCandidates.join(', ')}`);\n\n // 3) Load root + workspaces\n const root = await loadRoot(monorepoRoot);\n debugLog(isDebug, 'rootDir:', root.rootDir);\n\n // 4) Resolve workspace\n const { name, dir } = await resolveWorkspaceFromArg(argv.workspace as string, root.workspaces, root.rootDir);\n debugLog(isDebug, 'target workspace:', name, 'dir:', dir);\n\n // 5) Cycle check\n const graph: ReadonlyMap<string, ReadonlySet<string>> = buildWsGraph(root.workspaces);\n assertNoCycles(graph, name);\n\n // 6) Workspace closure and seeds\n const closure: ReadonlySet<string> = collectWorkspaceClosure(graph, name);\n const wsNamesSet: ReadonlySet<string> = new Set(root.workspaces.keys());\n const seedNames: ReadonlySet<string> = collectExternalSeedNames(closure, root.workspaces, wsNamesSet);\n debugLog(isDebug, 'workspace closure size:', closure.size, 'seed external deps:', seedNames.size, 'sample:', [...seedNames].slice(0, 10));\n\n // 7) Resolved prod tree\n const tree: TDependencyNode | undefined = await npmLsJson(root.rootDir, name);\n\n // 8) Collect external packages WITH paths (seed-filtered)\n const thirdPartyMap: Map<string, TCollected> = new Map(collectThirdPartyMap(tree, wsNamesSet, seedNames));\n fillMissingInstallPaths(thirdPartyMap, name, root.rootDir);\n\n if (thirdPartyMap.size === 0) debugLog(isDebug, `[info] No third-party prod deps reachable from seeds.`);\n else if (isDebug) console.log('[debug] examples (third-party):', [...thirdPartyMap.values()].slice(0, 5));\n\n // 9) Workspace licenses (excluding self by default)\n const wsEntries: ReadonlyArray<TLicenseEntry> = await getWorkspaceEntries(argv, name, closure, root);\n debugLog(isDebug, 'workspace license entries (after self-filter):', wsEntries.length);\n\n // 10) Third-party licenses\n const thirdEntries: ReadonlyArray<TLicenseEntry> = await buildLicenseEntries(thirdPartyMap);\n debugLog(isDebug, 'third-party license entries:', thirdEntries.length);\n\n // 11) Merge & write\n const merged: ReadonlyArray<TLicenseEntry> = [...wsEntries, ...thirdEntries];\n const sorted: ReadonlyArray<TLicenseEntry> = [...merged].sort((a, b) => (a.name === b.name ? a.version.localeCompare(b.version) : a.name.localeCompare(b.name)));\n\n const outPath: string = path.isAbsolute(argv.out as string) ? (argv.out as string) : path.join(process.cwd(), argv.out as string);\n\n const emptyNote: string | undefined = getEmptyNote(sorted, seedNames);\n\n debugLog(isDebug, 'write output to:', outPath, 'total entries:', sorted.length);\n\n await writeResultFile(outPath, name, sorted, emptyNote);\n }\n\n return { generate };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ThirdPartyLicensesService.js","sources":["../../src/Services/ThirdPartyLicensesService.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { TCollected, TDependencyNode, TLicenseEntry, TRepoUtilsService, TRootInfo, TThirdPartyGeneratorArgs, TThirdPartyLicensesService } from '@hellpig/anarchy-legal/Models';\n// eslint-disable-next-line spellcheck/spell-checker\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\n\nimport { RepoUtilsService } from './RepoUtilsService.ts';\n\nexport function ThirdPartyLicensesService(): TThirdPartyLicensesService {\n let isDebug: boolean = false;\n const repoUtilsService: TRepoUtilsService = RepoUtilsService();\n\n const {\n assertNoCycles,\n buildLicenseEntries,\n buildWorkspaceLicenseEntries,\n buildWsGraph,\n collectExternalSeedNames,\n collectThirdPartyMap,\n collectWorkspaceClosure,\n debugLog,\n fillMissingInstallPaths,\n findMonorepoRoot,\n loadRoot,\n npmLsJson,\n renderMarkdown,\n resolveWorkspaceFromArg\n } = repoUtilsService;\n\n function getStartCandidates(argv: TThirdPartyGeneratorArgs): ReadonlyArray<string> {\n const scriptDir: string = path.dirname(fileURLToPath(import.meta.url));\n return [argv.root as string | undefined, process.env.INIT_CWD, process.cwd(), scriptDir].filter(Boolean) as string[];\n }\n\n function getMonorepoRoot(startCandidates: ReadonlyArray<string>): Promise<string | undefined> {\n return startCandidates.reduce<Promise<string | undefined>>(async (prev, c) => {\n const acc: string | undefined = await prev;\n if (acc) return acc;\n try {\n const found: string = await findMonorepoRoot(c);\n debugLog(isDebug, 'monorepo root picked:', found, '(from', c + ')');\n return found;\n } catch (e) {\n debugLog(isDebug, 'no root from', c, ':', (e as Error).message);\n return undefined;\n }\n }, Promise.resolve<string | undefined>(undefined));\n }\n\n async function getWorkspaceEntries(argv: TThirdPartyGeneratorArgs, wsName: string, closure: ReadonlySet<string>, root: TRootInfo): Promise<ReadonlyArray<TLicenseEntry>> {\n let wsEntries: ReadonlyArray<TLicenseEntry> = [];\n if (argv['include-workspaces'] !== false) {\n wsEntries = await buildWorkspaceLicenseEntries(\n closure,\n root.workspaces,\n argv['include-workspace-self'] ? undefined : wsName // exclude self\n );\n }\n return wsEntries;\n }\n\n function getEmptyNote(sorted: ReadonlyArray<TLicenseEntry>, seedNames: ReadonlySet<string>): string | undefined {\n if (sorted.length !== 0) return undefined;\n const noSeeds: boolean = seedNames.size === 0;\n return noSeeds\n ? 'This workspace declares no production dependencies and has no reachable internal workspaces. Therefore, there are no third-party licenses to list.'\n : 'There are no third-party production dependencies reachable from this workspace. Therefore, there are no third-party licenses to list.';\n }\n\n async function writeResultFile(outPath: string, wsName: string, sorted: ReadonlyArray<TLicenseEntry>, emptyNote: string | undefined): Promise<void> {\n const resultFile: string = renderMarkdown(wsName, sorted, emptyNote);\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, resultFile, 'utf8');\n console.log(`The result file written to: ${outPath}`);\n }\n\n async function generate(): Promise<void> {\n // eslint-disable-next-line spellcheck/spell-checker\n const argv: TThirdPartyGeneratorArgs = await yargs(hideBin(process.argv))\n // .scriptName('anarchy-legal')\n .usage('$0 --workspace <name|path> --out <file> [--root <dir>] [--debug] [--no-include-workspaces]')\n .option('root', {\n type: 'string',\n describe: 'Starting directory to search for monorepo root. If omitted, uses INIT_CWD, then process.cwd(), then script dir.'\n })\n .option('workspace', {\n type: 'string',\n demandOption: true,\n describe: 'Target workspace (name from package.json or folder path relative to monorepo root)'\n })\n .option('out', {\n type: 'string',\n demandOption: true,\n describe: 'Output path for the result file (relative to current working dir)'\n })\n .option('debug', {\n type: 'boolean',\n default: false,\n describe: 'Print verbose diagnostic information'\n })\n .option('include-workspaces', {\n type: 'boolean',\n default: true,\n describe: 'Also include licenses of reachable internal workspaces (excluding self by default)'\n })\n .option('include-workspace-self', {\n type: 'boolean',\n default: false,\n describe: 'Also include license of the target workspace itself'\n })\n .help()\n .parseAsync();\n\n isDebug = Boolean(argv.debug);\n repoUtilsService.setDebugMode(isDebug);\n\n // 1) Determine start points\n const startCandidates: ReadonlyArray<string> = getStartCandidates(argv);\n debugLog(isDebug, 'start candidates:', startCandidates);\n\n // 2) Find monorepo root\n const monorepoRoot: string | undefined = await getMonorepoRoot(startCandidates);\n if (!monorepoRoot) throw new Error(`Failed to locate monorepo root from candidates: ${startCandidates.join(', ')}`);\n\n // 3) Load root + workspaces\n const root = await loadRoot(monorepoRoot);\n debugLog(isDebug, 'rootDir:', root.rootDir);\n\n // 4) Resolve workspace\n const { name, dir } = await resolveWorkspaceFromArg(argv.workspace as string, root.workspaces, root.rootDir);\n debugLog(isDebug, 'target workspace:', name, 'dir:', dir);\n\n // 5) Cycle check\n const graph: ReadonlyMap<string, ReadonlySet<string>> = buildWsGraph(root.workspaces);\n assertNoCycles(graph, name);\n\n // 6) Workspace closure and seeds\n const closure: ReadonlySet<string> = collectWorkspaceClosure(graph, name);\n const wsNamesSet: ReadonlySet<string> = new Set(root.workspaces.keys());\n const seedNames: ReadonlySet<string> = collectExternalSeedNames(closure, root.workspaces, wsNamesSet);\n debugLog(isDebug, 'workspace closure size:', closure.size, 'seed external deps:', seedNames.size, 'sample:', [...seedNames].slice(0, 10));\n\n // 7) Resolved prod tree\n const tree: TDependencyNode | undefined = await npmLsJson(root.rootDir, name);\n\n // 8) Collect external packages WITH paths (seed-filtered)\n const thirdPartyMap: Map<string, TCollected> = new Map(collectThirdPartyMap(tree, wsNamesSet, seedNames));\n fillMissingInstallPaths(thirdPartyMap, name, root.rootDir);\n\n if (thirdPartyMap.size === 0) debugLog(isDebug, `[info] No third-party prod deps reachable from seeds.`);\n else if (isDebug) console.log('[debug] examples (third-party):', [...thirdPartyMap.values()].slice(0, 5));\n\n // 9) Workspace licenses (excluding self by default)\n const wsEntries: ReadonlyArray<TLicenseEntry> = await getWorkspaceEntries(argv, name, closure, root);\n debugLog(isDebug, 'workspace license entries (after self-filter):', wsEntries.length);\n\n // 10) Third-party licenses\n const thirdEntries: ReadonlyArray<TLicenseEntry> = await buildLicenseEntries(thirdPartyMap);\n debugLog(isDebug, 'third-party license entries:', thirdEntries.length);\n\n // 11) Merge & write\n const merged: ReadonlyArray<TLicenseEntry> = [...wsEntries, ...thirdEntries];\n const sorted: ReadonlyArray<TLicenseEntry> = [...merged].sort((a, b) => (a.name === b.name ? a.version.localeCompare(b.version) : a.name.localeCompare(b.name)));\n\n const outPath: string = path.isAbsolute(argv.out as string) ? (argv.out as string) : path.join(process.cwd(), argv.out as string);\n\n const emptyNote: string | undefined = getEmptyNote(sorted, seedNames);\n\n debugLog(isDebug, 'write output to:', outPath, 'total entries:', sorted.length);\n\n await writeResultFile(outPath, name, sorted, emptyNote);\n }\n\n return { generate };\n}\n"],"names":[],"mappings":";;;;;;AAWO,SAAS,4BAAwD;AACtE,MAAI,UAAmB;AACvB,QAAM,mBAAsC,iBAAA;AAE5C,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACE;AAEJ,WAAS,mBAAmB,MAAuD;AACjF,UAAM,YAAoB,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AACrE,WAAO,CAAC,KAAK,MAA4B,QAAQ,IAAI,UAAU,QAAQ,IAAA,GAAO,SAAS,EAAE,OAAO,OAAO;AAAA,EACzG;AAEA,WAAS,gBAAgB,iBAAqE;AAC5F,WAAO,gBAAgB,OAAoC,OAAO,MAAM,MAAM;AAC5E,YAAM,MAA0B,MAAM;AACtC,UAAI,IAAK,QAAO;AAChB,UAAI;AACF,cAAM,QAAgB,MAAM,iBAAiB,CAAC;AAC9C,iBAAS,SAAS,yBAAyB,OAAO,SAAS,IAAI,GAAG;AAClE,eAAO;AAAA,MACT,SAAS,GAAG;AACV,iBAAS,SAAS,gBAAgB,GAAG,KAAM,EAAY,OAAO;AAC9D,eAAO;AAAA,MACT;AAAA,IACF,GAAG,QAAQ,QAA4B,MAAS,CAAC;AAAA,EACnD;AAEA,iBAAe,oBAAoB,MAAgC,QAAgB,SAA8B,MAAwD;AACvK,QAAI,YAA0C,CAAA;AAC9C,QAAI,KAAK,oBAAoB,MAAM,OAAO;AACxC,kBAAY,MAAM;AAAA,QAChB;AAAA,QACA,KAAK;AAAA,QACL,KAAK,wBAAwB,IAAI,SAAY;AAAA;AAAA,MAAA;AAAA,IAEjD;AACA,WAAO;AAAA,EACT;AAEA,WAAS,aAAa,QAAsC,WAAoD;AAC9G,QAAI,OAAO,WAAW,EAAG,QAAO;AAChC,UAAM,UAAmB,UAAU,SAAS;AAC5C,WAAO,UACH,uJACA;AAAA,EACN;AAEA,iBAAe,gBAAgB,SAAiB,QAAgB,QAAsC,WAA8C;AAClJ,UAAM,aAAqB,eAAe,QAAQ,QAAQ,SAAS;AACnE,UAAM,GAAG,MAAM,KAAK,QAAQ,OAAO,GAAG,EAAE,WAAW,MAAM;AACzD,UAAM,GAAG,UAAU,SAAS,YAAY,MAAM;AAC9C,YAAQ,IAAI,+BAA+B,OAAO,EAAE;AAAA,EACtD;AAEA,iBAAe,WAA0B;AAEvC,UAAM,OAAiC,MAAM,MAAM,QAAQ,QAAQ,IAAI,CAAC,EAErE,MAAM,4FAA4F,EAClG,OAAO,QAAQ;AAAA,MACd,MAAM;AAAA,MACN,UAAU;AAAA,IAAA,CACX,EACA,OAAO,aAAa;AAAA,MACnB,MAAM;AAAA,MACN,cAAc;AAAA,MACd,UAAU;AAAA,IAAA,CACX,EACA,OAAO,OAAO;AAAA,MACb,MAAM;AAAA,MACN,cAAc;AAAA,MACd,UAAU;AAAA,IAAA,CACX,EACA,OAAO,SAAS;AAAA,MACf,MAAM;AAAA,MACN,SAAS;AAAA,MACT,UAAU;AAAA,IAAA,CACX,EACA,OAAO,sBAAsB;AAAA,MAC5B,MAAM;AAAA,MACN,SAAS;AAAA,MACT,UAAU;AAAA,IAAA,CACX,EACA,OAAO,0BAA0B;AAAA,MAChC,MAAM;AAAA,MACN,SAAS;AAAA,MACT,UAAU;AAAA,IAAA,CACX,EACA,KAAA,EACA,WAAA;AAEH,cAAU,QAAQ,KAAK,KAAK;AAC5B,qBAAiB,aAAa,OAAO;AAGrC,UAAM,kBAAyC,mBAAmB,IAAI;AACtE,aAAS,SAAS,qBAAqB,eAAe;AAGtD,UAAM,eAAmC,MAAM,gBAAgB,eAAe;AAC9E,QAAI,CAAC,aAAc,OAAM,IAAI,MAAM,mDAAmD,gBAAgB,KAAK,IAAI,CAAC,EAAE;AAGlH,UAAM,OAAO,MAAM,SAAS,YAAY;AACxC,aAAS,SAAS,YAAY,KAAK,OAAO;AAG1C,UAAM,EAAE,MAAM,IAAA,IAAQ,MAAM,wBAAwB,KAAK,WAAqB,KAAK,YAAY,KAAK,OAAO;AAC3G,aAAS,SAAS,qBAAqB,MAAM,QAAQ,GAAG;AAGxD,UAAM,QAAkD,aAAa,KAAK,UAAU;AACpF,mBAAe,OAAO,IAAI;AAG1B,UAAM,UAA+B,wBAAwB,OAAO,IAAI;AACxE,UAAM,aAAkC,IAAI,IAAI,KAAK,WAAW,MAAM;AACtE,UAAM,YAAiC,yBAAyB,SAAS,KAAK,YAAY,UAAU;AACpG,aAAS,SAAS,2BAA2B,QAAQ,MAAM,uBAAuB,UAAU,MAAM,WAAW,CAAC,GAAG,SAAS,EAAE,MAAM,GAAG,EAAE,CAAC;AAGxI,UAAM,OAAoC,MAAM,UAAU,KAAK,SAAS,IAAI;AAG5E,UAAM,gBAAyC,IAAI,IAAI,qBAAqB,MAAM,YAAY,SAAS,CAAC;AACxG,4BAAwB,eAAe,MAAM,KAAK,OAAO;AAEzD,QAAI,cAAc,SAAS,EAAG,UAAS,SAAS,uDAAuD;AAAA,aAC9F,QAAS,SAAQ,IAAI,mCAAmC,CAAC,GAAG,cAAc,OAAA,CAAQ,EAAE,MAAM,GAAG,CAAC,CAAC;AAGxG,UAAM,YAA0C,MAAM,oBAAoB,MAAM,MAAM,SAAS,IAAI;AACnG,aAAS,SAAS,kDAAkD,UAAU,MAAM;AAGpF,UAAM,eAA6C,MAAM,oBAAoB,aAAa;AAC1F,aAAS,SAAS,gCAAgC,aAAa,MAAM;AAGrE,UAAM,SAAuC,CAAC,GAAG,WAAW,GAAG,YAAY;AAC3E,UAAM,SAAuC,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,cAAc,EAAE,OAAO,IAAI,EAAE,KAAK,cAAc,EAAE,IAAI,CAAE;AAE/J,UAAM,UAAkB,KAAK,WAAW,KAAK,GAAa,IAAK,KAAK,MAAiB,KAAK,KAAK,QAAQ,IAAA,GAAO,KAAK,GAAa;AAEhI,UAAM,YAAgC,aAAa,QAAQ,SAAS;AAEpE,aAAS,SAAS,oBAAoB,SAAS,kBAAkB,OAAO,MAAM;AAE9E,UAAM,gBAAgB,SAAS,MAAM,QAAQ,SAAS;AAAA,EACxD;AAEA,SAAO,EAAE,SAAA;AACX;"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@hellpig/anarchy-legal",
3
3
  "author": "S. Panfilov",
4
4
  "private": false,
5
- "version": "1.12.4",
5
+ "version": "1.12.5",
6
6
  "type": "module",
7
7
  "repository": {
8
8
  "type": "git",