@terrazzo/parser
Version:
Parser/validator for the Design Tokens Community Group (DTCG) standard.
113 lines • 3.79 kB
JavaScript
import { pluralize } from '@terrazzo/token-tools';
import lintRunner from '../lint/index.js';
import Logger from '../logger.js';
import { createSyntheticResolver } from '../resolver/create-synthetic-resolver.js';
import { loadResolver } from '../resolver/load.js';
import { loadSources } from './load.js';
/** Parse */
export default async function parse(_input, { logger = new Logger(), req = defaultReq, skipLint = false, config = {}, continueOnError = false, resolveAliases = true, yamlToMomoa, transform, } = {}) {
const inputs = Array.isArray(_input) ? _input : [_input];
let tokens = {};
let resolver;
let sources = [];
// 0. validate
if (inputs.length === 0) {
logger.error({ group: 'parser', label: 'init', message: 'Nothing to parse.' });
}
for (let i = 0; i < inputs.length; i++) {
if (!inputs[i] ||
typeof inputs[i] !== 'object' ||
!inputs[i]?.src ||
(inputs[i]?.filename && !(inputs[i].filename instanceof URL))) {
logger.error({
group: 'parser',
label: 'init',
message: `Input ${i}: expected { src: any; filename: URL }`,
});
}
}
const totalStart = performance.now();
// 1. Load tokens
const initStart = performance.now();
const resolverResult = await loadResolver(inputs, { config, logger, req, yamlToMomoa });
// 1a. Resolver
if (resolverResult.resolver) {
tokens = resolverResult.tokens;
sources = resolverResult.sources;
resolver = resolverResult.resolver;
}
else {
// 1b. No resolver
const tokenResult = await loadSources(inputs, {
req,
logger,
config,
continueOnError,
yamlToMomoa,
resolveAliases,
transform,
});
tokens = tokenResult.tokens;
sources = tokenResult.sources;
}
logger.debug({
message: 'Loaded tokens',
group: 'parser',
label: 'core',
timing: performance.now() - initStart,
});
if (skipLint !== true && config?.plugins?.length) {
const lintStart = performance.now();
await lintRunner({ tokens, sources, config, logger });
logger.debug({
message: 'Lint finished',
group: 'plugin',
label: 'lint',
timing: performance.now() - lintStart,
});
}
const resolverTiming = performance.now();
const finalResolver = resolver || (await createSyntheticResolver(tokens, { config, logger, req, sources }));
logger.debug({
message: 'Resolver finalized',
group: 'parser',
label: 'core',
timing: performance.now() - resolverTiming,
});
logger.debug({
message: 'Finish all parser tasks',
group: 'parser',
label: 'core',
timing: performance.now() - totalStart,
});
if (continueOnError) {
const { errorCount } = logger.stats();
if (errorCount > 0) {
logger.error({
group: 'parser',
message: `Parser encountered ${errorCount} ${pluralize(errorCount, 'error', 'errors')}. Exiting.`,
});
}
}
return {
tokens,
sources,
resolver: finalResolver,
};
}
let fs;
/** Fallback req */
async function defaultReq(src, _origin) {
if (src.protocol === 'file:') {
if (!fs) {
fs = await import('node:fs/promises');
}
return await fs.readFile(src, 'utf8');
}
const res = await fetch(src);
if (!res.ok) {
throw new Error(`${src} responded with ${res.status}\n${await res.text()}`);
}
return await res.text();
}
//# sourceMappingURL=index.js.map