Archify Diagram Viewer 0.1.0

VS Code extension that previews Archify diagrams from their JSON sources
(live, as you type) and opens rendered Archify HTML in a viewer tab.
Bundles the Archify 3.0.1 renderer and runs it on VS Code's Node runtime.
Adds validation diagnostics, JSON schema help, source-link navigation,
export saving, render-to-file and open-in-browser commands.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-30 12:40:55 +03:00
co-authored by Claude Opus 5.5
commit d56e784e97
119 changed files with 66708 additions and 0 deletions
+408
View File
@@ -0,0 +1,408 @@
const PORTABLE_PATH_PROFILES = new Set(['output', 'repo', 'archive']);
const WINDOWS_SAFE_PROFILES = new Set(['output', 'archive']);
const WINDOWS_RESERVED_NAME = /^(?:con|prn|aux|nul|conin\$|conout\$|com[1-9¹²³]|lpt[1-9¹²³])(?:\.|$)/iu;
const WINDOWS_SHORT_NAME = /~[1-9][0-9]*(?:\.|$)/iu;
const URI_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*:/u;
const CONTROL_CHARACTER = /\p{Cc}/u;
const WINDOWS_INVALID_CHARACTER = /[<>"|?*]/u;
const MAX_SEMANTIC_VARIANTS = 32;
export class PortablePathError extends Error {
constructor(message, {
code,
reason,
value,
profile,
segment,
segmentIndex,
character,
index,
conflictIndex,
conflictValue,
collisionKind,
semantics,
pathPart,
conflictPathPart,
utf8Bytes,
utf16CodeUnits,
limit,
} = {}) {
super(message);
this.name = 'PortablePathError';
this.code = code;
this.reason = reason;
this.value = value;
this.profile = profile;
if (segment !== undefined) this.segment = segment;
if (segmentIndex !== undefined) this.segmentIndex = segmentIndex;
if (character !== undefined) this.character = character;
if (index !== undefined) this.index = index;
if (conflictIndex !== undefined) this.conflictIndex = conflictIndex;
if (conflictValue !== undefined) this.conflictValue = conflictValue;
if (collisionKind !== undefined) this.collisionKind = collisionKind;
if (semantics !== undefined) this.semantics = semantics;
if (pathPart !== undefined) this.pathPart = pathPart;
if (conflictPathPart !== undefined) this.conflictPathPart = conflictPathPart;
if (utf8Bytes !== undefined) this.utf8Bytes = utf8Bytes;
if (utf16CodeUnits !== undefined) this.utf16CodeUnits = utf16CodeUnits;
if (limit !== undefined) this.limit = limit;
}
}
function pathError(value, profile, reason, message, details = {}) {
return new PortablePathError(message, {
code: `portable-path/${reason}`,
reason,
value,
profile,
...details,
});
}
function assertProfile(profile) {
if (PORTABLE_PATH_PROFILES.has(profile)) return;
throw pathError(
undefined,
profile,
'profile',
`Portable path profile must be one of: ${[...PORTABLE_PATH_PROFILES].join(', ')}.`,
);
}
export function validatePortablePath(value, options = {}) {
const profile = options?.profile;
assertProfile(profile);
if (typeof value !== 'string') {
throw pathError(value, profile, 'type', 'Portable path must be a string.');
}
if (value.length === 0) {
throw pathError(value, profile, 'empty', 'Portable path must not be empty.');
}
if (/^[A-Za-z]:[\\/]/u.test(value) || value.startsWith('/') || value.startsWith('\\')) {
throw pathError(value, profile, 'absolute', 'Portable path must be relative.');
}
if (/^[A-Za-z]:/u.test(value)) {
throw pathError(
value,
profile,
'drive-relative',
'Portable path must not use a drive-relative Windows path.',
);
}
if (URI_SCHEME.test(value)) {
throw pathError(value, profile, 'uri', 'Portable path must not be a URI.');
}
if (value.includes('\\')) {
throw pathError(
value,
profile,
'backslash',
'Portable path must use forward slashes as separators.',
);
}
const segments = value.split('/');
for (const [segmentIndex, segment] of segments.entries()) {
const segmentDetails = { segment, segmentIndex };
if (segment.length === 0) {
throw pathError(
value,
profile,
'empty-segment',
'Portable path must not contain empty segments.',
segmentDetails,
);
}
if (segment === '.' || segment === '..') {
throw pathError(
value,
profile,
'dot-segment',
'Portable path must not contain dot segments.',
segmentDetails,
);
}
const controlMatch = segment.match(CONTROL_CHARACTER);
if (controlMatch) {
throw pathError(
value,
profile,
'control',
'Portable path must not contain control characters.',
{ ...segmentDetails, character: controlMatch[0] },
);
}
const surrogateMatch = segment.match(/[\uD800-\uDFFF]/u);
if (surrogateMatch) {
throw pathError(
value,
profile,
'unpaired-surrogate',
'Portable path must not contain unpaired UTF-16 surrogates.',
{ ...segmentDetails, character: surrogateMatch[0] },
);
}
if (!WINDOWS_SAFE_PROFILES.has(profile)) continue;
if (segment.includes(':')) {
throw pathError(
value,
profile,
'windows-ads',
'Portable path must not select a Windows alternate data stream.',
{ ...segmentDetails, character: ':' },
);
}
const invalidMatch = segment.match(WINDOWS_INVALID_CHARACTER);
if (invalidMatch) {
throw pathError(
value,
profile,
'windows-invalid-character',
'Portable path contains a character that is invalid in Windows file names.',
{ ...segmentDetails, character: invalidMatch[0] },
);
}
if (/[. ]$/u.test(segment)) {
throw pathError(
value,
profile,
'windows-trailing-dot-space',
'Portable path segments must not end with a dot or space.',
segmentDetails,
);
}
if (WINDOWS_RESERVED_NAME.test(segment)) {
throw pathError(
value,
profile,
'windows-reserved-name',
'Portable path must not use a reserved Windows device name.',
segmentDetails,
);
}
if (WINDOWS_SHORT_NAME.test(segment)) {
throw pathError(
value,
profile,
'windows-short-name',
'Portable path must not use a Windows 8.3 short-name shape.',
segmentDetails,
);
}
const utf8Bytes = Buffer.byteLength(segment, 'utf8');
const utf16CodeUnits = segment.length;
if (utf8Bytes > 255 || utf16CodeUnits > 255) {
throw pathError(
value,
profile,
'component-too-long',
'Portable path segments must fit both UTF-8 and UTF-16 filesystem component limits.',
{
...segmentDetails,
utf8Bytes,
utf16CodeUnits,
limit: 255,
},
);
}
}
return value;
}
function collisionError(values, profile, index, conflictIndex, reason, details = {}) {
return new PortablePathError(
`Portable paths at indexes ${conflictIndex} and ${index} collide under portable filesystem semantics.`,
{
code: 'portable-path/collision',
reason,
value: values[index],
profile,
index,
conflictIndex,
conflictValue: values[conflictIndex],
...details,
},
);
}
function createSemanticIndex() {
return new Map();
}
function semanticEnvelope(value, profile, index) {
const variants = [value];
const seen = new Set(variants);
const transforms = [
(candidate) => candidate.normalize('NFC'),
(candidate) => candidate.normalize('NFD'),
// path-contract-allow: portable-logical-path -- Archive names require conservative case-collision closure.
(candidate) => candidate.toLocaleLowerCase('en-US'),
// path-contract-allow: portable-logical-path -- Archive names require conservative case-collision closure.
(candidate) => candidate.toLocaleUpperCase('en-US'),
];
for (let cursor = 0; cursor < variants.length; cursor += 1) {
for (const transform of transforms) {
const transformed = transform(variants[cursor]);
if (seen.has(transformed)) continue;
if (variants.length >= MAX_SEMANTIC_VARIANTS) {
throw pathError(
value,
profile,
'semantic-expansion',
'Portable path semantic comparison exceeded its bounded Unicode expansion.',
{ index, limit: MAX_SEMANTIC_VARIANTS },
);
}
seen.add(transformed);
variants.push(transformed);
}
}
return variants;
}
function classifySemanticCollision(value, conflictValue) {
if (value === conflictValue) return 'exact';
if (value.normalize('NFC') === conflictValue.normalize('NFC')) return 'normalization';
const directLowerMatch = value.toLocaleLowerCase('en-US')
=== conflictValue.toLocaleLowerCase('en-US');
const directUpperMatch = value.toLocaleUpperCase('en-US')
=== conflictValue.toLocaleUpperCase('en-US');
return directLowerMatch || directUpperMatch ? 'case' : 'case-and-normalization';
}
function findSemanticCollision(semanticIndex, value, profile, sourceIndex) {
const variants = semanticEnvelope(value, profile, sourceIndex);
for (const variant of variants) {
const entry = semanticIndex.get(variant);
if (entry) {
return {
entry,
variants,
semantics: classifySemanticCollision(value, entry.value),
};
}
}
return { entry: null, variants, semantics: null };
}
function rememberSemanticEntry(semanticIndex, entry, variants) {
for (const variant of variants) {
if (!semanticIndex.has(variant)) semanticIndex.set(variant, entry);
}
}
export function validatePortablePathSet(values, options = {}) {
const profile = options?.profile;
assertProfile(profile);
if (!Array.isArray(values)) {
throw pathError(values, profile, 'set-type', 'Portable path set must be an array.');
}
const leafEntries = createSemanticIndex();
const directoryEntries = createSemanticIndex();
for (const [index, value] of values.entries()) {
try {
validatePortablePath(value, { profile });
} catch (error) {
if (error instanceof PortablePathError && error.index === undefined) error.index = index;
throw error;
}
const leafCollision = findSemanticCollision(leafEntries, value, profile, index);
if (leafCollision.entry) {
const conflictIndex = leafCollision.entry.index;
throw collisionError(
values,
profile,
index,
conflictIndex,
leafCollision.semantics === 'exact' ? 'duplicate' : leafCollision.semantics,
{
collisionKind: 'entry',
semantics: leafCollision.semantics,
pathPart: value,
conflictPathPart: leafCollision.entry.value,
},
);
}
const segments = value.split('/');
const prefixes = segments.slice(0, -1).map((_, prefixIndex) => (
segments.slice(0, prefixIndex + 1).join('/')
));
for (const prefix of prefixes) {
const directoryCollision = findSemanticCollision(directoryEntries, prefix, profile, index);
if (directoryCollision.entry && directoryCollision.semantics !== 'exact') {
throw collisionError(
values,
profile,
index,
directoryCollision.entry.index,
`directory-${directoryCollision.semantics}`,
{
collisionKind: 'directory-spelling',
semantics: directoryCollision.semantics,
pathPart: prefix,
conflictPathPart: directoryCollision.entry.value,
},
);
}
const fileCollision = findSemanticCollision(leafEntries, prefix, profile, index);
if (fileCollision.entry) {
throw collisionError(
values,
profile,
index,
fileCollision.entry.index,
fileCollision.semantics === 'exact'
? 'tree-file'
: `tree-file-${fileCollision.semantics}`,
{
collisionKind: 'tree-file',
semantics: fileCollision.semantics,
pathPart: prefix,
conflictPathPart: fileCollision.entry.value,
},
);
}
}
const directoryCollision = findSemanticCollision(directoryEntries, value, profile, index);
if (directoryCollision.entry) {
throw collisionError(
values,
profile,
index,
directoryCollision.entry.index,
directoryCollision.semantics === 'exact'
? 'tree-file'
: `tree-file-${directoryCollision.semantics}`,
{
collisionKind: 'tree-file',
semantics: directoryCollision.semantics,
pathPart: value,
conflictPathPart: directoryCollision.entry.value,
},
);
}
rememberSemanticEntry(leafEntries, { index, value }, leafCollision.variants);
for (const prefix of prefixes) {
rememberSemanticEntry(
directoryEntries,
{ index, value: prefix },
semanticEnvelope(prefix, profile, index),
);
}
}
return values;
}