Saltar al contenido principal

TypeScript

El paquete de TypeScript es la implementación de referencia de TDC. El CLI es estupendo cuando lo que quiere es un archivo; la biblioteca es para obtener datos dentro de su código —como una cadena o como objetos JS vivos— sin lanzar un proceso ni leer un archivo.

import { TDC } from "tdcv2";

Cómo crear un TDC​

El constructor recibe o bien una ruta a un archivo DSL (configFile), o bien una cadena DSL (configString). Desde el código se pueden anular los parámetros de ejecución seed, count, locale y now: le ganan a los valores de <env>.

const tdc = new TDC({
configString: `<tdc>
<env count="4" seed="demo" local="en">
<sequence name="Gender"><gen type="text" value="Male,Female"/></sequence>
<sequence name="MaleName" parent="Gender.Male"><gen type="template" value="person.male.firstName"/></sequence>
<sequence name="FemaleName" parent="Gender.Female"><gen type="template" value="person.female.firstName"/></sequence>
<before><line><data>Gender,Name</data></line></before>
</env>
<block><line><data>\${{Gender}},\${{MaleName}}\${{FemaleName}}</data></line></block>
</tdc>`,
});

console.log(tdc.toString());

El nombre queda atado al género mediante parent: dos secuencias, una por rama — si no, el nombre se sortearía por su cuenta y a un hombre le tocaría un nombre de mujer. En cada fila se rellena exactamente una, así que en la salida van simplemente una junto a otra.

node example.js
Gender,Name
Female,Mary
Male,James
Male,John
Female,Elizabeth

Anular desde el código — estos le ganan a <env>:

const tdc = new TDC({
configFile: "./patients.tdc",
seed: "test-seed",
count: 100,
locale: "ru",
});

Para fuentes en archivos externos, indique las carpetas de datos (y un directorio base para configString):

const tdc = new TDC({
configFile: "./configs/users.tdc",
dataPaths: ["./data", "./private-data"],
});

Con configFile, las rutas src relativas dentro del .tdc se resuelven desde la carpeta de ese archivo; con configString, fije baseDir usted mismo.

El resto de las opciones del constructor son menos comunes, pero no menos reales:

OpciónQué hace
localeAnula <env local=…> — la configuración pierde
defaultLocaleSolo se aplica cuando <env> no declara ningún locale. La clave locale de tdcv2.config.json va a esta, no a la anulación
mode"memory" o "disk" — la misma elección que --mode
engine1, 2 o 3 — fuerza un motor, y falla en vez de caer a otro
streamAlias heredado de engine: 2

Esa división entre locale y defaultLocale merece una segunda mirada: un "locale": "ru" en la configuración del proyecto no le gana a un local="en" del archivo de configuración, y nada lo reporta. Solo anulan el locale del propio constructor y el --locale de la CLI.

preflight(opts?) tiene una opción propia: output, que es "materialized" (por omisión — toda la corrida sostenida a la vez, lo que hace toArray()) o "streaming".

Métodos terminales​

MétodoDevuelvePara
toString()toda la salida como una sola cadenaresultados chicos o medianos
writeFile(path)escribe la salida en un archivo (por trozos)un archivo de cualquier tamaño
toIterator()un generador de líneas (una por registro)texto grande, sin cadena entera
toStream()un Readable de Node.jspipe a archivo / HTTP / gzip
toColumns()columnas; números como Float64Arrayflujos numéricos, muchas ejecuciones
toArray()un arreglo de objetos-filafixtures chicos de objetos
iterate()un generador de objetos-filasalida de objetos, sin arreglo
getAt(index)un objeto-fila por índiceacceso puntual
preflight(opts?)un diagnóstico de memoria, o undefineduna revisión antes de una corrida grande
seedInfo(){ seed, generated }leer o registrar la semilla
toStringAsync()toda la salida, como promesauna configuración con type="http"
writeFileAsync(path)escribe la salida, como promesauna configuración con type="http"
usesHttp()true si la configuración llama a la redelegir entre los dos pares

toString/writeFile/toIterator/toStream son salida de texto a través del disco, con memoria O(cantidad de campos). Vea Salidas grandes para las mediciones.

Sobre el par asíncrono hay una regla: una configuración con <gen type="http"> tiene que usarlo. Una llamada de red no se puede hacer desde una función síncrona, así que toString() sobre esa configuración lanza en vez de devolver medio dataset:

const tdc = new TDC({ configFile: "./enriched.tdc" });
const text = tdc.usesHttp() ? await tdc.toStringAsync() : tdc.toString();

usesHttp() responde eso sin ejecutar nada, que es justo lo que hace la CLI. En todo lo demás los dos caminos se comportan igual: para una configuración sin generador http, toStringAsync() es toString() envuelto en una promesa. Lo que sí cambia es la reproducibilidad: una corrida que llama a un servicio es tan repetible como lo sea el servicio.

