@lblod/ember-rdfa-editor-lblod-plugins 2.1.0 → 2.1.1

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.
package/.release-it.json CHANGED
@@ -3,12 +3,14 @@
3
3
  "release": true
4
4
  },
5
5
  "plugins": {
6
- "@release-it-plugins/lerna-changelog": {
7
- "infile": "CHANGELOG.md",
8
- "launchEditor": true
6
+ "@release-it/keep-a-changelog": {
7
+ "filename": "CHANGELOG.md",
8
+ "addUnreleased": true,
9
+ "strictLatest": false,
10
+ "addVersionUrl": true
9
11
  }
10
12
  },
11
13
  "npm": {
12
14
  "publish": false
13
15
  }
14
- }
16
+ }
package/CHANGELOG.md CHANGED
@@ -1,31 +1,41 @@
1
+ # Changelog
1
2
 
3
+ All notable changes to this project will be documented in this file.
2
4
 
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
3
7
 
8
+ ## [Unreleased]
4
9
 
10
+ ## [2.1.1] - 2023-02-07
5
11
 
12
+ ### Changed
6
13
 
14
+ - move to keep-a-changelog for changelog management
15
+ - bump editor to v2.1.2
16
+ - bump editor to v2.1.1
7
17
 
18
+ ### Added
8
19
 
20
+ - add types for the `debug` lib
9
21
 
22
+ ### Fixed
10
23
 
24
+ - correctly set the date type as xsd:date or xsd:dateTime based on the date content
25
+ - Add the __rdfaId when manually creating decisions titles, decision articles or citations
26
+ - fix citation highlights not triggering correctly in various situations
11
27
 
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
- ## 2.1.0 (2023-02-06)
28
+ ## [2.1.0] - 2023-02-06
23
29
 
24
30
  #### :rocket: Enhancement