Salida en objetos​

En las pruebas suele ser más cómodo trabajar con objetos vivos que analizar CSV o JSON: se puede revisar row.Gender directamente. toArray(), iterate() y getAt(index) le dan eso. La salida en objetos ignora <block> y los envoltorios de texto: solo lee las <sequence> materializadas:

  • una secuencia simple se vuelve una propiedad escalar;
  • una secuencia compuesta se vuelve un objeto anidado;
  • una secuencia filtrada por parent queda como undefined en las filas donde no aplica.

getAt(index) es el trabajo de una sola fila, y el índice da igual: en una configuración de 200 000 filas, getAt(0) y getAt(199999) vuelven en unos 2 ms, mientras que toArray() tarda unos 210 ms en la misma corrida. iterate() cuesta lo mismo en total que toArray(), pero nunca sostiene el arreglo.

const tdc = new TDC({
configString: `<tdc>
<env count="4" seed="demo" local="en">
<sequence name="Gender"><gen type="text" value="Male,Female"/></sequence>
<sequence name="Person">
<gen name="Code" type="regex" value="[0-9]{4}"/>
</sequence>
<sequence name="MaleName" parent="Gender.Male"><gen type="template" value="person.male.firstName"/></sequence>
<sequence name="FemaleName" parent="Gender.Female"><gen type="template" value="person.female.firstName"/></sequence>
</env>
<block><line><data>ignored</data></line></block>
</tdc>`,
});

console.log(tdc.getAt(0)); // una fila Female
console.log(tdc.getAt(1)); // una fila Male
node objects.js
{
Gender: 'Female',
Person: { Code: '7541' },
MaleName: undefined,
FemaleName: 'Mary'
}
{
Gender: 'Male',
Person: { Code: '1506' },
MaleName: 'James',
FemaleName: undefined
}

Person es un objeto anidado. MaleName y FemaleName están las dos presentes, pero en cada fila se rellena exactamente una: la otra vale undefined, porque su parent no coincidió allí. Así se ve un filtro por padre en la salida de objetos.

Los mismos valores, de a una fila

Los métodos de objetos leen del motor al que el enrutador manda la configuración — el mismo que usa toString() — así que los valores coinciden, y getAt(index) cuesta una fila en vez de todo lo que va antes: pedir la fila nueve millones de una configuración de diez millones es el trabajo de una sola fila.

Un valor sin configuración​

El paquete exporta además tdc, que sortea un solo valor desde los mismos paquetes de datos que lee una configuración: sin archivo, sin <env>, una llamada.

import { tdc } from "tdcv2";

tdc.person.lastName(); // Jones
tdc.country.usa.docs.ssn(); // 699209702, con sus dígitos de control reales
tdc.person.lastName.many(5); // cinco de ellos
tdc.seed("demo").locale("ru").person.lastName(); // fijado y en ruso

Cada dirección incluida es una propiedad real del tipo, así que un error de escritura es un error de compilación y el autocompletado funciona sin ningún plugin. Toda la superficie está en Un valor a la vez.

Los paquetes que ve una ejecución​

El paquete de npm trae los paquetes de inicio en inglés; los que una persona instala con tdcv2 pack add viven en un almacén que nombra tdcv2.config.json. packRoots() devuelve todas las carpetas de las que una ejecución lee paquetes — las incluidas, los dataPaths de la configuración global, los del proyecto, en ese orden — y new TDC() construye su propia lista con la misma llamada, así que no pueden discrepar:

import { packRoots, scanPacks } from "tdcv2";

const { registry } = scanPacks(packRoots({ configFile: "users.tdc" }));
registry.has("fr.person.lastName"); // true once `tdcv2 pack add fr` has run

Con configFile el proyecto se busca desde la carpeta de ese archivo, como hace una ejecución; cwd indica otra carpeta de partida y dataPaths las carpetas que añadiría --data-path.

Para una herramienta que escribe configuraciones, el paquete exporta además lo que acepta el validador: EXPR_FUNCTIONS (cada función de expresión con su aridad), COMPUTE_TAGS y COMPUTE_ATTRIBUTES (cada etiqueta de <compute> y los atributos que lee).

Los mismos nombres en todos los lenguajes​

El objeto que devuelve una ejecución terminada responde a los mismos nombres en los cinco paquetes, escritos según la costumbre de cada lenguaje. La tabla está aquí, y los conjuntos de pruebas la comprueban en vez de darla por buena.

Vea también​

  • CLI — el mismo motor desde la línea de comandos.
  • Salidas grandes — métodos de streaming y memoria.