25
- * [#98](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/98) Improve citation plugin regex and improve citation type matching ([@elpoelma](https://github.com/elpoelma))
31
+
32
+ * [#98](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/98) Improve citation plugin regex and improve
33
+ citation type matching ([@elpoelma](https://github.com/elpoelma))
26
34
 
27
35
  #### :bug: Bug Fix
28
- * [#96](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/96) Fix insert-citation button not being enabled in correct context. ([@elpoelma](https://github.com/elpoelma))
36
+
37
+ * [#96](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/96) Fix insert-citation button not being enabled
38
+ in correct context. ([@elpoelma](https://github.com/elpoelma))
29
39
  * [#100](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/100) Prevent splitting of besluit related nodes ([@elpoelma](https://github.com/elpoelma))
30
40
  * [#97](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/97) Fix: disallow splitting of besluit node ([@elpoelma](https://github.com/elpoelma))
31
41
 
@@ -305,3 +315,6 @@ add onclick handler to pencil icon in variable plugin
305
315
  - Elena Poelman ([@elpoelma](https://github.com/elpoelma))
306
316
 
307
317
  # Changelog
318
+
319
+ [unreleased]: https://github.com/lblod/ember-rdfa-editor-lblod-plugins/compare/v2.1.1...HEAD
320
+ [2.1.1]: https://github.com/lblod/ember-rdfa-editor-lblod-plugins/compare/v2.1.0...v2.1.1
@@ -5,6 +5,7 @@ import { ProseController } from '@lblod/ember-rdfa-editor/core/prosemirror';
5
5
  import { NodeSelection, PNode } from '@lblod/ember-rdfa-editor';
6
6
  import { DateFormat } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/rdfa-date-plugin';
7
7
  import {
8
+ formatContainsTime,
8
9
  validateDateFormat,
9
10
  ValidationError,
10
11
  } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/rdfa-date-plugin/utils';
@@ -28,7 +29,6 @@ type Args = {
28
29
  };
29
30
  };
30
31
  };
31
- const TIME_CHAR_REGEX = new RegExp('[abBhHkKmsStTp]');
32
32
  const SECONDS_REGEX = new RegExp('[sStT]|p{2,}');
33
33
  export default class RdfaDatePluginCardComponent extends Component<Args> {
34
34
  @service
@@ -84,8 +84,7 @@ export default class RdfaDatePluginCardComponent extends Component<Args> {
84
84
  return optionMapOr(
85
85
  false,
86
86
  (node) => {
87
- const format = node.attrs.format as string;
88
- return !TIME_CHAR_REGEX.test(format);
87
+ return !formatContainsTime(node.attrs.format);
89
88
  },
90
89
  this.selectedDateNode
91
90
  );
@@ -96,7 +95,7 @@ export default class RdfaDatePluginCardComponent extends Component<Args> {
96
95
  false,
97
96
  (node) => {
98
97
  const format = node.attrs.format as string;
99
- return SECONDS_REGEX.test(format);
98
+ return SECONDS_REGEX.test(format.replace(/'[^']*'|"[^"]*"/g, ''));
100
99
  },
101
100
  this.selectedDateNode
102
101
  );
@@ -209,7 +208,7 @@ export default class RdfaDatePluginCardComponent extends Component<Args> {
209
208
  return tr
210
209
  .setNodeAttribute(pos, 'format', dateFormat)
211
210
  .setNodeAttribute(pos, 'custom', custom)
212
- .setNodeAttribute(pos, 'onlyDate', this.onlyDate);
211
+ .setNodeAttribute(pos, 'onlyDate', !formatContainsTime(dateFormat));
213
212
  }, true);
214
213
  }
215
214
 
@@ -243,7 +242,7 @@ export default class RdfaDatePluginCardComponent extends Component<Args> {
243
242
  this.controller.withTransaction((tr) => {
244
243
  return tr
245
244
  .setNodeAttribute(pos, 'format', format)
246
- .setNodeAttribute(pos, 'onlyDate', this.onlyDate);
245
+ .setNodeAttribute(pos, 'onlyDate', !formatContainsTime(format));
247
246
  }, true);
248
247
  }
249
248
  }
@@ -1,6 +1,7 @@
1
1
  import { findParentNodeOfType } from '@curvenote/prosemirror-utils';
2
2
  import { Command, NodeSelection } from '@lblod/ember-rdfa-editor';
3
3
  import IntlService from 'ember-intl/services/intl';
4
+ import { v4 as uuid } from 'uuid';
4
5
 
5
6
  export default function insertTitle(intl: IntlService): Command {
6
7
  return function (state, dispatch) {
@@ -19,7 +20,7 @@ export default function insertTitle(intl: IntlService): Command {
19
20
  besluit.pos + 1,
20
21
  schema.node(
21
22
  'title',
22
- null,
23
+ { __rdfaId: uuid() },
23
24
  schema.node(
24
25
  'paragraph',
25
26
  null,
@@ -26,6 +26,7 @@ const NNWS = '[^\\S\\n]';
26
26
 
27
27
  /**
28
28
  * match for a "decree"
29
+ * the "t" at the end is not a typo
29
30
  */
30
31
  const DECREE = `\\w*decreet`;
31
32
 
@@ -56,7 +57,11 @@ const FLEMGOV = `besluit${VVR}`;
56
57
  * match for "coordinated laws"
57
58
  * whatever that may be
58
59
  */
59
- const COORD = `geco[öo]rdineerde${NNWS}wetten`;
60
+ const COORD = `geco[öo]rdineerde${NNWS}wet(ten)?`;
61
+ /**
62
+ * literally "special law"
63
+ */
64
+ const SPECIAL = `bijzondere${NNWS}wet`;
60
65
  /**
61
66
  * Matches any kind of law
62
67
  */
@@ -80,13 +85,13 @@ const ENUM_ROYAL = `genummerd${NNWS}?${ROYAL}`;
80
85
  /**
81
86
  * The type of citation that we need to search for
82
87
  */
83
- const TYPE = `${DECREE}|${MEMO}|${TREATY}|${CONSTITUTION_CHANGE}|${COLLAB}|${BOOK}|${PROTOCOL}|${FLEMGOV}|${COORD}|${LAW}|${ROYAL}|${MINISTERIAL}|${ENUM_ROYAL}`;
88
+ const TYPE = `${DECREE}|${MEMO}|${TREATY}|${CONSTITUTION_CHANGE}|${COLLAB}|${BOOK}|${PROTOCOL}|${FLEMGOV}|${COORD}|${SPECIAL}|${LAW}|${ROYAL}|${MINISTERIAL}|${ENUM_ROYAL}`;
84
89
  /**
85
90
  * The monster regex that makes the citation plugin trigger.
86
91
  * In restructuring, I've made sure that I didn't abstract away any of the capturing groups,
87
92
  * only their content, so you can still see what's going on
88
93
  *
89
- * This regex uses named capturing groups, that's the "?<name>" syntax for easy parsing later
94
+ * This regex uses named capturing groups, that's the "?<name>" syntax, for easy parsing later
90
95
  */
91
96
  export const CITATION_REGEX = new RegExp(
92
97
  `((?<type>${TYPE})${NNWS}*(?<searchTerms>(${NNWS}|[${BASIC_MULTIPLANE_CHARACTER};:'"()&-_]){3,})?)`,
@@ -179,8 +184,13 @@ function citationPlugin(config: CitationPluginConfig): CitationPlugin {
179
184
  init(stateConfig: EditorStateConfig, state: EditorState) {
180
185
  return calculateCitationPluginState(state, config);
181
186
  },
182
- apply(tr, set, oldState, newState) {
183
- return calculateCitationPluginState(newState, config, oldState);
187
+ apply(tr, oldPluginState, oldState, newState) {
188
+ return calculateCitationPluginState(
189
+ newState,
190
+ config,
191
+ oldState,
192
+ oldPluginState.highlights.map(tr.mapping, tr.doc)
193
+ );
184
194
  },
185
195
  },
186
196
  props: {
@@ -195,7 +205,8 @@ function citationPlugin(config: CitationPluginConfig): CitationPlugin {
195
205
  function calculateCitationPluginState(
196
206
  state: EditorState,
197
207
  config: CitationPluginConfig,
198
- oldState?: EditorState
208
+ oldState?: EditorState,
209
+ oldDecs?: DecorationSet
199
210
  ) {
200
211
  const { doc, schema } = state;
201
212
  let activeRanges;
@@ -216,7 +227,8 @@ function calculateCitationPluginState(
216
227
  schema,
217
228
  nodes,
218
229
  doc,
219
- oldState?.doc
230
+ oldState?.doc,
231
+ oldDecs
220
232
  );
221
233
  activeRanges = calculatedDecs.activeRanges;
222
234
  highlights = calculatedDecs.decorations;
@@ -232,11 +244,19 @@ function calculateDecorationsInNodes(
232
244
  schema: CitationSchema,
233
245
  nodes: Set<NodeType>,
234
246
  newDoc: PNode,
235
- oldDoc?: PNode
247
+ oldDoc?: PNode,
248
+ oldDecorations?: DecorationSet
236
249
  ): { decorations: DecorationSet; activeRanges: [number, number][] } {
237
250
  const activeRanges: [number, number][] = [];
238
- const decorations: Decoration[] = [];
239
- const collector = collectDecorations(decorations, schema, config.regex);
251
+ const decsToAdd: Decoration[] = [];
252
+ const decsToRemove: Decoration[] = [];
253
+ const collector = collectDecorations(
254
+ decsToAdd,
255
+ schema,
256
+ config.regex,
257
+ decsToRemove,
258
+ oldDecorations
259
+ );
240
260
  if (nodes.has(newDoc.type)) {
241
261
  oldDoc
242
262
  ? changedDescendants(oldDoc, newDoc, 0, collector)
@@ -268,7 +288,9 @@ function calculateDecorationsInNodes(
268
288
  });
269
289
  }
270
290
  return {
271
- decorations: DecorationSet.create(newDoc, decorations),
291
+ decorations: oldDecorations
292
+ ? oldDecorations.remove(decsToRemove).add(newDoc, decsToAdd)
293
+ : DecorationSet.create(newDoc, decsToAdd),
272
294
  activeRanges,
273
295
  };
274
296
  }
@@ -279,22 +301,24 @@ function calculateDecorationsInRanges(
279
301
  doc: PNode,
280
302
  activeRanges: [number, number][]
281
303
  ): { decorations: DecorationSet; activeRanges: [number, number][] } {
282
- const decorations: Decoration[] = [];
283
- const collector = collectDecorations(decorations, schema, config.regex);
304
+ const decorationsToAdd: Decoration[] = [];
305
+ const collector = collectDecorations(decorationsToAdd, schema, config.regex);
284
306
 
285
307
  for (const [start, end] of activeRanges) {
286
308
  doc.nodesBetween(start, end, collector);
287
309
  }
288
310
  return {
289
- decorations: DecorationSet.create(doc, decorations),
311
+ decorations: DecorationSet.create(doc, decorationsToAdd),
290
312
  activeRanges: activeRanges,
291
313
  };
292
314
  }
293
315
 
294
316
  function collectDecorations(
295
- decorations: Decoration[],
317
+ decsToAdd: Decoration[],
296
318
  schema: CitationSchema,
297
- regex: RegExp = CITATION_REGEX
319
+ regex: RegExp = CITATION_REGEX,
320
+ decsToRemove?: Decoration[],
321
+ oldDecs?: DecorationSet
298
322
  ) {
299
323
  return function (node: PNode, pos: number): boolean {
300
324
  if (
@@ -302,6 +326,17 @@ function collectDecorations(
302
326
  node.text &&
303
327
  !schema.marks.citation.isInSet(node.marks)
304
328
  ) {
329
+ if (decsToRemove && oldDecs) {
330
+ decsToRemove.push(
331
+ ...oldDecs.find(
332
+ pos,
333
+ pos + node.nodeSize,
334
+ (spec) =>
335
+ (spec as Record<string, string>).name === 'citationHighlight'
336
+ )
337
+ );
338
+ }
339
+
305
340
  for (const match of node.text.matchAll(regex)) {
306
341
  const processedMatch = processMatch(
307
342
  match as RegexpMatchArrayWithIndices
@@ -312,7 +347,7 @@ function collectDecorations(
312
347
  const { start: matchStart, end: matchEnd } = searchTextMatch;
313
348
  const decorationStart = pos + matchStart;
314
349
  const decorationEnd = pos + matchEnd;
315
- decorations.push(
350
+ decsToAdd.push(
316
351
  Decoration.inline(
317
352
  decorationStart,
318
353
  decorationEnd,
@@ -321,6 +356,7 @@ function collectDecorations(
321
356
  'data-editor-highlight': 'true',
322
357
  },
323
358
  {
359
+ name: 'citationHighlight',
324
360
  searchText: text,
325
361
  legislationTypeUri,
326
362
  }
@@ -1,6 +1,7 @@
1
1
  import { PNode } from '@lblod/ember-rdfa-editor';
2
2
  import { CitationSchema } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/citation-plugin';
3
3
  import { unwrap } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
4
+ import { v4 as uuid } from 'uuid';
4
5
 
5
6
  export function citedText(
6
7
  schema: CitationSchema,
@@ -12,6 +13,7 @@ export function citedText(
12
13
  href: uri,
13
14
  property: 'eli:cites',
14
15
  typeof: 'eli:LegalExpression',
16
+ __rdfaId: uuid(),
15
17
  }),
16
18
  ]);
17
19
  }
@@ -5,7 +5,8 @@ import { unwrap } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
5
5
  const STOP_WORDS = ['het', 'de', 'van', 'tot', 'dat'];
6
6
  const DATE_REGEX = new RegExp('(\\d{1,2})\\s(\\w+)\\s(\\d{2,4})', 'g');
7
7
  const INVISIBLE_SPACE = '\u200B';
8
- const SPACES_REGEX = new RegExp('[\\s${UNBREAKABLE_SPACE}]+');
8
+ const UNBREAKABLE_SPACE = '\u00A0';
9
+ const SPACES_REGEX = new RegExp(`[\\s${UNBREAKABLE_SPACE}]+`);
9
10
  export type RegexpMatchArrayWithIndices = RegExpMatchArray & {
10
11
  indices: Array<[number, number]> & {
11
12
  groups: { [key: string]: [number, number] };
@@ -57,13 +58,13 @@ export default function processMatch(
57
58
  cleanedSearchTerms = `${type} ${cleanedSearchTerms}`;
58
59
  } else if (/wetboek/i.test(type)) {
59
60
  typeLabel = 'wetboek';
60
- } else if (/geco[oö]rdineerde[^\S\n]wetten/i.test(type)) {
61
+ } else if (/geco[oö]rdineerde[^\S\n]wet(ten)?/i.test(type)) {
61
62
  typeLabel = 'gecoördineerde wetten';
62
63
  } else if (/grondwets?wijziging/i.test(type)) {
63
64
  typeLabel = 'grondwetswijziging';
64
65
  } else if (/grondwet/i.test(type)) {
65
66
  typeLabel = 'grondwet';
66
- } else if (/bijzondere wet/i.test(type)) {
67
+ } else if (/bijzondere[^\S\n]wet/i.test(type)) {
67
68
  typeLabel = 'bijzondere wet';
68
69
  } else if (/\w+wet/i.test(type)) {
69
70
  typeLabel = 'wet';
@@ -2,6 +2,8 @@ import { formatWithOptions } from 'date-fns/fp';
2
2
  import { nlBE } from 'date-fns/locale';
3
3
  import { RegexpMatchArrayWithIndices } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/citation-plugin/utils/process-match';
4
4
 
5
+ const TIME_CHAR_REGEX = new RegExp('[abBhHkKmsStTp]');
6
+
5
7
  export function formatDate(date: Date, format: string) {
6
8
  try {
7
9
  return formatWithOptions({ locale: nlBE }, format)(date);
@@ -10,6 +12,10 @@ export function formatDate(date: Date, format: string) {
10
12
  }
11
13
  }
12
14
 
15
+ export function formatContainsTime(format: string) {
16
+ return TIME_CHAR_REGEX.test(format.replace(/'[^']*'|"[^"]*"/g, ''));
17
+ }
18
+
13
19
  type ValidationErrorType =
14
20
  | 'date'
15
21
  | 'locale'
@@ -187,12 +187,18 @@ export const besluitArticleStructure: StructureSpec = {
187
187
  const numberConverted = number?.toString() ?? '1';
188
188
  const node = schema.node(
189
189
  `besluit_article`,
190
- { resource: `http://data.lblod.info/articles/${uuid()}` },
190
+ {
191
+ resource: `http://data.lblod.info/articles/${uuid()}`,
192
+ __rdfaId: uuid(),
193
+ },
191
194
  [
192
- schema.node('besluit_article_header', { number: numberConverted }),
195
+ schema.node('besluit_article_header', {
196
+ number: numberConverted,
197
+ __rdfaId: uuid(),
198
+ }),
193
199
  schema.node(
194
200
  `besluit_article_content`,
195
- {},
201
+ { __rdfaId: uuid() },
196
202
  content ??
197
203
  schema.node(
198
204
  'paragraph',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lblod/ember-rdfa-editor-lblod-plugins",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Ember addon providing lblod specific plugins for the ember-rdfa-editor",
5
5
  "keywords": [
6
6
  "ember-addon",
@@ -63,10 +63,11 @@
63
63
  "@embroider/test-setup": "^1.6.0",
64
64
  "@glimmer/component": "^1.1.2",
65
65
  "@glimmer/tracking": "^1.1.2",
66
- "@lblod/ember-rdfa-editor": "^2.1.0",
66
+ "@lblod/ember-rdfa-editor": "^2.1.2",
67
67
  "@rdfjs/types": "^1.1.0",
68
- "@release-it-plugins/lerna-changelog": "^5.0.0",
68
+ "@release-it/keep-a-changelog": "^3.1.0",
69
69
  "@tsconfig/ember": "^1.0.1",
70
+ "@types/debug": "^4.1.7",
70
71
  "@types/ember": "^4.0.2",
71
72
  "@types/ember__application": "^4.0.4",
72
73
  "@types/ember__array": "^4.0.3",
@@ -145,7 +146,7 @@
145
146
  },
146
147
  "peerDependencies": {
147
148
  "@appuniversum/ember-appuniversum": "^2.2.0",
148
- "@lblod/ember-rdfa-editor": "^2.0.1",
149
+ "@lblod/ember-rdfa-editor": "^2.1.2",
149
150
  "ember-concurrency": "^2.3.7"
150
151
  },
151
152
  "engines": {
@@ -4,7 +4,7 @@ import { Decoration, DecorationSet, EditorState, InlineDecorationSpec, MarkSpec,
4
4
  * In restructuring, I've made sure that I didn't abstract away any of the capturing groups,
5
5
  * only their content, so you can still see what's going on
6
6
  *
7
- * This regex uses named capturing groups, that's the "?<name>" syntax for easy parsing later
7
+ * This regex uses named capturing groups, that's the "?<name>" syntax, for easy parsing later
8
8
  */
9
9
  export declare const CITATION_REGEX: RegExp;
10
10
  export type CitationSchema = Schema<string, 'citation'>;
@@ -1,4 +1,5 @@
1
1
  export declare function formatDate(date: Date, format: string): string;
2
+ export declare function formatContainsTime(format: string): boolean;
2
3
  type ValidationErrorType = 'date' | 'locale' | 'use-yyyy' | 'use-yy' | 'use-d' | 'use-dd' | 'character' | 'required' | 'fractions' | 'unknown';
3
4
  interface ValidationOk {
4
5
  type: 'ok';